diff options
-rw-r--r-- | sca-cpp/trunk/modules/js/Makefile.am | 8 | ||||
-rw-r--r-- | sca-cpp/trunk/modules/js/htdocs/component.js | 4 | ||||
-rw-r--r-- | sca-cpp/trunk/modules/js/htdocs/jsonutil.js | 259 | ||||
-rw-r--r-- | sca-cpp/trunk/modules/js/htdocs/util.js | 34 | ||||
-rw-r--r-- | sca-cpp/trunk/modules/js/js-eval.cpp | 55 | ||||
-rw-r--r-- | sca-cpp/trunk/modules/js/json-test.js | 51 | ||||
-rwxr-xr-x | sca-cpp/trunk/modules/js/util-test | 30 | ||||
-rwxr-xr-x | sca-cpp/trunk/modules/server/server-conf | 5 |
8 files changed, 441 insertions, 5 deletions
diff --git a/sca-cpp/trunk/modules/js/Makefile.am b/sca-cpp/trunk/modules/js/Makefile.am index 8c88f32c0f..e525332107 100644 --- a/sca-cpp/trunk/modules/js/Makefile.am +++ b/sca-cpp/trunk/modules/js/Makefile.am @@ -25,5 +25,9 @@ EXTRA_DIST = htdocs/*.js htdocs/*.css js_test_SOURCES = js-test.cpp js_test_LDFLAGS = -lmozjs -noinst_PROGRAMS = js-test -TESTS = js-test +js_eval_SOURCES = js-eval.cpp +js_eval_LDFLAGS = -lmozjs + +noinst_PROGRAMS = js-test js-eval +dist_noinst_SCRIPTS = util-test +TESTS = js-test util-test diff --git a/sca-cpp/trunk/modules/js/htdocs/component.js b/sca-cpp/trunk/modules/js/htdocs/component.js index ecbcdeda5b..8e25292018 100644 --- a/sca-cpp/trunk/modules/js/htdocs/component.js +++ b/sca-cpp/trunk/modules/js/htdocs/component.js @@ -31,11 +31,11 @@ * Client component wiring API, supporting JSON and ATOM bindings. */ +var JSONClient = {}; + /** * Escape a character. */ -var JSONClient = {}; - JSONClient.escapeJSONChar = function(c) { if(c == "\"" || c == "\\") return "\\" + c; if (c == "\b") return "\\b"; diff --git a/sca-cpp/trunk/modules/js/htdocs/jsonutil.js b/sca-cpp/trunk/modules/js/htdocs/jsonutil.js new file mode 100644 index 0000000000..1a1a027e88 --- /dev/null +++ b/sca-cpp/trunk/modules/js/htdocs/jsonutil.js @@ -0,0 +1,259 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * JSON data conversion functions. + */ +var json = {}; + +/** + * JSON exceptions. + */ +json.Exception = function(code, message) { + this.name = "JSONException"; + this.code = code; + this.message = message; +}; + +json.Exception.prototype = new Error(); + +json.Exception.prototype.toString = function() { + return this.name + ": " + this.message; +}; + +/** + * Return true if a list represents a JS array. + */ +json.isJSArray = function(l) { + if (isNil(l)) + return true; + var v = car(l); + if (isSymbol(v)) + return false; + if (isList(v)) + if (!isNil(v) && isSymbol(car(v))) + return false; + return true; +}; + +/** + * Converts JSON properties to values. + */ +json.jsPropertiesToValues = function(propertiesSoFar, o, i) { + if (isNil(i)) + return propertiesSoFar; + var p = car(i); + var jsv = o[p]; + var v = json.jsValToValue(jsv); + + if (typeof p == 'string') { + var n = '' + p; + if (n.slice(0, 1) == '@') + return json.jsPropertiesToValues(cons(mklist(attribute, "'" + n.slice(1), v), propertiesSoFar), o, cdr(i)); + if (isList(v) && !json.isJSArray(v)) + return json.jsPropertiesToValues(cons(cons(element, cons("'" + n, v)), propertiesSoFar), o, cdr(i)); + return json.jsPropertiesToValues(cons(mklist(element, "'" + n, v), propertiesSoFar), o, cdr(i)); + } + return json.jsPropertiesToValues(cons(v, propertiesSoFar), o, cdr(i)); +}; + +/** + * Converts a JSON val to a value. + */ +json.jsValToValue = function(jsv) { + if (isList(jsv)) + return json.jsPropertiesToValues(mklist(), jsv, reverse(range(0, jsv.length))); + if (typeof jsv == 'object') + return json.jsPropertiesToValues(mklist(), jsv, properties(jsv)); + if (typeof jsv == 'string') + return '' + jsv; + return jsv; +} + +/** + * Return true if a list of strings contains a JSON document. + */ +json.isJSON = function(l) { + if (isNil(l)) + return false; + var s = car(l).slice(0, 1); + return s == "[" || s == "{"; +}; + +/** + * Convert a list of strings representing a JSON document to a list of values. + */ +json.readJSON = function(l) { + var s = writeStrings(l); + var obj; + eval('obj = { \"val\": ' + s + " }"); + return json.jsValToValue(obj.val); +}; + +/** + * Convert a list of values to JSON array elements. + */ +json.valuesToJSElements = function(a, l, i) { + if (isNil(l)) + return a; + var pv = json.valueToJSVal(car(l)); + a[i] = pv + return json.valuesToJSElements(a, cdr(l), i + 1); +}; + +/** + * Convert a value to a JSON value. + */ +json.valueToJSVal = function(v) { + if (!isList(v)) + return v; + if (json.isJSArray(v)) + return json.valuesToJSElements(range(0, v.length), v, 0); + return json.valuesToJSProperties({}, v); +}; + +/** + * Convert a list of values to JSON properties. + */ +json.valuesToJSProperties = function(o, l) { + if (isNil(l)) + return o; + var token = car(l); + if (isTaggedList(token, attribute)) { + var pv = json.valueToJSVal(attributeValue(token)); + o['@' + attributeName(token).slice(1)] = pv; + } else if (isTaggedList(token, element)) { + if (elementHasValue(token)) { + var pv = json.valueToJSVal(elementValue(token)); + o[elementName(token).slice(1)] = pv; + } else { + var child = {}; + o[elementName(token).slice(1)] = child; + json.valuesToJSProperties(child, elementChildren(token)); + } + } + return json.valuesToJSProperties(o, cdr(l)); +}; + +/** + * Convert a list of values to a list of strings representing a JSON document. + */ +json.writeJSON = function(l) { + var jsv; + if (json.isJSArray(l)) + jsv = json.valuesToJSElements(range(0, l.length), l, 0); + else + jsv = json.valuesToJSProperties({}, l); + var s = json.toJSON(jsv); + return mklist(s); +} + +/** + * Convert a list + params to a JSON-RPC request. + */ +json.jsonRequest = function(id, func, params) { + var r = mklist(mklist("'id", id), mklist("'method", func), mklist("'params", params)); + return json.writeJSON(valuesToElements(r)); +}; + +/** + * Convert a value to a JSON-RPC result. + */ +json.jsonResult = function(id, val) { + return json.writeJSON(valuesToElements(mklist(mklist("'id", id), mklist("'result", val)))); +}; + +/** + * Convert a JSON-RPC result to a value. + */ +json.jsonResultValue = function(s) { + var jsres = json.readJSON(s); + var res = elementsToValues(jsres); + var val = cadr(assoc("'result", res)); + if (isList(val) && !json.isJSArray(val)) + return mklist(val); + return val; +}; + +/** + * Escape a character. + */ +json.escapeJSONChar = function(c) { + if(c == "\"" || c == "\\") return "\\" + c; + if (c == "\b") return "\\b"; + if (c == "\f") return "\\f"; + if (c == "\n") return "\\n"; + if (c == "\r") return "\\r"; + if (c == "\t") return "\\t"; + var hex = c.charCodeAt(0).toString(16); + if(hex.length == 1) return "\\u000" + hex; + if(hex.length == 2) return "\\u00" + hex; + if(hex.length == 3) return "\\u0" + hex; + return "\\u" + hex; +}; + +/** + * Encode a string into JSON format. + */ +json.escapeJSONString = function(s) { + // The following should suffice but Safari's regex is broken (doesn't support callback substitutions) + // return "\"" + s.replace(/([^\u0020-\u007f]|[\\\"])/g, json.escapeJSONChar) + "\""; + + // Rather inefficient way to do it + var parts = s.split(""); + for(var i = 0; i < parts.length; i++) { + var c = parts[i]; + if(c == '"' || c == '\\' || c.charCodeAt(0) < 32 || c.charCodeAt(0) >= 128) + parts[i] = json.escapeJSONChar(parts[i]); + } + return "\"" + parts.join("") + "\""; +}; + +/** + * Marshall objects to JSON format. + */ +json.toJSON = function(o) { + if(o == null) + return "null"; + if(o.constructor == String) + return json.escapeJSONString(o); + if(o.constructor == Number) + return o.toString(); + if(o.constructor == Boolean) + return o.toString(); + if(o.constructor == Date) + return '{javaClass: "java.util.Date", time: ' + o.valueOf() +'}'; + if(o.constructor == Array) { + var v = []; + for(var i = 0; i < o.length; i++) + v.push(json.toJSON(o[i])); + return "[" + v.join(", ") + "]"; + } + var v = []; + for(attr in o) { + if(o[attr] == null) + v.push("\"" + attr + "\": null"); + else if(typeof o[attr] == "function") + ; // Skip + else + v.push(json.escapeJSONString(attr) + ": " + json.toJSON(o[attr])); + } + return "{" + v.join(", ") + "}"; +}; + diff --git a/sca-cpp/trunk/modules/js/htdocs/util.js b/sca-cpp/trunk/modules/js/htdocs/util.js index 20af741c6d..512e3c26d5 100644 --- a/sca-cpp/trunk/modules/js/htdocs/util.js +++ b/sca-cpp/trunk/modules/js/htdocs/util.js @@ -72,6 +72,13 @@ function reverse(l) { return l.slice(0).reverse(); } +function range(a, b) { + var l = new Array(); + for (var x = a; x < b; x++) + l.push(x); + return l; +} + function isNil(v) { if (v == null || typeof v == 'undefined' || (v.constructor == Array && v.length == 0)) return true; @@ -85,7 +92,7 @@ function isSymbol(v) { } function isString(v) { - if (typeof v == 'string') + if (typeof v == 'string' && v.slice(0, 1) != "'") return true; return false; } @@ -199,6 +206,21 @@ function debug(o) { } /** + * Simple assert function. + */ +function AssertException() { +} + +AssertException.prototype.toString = function () { + return 'AssertException'; +}; + +function assert(exp) { + if (!exp) + throw new AssertException(); +} + +/** * Write a list of strings. */ function writeStrings(l) { @@ -252,6 +274,16 @@ function unmemo(obj) { } /** + * Returns a list of the properties of an object. + */ +function properties(o) { + var a = new Array(); + for (p in o) + a.push(p); + return a; +} + +/** * Functions with side effects. Use with moderation. */ diff --git a/sca-cpp/trunk/modules/js/js-eval.cpp b/sca-cpp/trunk/modules/js/js-eval.cpp new file mode 100644 index 0000000000..ee0fa89b31 --- /dev/null +++ b/sca-cpp/trunk/modules/js/js-eval.cpp @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* $Rev$ $Date$ */ + +/** + * Evaluate a JavaScript script. + */ + +#include <assert.h> +#include "stream.hpp" +#include "fstream.hpp" +#include "string.hpp" +#include "eval.hpp" + +namespace tuscany { +namespace js { + +bool eval() { + ostringstream os; + for(;;) { + int c = cin.get(); + if (c == -1) + break; + os << (char)c; + } + failable<value> v = evalScript(str(os)); + assert(hasContent(v)); + cout << v; + return true; +} + +} +} + +int main() { + tuscany::js::eval(); + return 0; +} diff --git a/sca-cpp/trunk/modules/js/json-test.js b/sca-cpp/trunk/modules/js/json-test.js new file mode 100644 index 0000000000..5cc93a86eb --- /dev/null +++ b/sca-cpp/trunk/modules/js/json-test.js @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * Test JSON data encoding functions. + */ +function testJSON() { + var ad = mklist(mklist(attribute, "'city", "san francisco"), mklist(attribute, "'state", "ca")); + var ac = mklist(mklist(element, "'id", "1234"), mklist(attribute, "'balance", 1000)); + var cr = mklist(mklist(attribute, "'name", "jdoe"), cons(element, cons("'address", ad)), cons(element, cons("'account", ac))); + var c = mklist(cons(element, cons("'customer", cr))); + var s = json.writeJSON(c); + assert(car(s) == "{\"customer\": {\"@name\": \"jdoe\", \"address\": {\"@city\": \"san francisco\", \"@state\": \"ca\"}, \"account\": {\"id\": \"1234\", \"@balance\": 1000}}}"); + + var phones = mklist("408-1234", "650-1234"); + var l = mklist(mklist(element, "'phones", phones), mklist(element, "'lastName", "test\ttab"), mklist(attribute, "'firstName", "test1")); + var s2 = json.writeJSON(l); + assert(car(s2) == "{\"phones\": [\"408-1234\", \"650-1234\"], \"lastName\": \"test\\ttab\", \"@firstName\": \"test1\"}"); + + var r = json.readJSON(s2); + var w = json.writeJSON(r); + assert(car(w) == "{\"@firstName\": \"test1\", \"lastName\": \"test\\ttab\", \"phones\": [\"408-1234\", \"650-1234\"]}"); + + var l4 = mklist(mklist("'ns1:echoString", mklist("'@xmlns:ns1", "http://ws.apache.org/axis2/services/echo"), mklist("'text", "Hello World!"))); + var s4 = json.writeJSON(valuesToElements(l4)); + assert(car(s4) == "{\"ns1:echoString\": {\"@xmlns:ns1\": \"http://ws.apache.org/axis2/services/echo\", \"text\": \"Hello World!\"}}"); + + var r5 = elementsToValues(json.readJSON(s4)); + var s5 = json.writeJSON(valuesToElements(r5)); + assert(car(s5) == "{\"ns1:echoString\": {\"text\": \"Hello World!\", \"@xmlns:ns1\": \"http://ws.apache.org/axis2/services/echo\"}}"); + return true; +} + +testJSON(); + diff --git a/sca-cpp/trunk/modules/js/util-test b/sca-cpp/trunk/modules/js/util-test new file mode 100755 index 0000000000..ccfb377bd1 --- /dev/null +++ b/sca-cpp/trunk/modules/js/util-test @@ -0,0 +1,30 @@ +#!/bin/sh + +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# Run Javascript util test cases +here=`readlink -f $0`; here=`dirname $here` + +echo "Testing..." +cat htdocs/util.js htdocs/elemutil.js htdocs/jsonutil.js json-test.js | ./js-eval 2>/dev/null 1>&2 +rc=$? +if [ "$rc" = "0" ]; then + echo "OK" +fi + +return $rc diff --git a/sca-cpp/trunk/modules/server/server-conf b/sca-cpp/trunk/modules/server/server-conf index 992627596b..61dcdeeb91 100755 --- a/sca-cpp/trunk/modules/server/server-conf +++ b/sca-cpp/trunk/modules/server/server-conf @@ -61,6 +61,7 @@ Alias /util.js $jsprefix/htdocs/util.js Alias /elemutil.js $jsprefix/htdocs/elemutil.js Alias /xmlutil.js $jsprefix/htdocs/xmlutil.js Alias /atomutil.js $jsprefix/htdocs/atomutil.js +Alias /jsonutil.js $jsprefix/htdocs/jsonutil.js Alias /ui.js $jsprefix/htdocs/ui.js Alias /ui.css $jsprefix/htdocs/ui.css Alias /scdl.js $jsprefix/htdocs/scdl.js @@ -85,6 +86,10 @@ Require all granted AuthType None Require all granted </Location> +<Location /jsonutil.js> +AuthType None +Require all granted +</Location> <Location /ui.js> AuthType None Require all granted |