summaryrefslogtreecommitdiffstats
path: root/cpp
diff options
context:
space:
mode:
authorjsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68>2009-10-18 22:25:08 +0000
committerjsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68>2009-10-18 22:25:08 +0000
commitf87b9f1e48df02c26e0bbe3f8f1664c2b0862e52 (patch)
tree4d0ee23a5b5c7878b5b4f2131bc17f9765b93313 /cpp
parent6dd3610df5854ef9af7e5e2907b2f4065d69075d (diff)
Some fixes to the JSON and httpd support. Added support for Atom. Adjusted store test.
git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@826545 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'cpp')
-rw-r--r--cpp/sca/configure.ac1
-rw-r--r--cpp/sca/etc/git-exclude4
-rw-r--r--cpp/sca/modules/Makefile.am2
-rw-r--r--cpp/sca/modules/atom/Makefile.am23
-rw-r--r--cpp/sca/modules/atom/atom-test.cpp150
-rw-r--r--cpp/sca/modules/atom/atom.hpp154
-rw-r--r--cpp/sca/modules/httpd/mod.cpp10
-rw-r--r--cpp/sca/modules/json/json-test.cpp56
-rw-r--r--cpp/sca/modules/json/json.hpp113
-rw-r--r--cpp/sca/test/store-script/htdocs/store.html21
-rw-r--r--cpp/sca/test/store-script/htdocs/store.js2
-rw-r--r--cpp/sca/test/store-script/store-script-test.cpp34
-rw-r--r--cpp/sca/test/store-script/store.scm14
13 files changed, 484 insertions, 100 deletions
diff --git a/cpp/sca/configure.ac b/cpp/sca/configure.ac
index edf471fcae..46584271b4 100644
--- a/cpp/sca/configure.ac
+++ b/cpp/sca/configure.ac
@@ -266,6 +266,7 @@ AM_CONDITIONAL([WANT_DOXYGEN], [test x$want_doxygen = xtrue])
AC_CONFIG_FILES([Makefile
kernel/Makefile
modules/Makefile
+ modules/atom/Makefile
modules/eval/Makefile
modules/httpd/Makefile
modules/json/Makefile
diff --git a/cpp/sca/etc/git-exclude b/cpp/sca/etc/git-exclude
index 048c6979a1..70284ba699 100644
--- a/cpp/sca/etc/git-exclude
+++ b/cpp/sca/etc/git-exclude
@@ -60,8 +60,10 @@ sca/runtime/extensions/cpp/tools/scagen/docs/
account_client
calculator_client
kernel-test
-xml-test
+xsd-test
+atom-test
eval-test
+eval-shell
json-test
store-function-test
store-object-test
diff --git a/cpp/sca/modules/Makefile.am b/cpp/sca/modules/Makefile.am
index f152862a75..025a549df3 100644
--- a/cpp/sca/modules/Makefile.am
+++ b/cpp/sca/modules/Makefile.am
@@ -15,5 +15,5 @@
# specific language governing permissions and limitations
# under the License.
-SUBDIRS = eval httpd json
+SUBDIRS = atom eval httpd json
diff --git a/cpp/sca/modules/atom/Makefile.am b/cpp/sca/modules/atom/Makefile.am
new file mode 100644
index 0000000000..90e3207bb2
--- /dev/null
+++ b/cpp/sca/modules/atom/Makefile.am
@@ -0,0 +1,23 @@
+# 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.
+
+noinst_PROGRAMS = atom-test
+
+INCLUDES = -I. -I$(top_builddir)/kernel -I${LIBXML2_INCLUDE}
+
+atom_test_SOURCES = atom-test.cpp
+atom_test_LDADD = -lpthread -L${LIBXML2_LIB} -lxml2
diff --git a/cpp/sca/modules/atom/atom-test.cpp b/cpp/sca/modules/atom/atom-test.cpp
new file mode 100644
index 0000000000..0cef6b3b60
--- /dev/null
+++ b/cpp/sca/modules/atom/atom-test.cpp
@@ -0,0 +1,150 @@
+/*
+ * 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$ */
+
+/**
+ * Test ATOM data conversion functions.
+ */
+
+#include <assert.h>
+#include <iostream>
+#include <sstream>
+#include <string>
+#include "slist.hpp"
+#include "atom.hpp"
+
+namespace tuscany {
+
+std::ostringstream* atomWriter(std::ostringstream* os, const std::string& s) {
+ (*os) << s;
+ return os;
+}
+
+std::string itemEntry("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<entry xmlns=\"http://www.w3.org/2005/Atom\">"
+ "<title type=\"text\">item</title>"
+ "<id>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b</id>"
+ "<content type=\"application/xml\">"
+ "<item>"
+ "<name>Apple</name><price>$2.99</price>"
+ "</item>"
+ "</content>"
+ "<link href=\"cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b\"/>"
+ "</entry>\n");
+
+bool testATOMEntry() {
+ {
+ const list<value> i = list<value>() << element << "item"
+ << (list<value>() << element << "name" << std::string("Apple"))
+ << (list<value>() << element << "price" << std::string("$2.99"));
+ const list<value> a = mklist<value>(std::string("item"), std::string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
+ std::ostringstream os;
+ writeATOMEntry<std::ostringstream*>(atomWriter, &os, a);
+ assert(os.str() == itemEntry);
+ }
+ {
+ const list<value> a = readATOMEntry(mklist(itemEntry));
+ std::ostringstream os;
+ writeATOMEntry<std::ostringstream*>(atomWriter, &os, a);
+ assert(os.str() == itemEntry);
+ }
+ return true;
+}
+
+std::string emptyFeed("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<feed xmlns=\"http://www.w3.org/2005/Atom\">"
+ "<title type=\"text\">Feed</title>"
+ "<id>1234</id>"
+ "</feed>\n");
+
+std::string itemFeed("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<feed xmlns=\"http://www.w3.org/2005/Atom\">"
+ "<title type=\"text\">Feed</title>"
+ "<id>1234</id>"
+ "<entry xmlns=\"http://www.w3.org/2005/Atom\">"
+ "<title type=\"text\">item</title>"
+ "<id>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b</id>"
+ "<content type=\"application/xml\">"
+ "<item>"
+ "<name>Apple</name><price>$2.99</price>"
+ "</item>"
+ "</content>"
+ "<link href=\"cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b\"/>"
+ "</entry>"
+ "<entry xmlns=\"http://www.w3.org/2005/Atom\">"
+ "<title type=\"text\">item</title>"
+ "<id>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83c</id>"
+ "<content type=\"application/xml\">"
+ "<item>"
+ "<name>Orange</name><price>$3.55</price>"
+ "</item>"
+ "</content>"
+ "<link href=\"cart-53d67a61-aa5e-4e5e-8401-39edeba8b83c\"/>"
+ "</entry>"
+ "</feed>\n");
+
+bool testATOMFeed() {
+ {
+ std::ostringstream os;
+ writeATOMFeed<std::ostringstream*>(atomWriter, &os, mklist<value>("Feed", "1234"));
+ assert(os.str() == emptyFeed);
+ }
+ {
+ const list<value> a = readATOMFeed(mklist(emptyFeed));
+ std::ostringstream os;
+ writeATOMFeed<std::ostringstream*>(atomWriter, &os, a);
+ assert(os.str() == emptyFeed);
+ }
+ {
+ const list<value> i = list<value>()
+ << (list<value>() << "item" << "cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"
+ << (list<value>() << element << "item"
+ << (list<value>() << element << "name" << "Apple")
+ << (list<value>() << element << "price" << "$2.99")))
+ << (list<value>() << "item" << "cart-53d67a61-aa5e-4e5e-8401-39edeba8b83c"
+ << (list<value>() << element << "item"
+ << (list<value>() << element << "name" << "Orange")
+ << (list<value>() << element << "price" << "$3.55")));
+ const list<value> a = cons<value>("Feed", cons<value>("1234", i));
+ std::ostringstream os;
+ writeATOMFeed<std::ostringstream*>(atomWriter, &os, a);
+ assert(os.str() == itemFeed);
+ }
+ {
+ const list<value> a = readATOMFeed(mklist(itemFeed));
+ std::ostringstream os;
+ writeATOMFeed<std::ostringstream*>(atomWriter, &os, a);
+ assert(os.str() == itemFeed);
+ }
+ return true;
+}
+
+}
+
+int main() {
+ std::cout << "Testing..." << std::endl;
+
+ tuscany::testATOMEntry();
+ tuscany::testATOMFeed();
+
+ std::cout << "OK" << std::endl;
+
+ return 0;
+}
diff --git a/cpp/sca/modules/atom/atom.hpp b/cpp/sca/modules/atom/atom.hpp
new file mode 100644
index 0000000000..5bb8d45e38
--- /dev/null
+++ b/cpp/sca/modules/atom/atom.hpp
@@ -0,0 +1,154 @@
+/*
+ * 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$ */
+
+#ifndef tuscany_atom_hpp
+#define tuscany_atom_hpp
+
+/**
+ * ATOM data conversion functions.
+ */
+
+#include <string>
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "xml.hpp"
+
+namespace tuscany {
+
+/**
+ * Convert a list of elements to a list of values representing an ATOM entry.
+ */
+const list<value> atomEntry(const list<value>& e) {
+ const list<value> t = filter<value>(selector(mklist<value>(element, "title")), e);
+ const list<value> i = filter<value>(selector(mklist<value>(element, "id")), e);
+ const list<value> c = filter<value>(selector(mklist<value>(element, "content")), e);
+ return mklist<value>(elementValue(car(t)), elementValue(car(i)), cadr(elementChildren(car(c))));
+}
+
+/**
+ * Convert a list of elements to a list of values representing ATOM entries.
+ */
+const list<value> atomEntries(const list<value>& e) {
+ if (isNil(e))
+ return list<value>();
+ return cons<value>(atomEntry(car(e)), atomEntries(cdr(e)));
+}
+
+/**
+ * Convert a list of strings to a list of values representing an ATOM entry.
+ */
+const failable<list<value>, std::string> readATOMEntry(const list<std::string>& ilist) {
+ const list<value> e = readXML(ilist);
+ if (isNil(e))
+ return std::string("Empty entry");
+ return atomEntry(car(e));
+}
+
+/**
+ * Convert a list of strings to a list of values representing an ATOM feed.
+ */
+const failable<list<value>, std::string> readATOMFeed(const list<std::string>& ilist) {
+ const list<value> f = readXML(ilist);
+ if (isNil(f))
+ return std::string("Empty feed");
+ const list<value> t = filter<value>(selector(mklist<value>(element, "title")), car(f));
+ const list<value> i = filter<value>(selector(mklist<value>(element, "id")), car(f));
+ const list<value> e = filter<value>(selector(mklist<value>(element, "entry")), car(f));
+ if (isNil(e))
+ return mklist<value>(elementValue(car(t)), elementValue(car(i)));
+ return cons<value>(elementValue(car(t)), cons(elementValue(car(i)), atomEntries(e)));
+}
+
+/**
+ * Convert a list of values representing an ATOM entry to a list of elements.
+ * The first two values in the list are the entry title and id.
+ */
+const list<value> atomEntryElement(const list<value>& l) {
+ return list<value>()
+ << element << "entry" << (list<value>() << attribute << "xmlns" << "http://www.w3.org/2005/Atom")
+ << (list<value>() << element << "title" << (list<value>() << attribute << "type" << "text") << car(l))
+ << (list<value>() << element << "id" << cadr(l))
+ << (list<value>() << element << "content" << (list<value>() << attribute << "type" << "application/xml") << caddr(l))
+ << (list<value>() << element << "link" << (list<value>() << attribute << "href" << cadr(l)));
+}
+
+/**
+ * Convert a list of values representing ATOM entries to a list of elements.
+ */
+const list<value> atomEntriesElements(const list<value>& l) {
+ if (isNil(l))
+ return list<value>();
+ return cons<value>(atomEntryElement(car(l)), atomEntriesElements(cdr(l)));
+}
+
+/**
+ * Convert a list of values representing an ATOM entry to an ATOM entry.
+ * The first two values in the list are the entry id and title.
+ */
+template<typename R> const failable<R, std::string> writeATOMEntry(const lambda<R(R, std::string)>& reduce, const R& initial, const list<value>& l) {
+ return writeXML<R>(reduce, initial, mklist<value>(atomEntryElement(l)));
+}
+
+/**
+ * Convert a list of values representing an ATOM entry to a list of strings.
+ * The first two values in the list are the entry id and title.
+ */
+const list<std::string> writeATOMList(const list<std::string>& listSoFar, const std::string& s) {
+ return cons(s, listSoFar);
+}
+
+const failable<list<std::string>, std::string> writeATOMEntry(const list<value>& l) {
+ const failable<list<std::string>, std::string> ls = writeATOMEntry<list<std::string> >(writeATOMList, list<std::string>(), l);
+ if (!hasValue(ls))
+ return ls;
+ return reverse(list<std::string>(ls));
+}
+
+/**
+ * Convert a list of values representing an ATOM feed to an ATOM feed.
+ * The first two values in the list are the feed id and title.
+ */
+template<typename R> const failable<R, std::string> writeATOMFeed(const lambda<R(R, std::string)>& reduce, const R& initial, const list<value>& l) {
+ const list<value> f = list<value>()
+ << element << "feed" << (list<value>() << attribute << "xmlns" << "http://www.w3.org/2005/Atom")
+ << (list<value>() << element << "title" << (list<value>() << attribute << "type" << "text") << car(l))
+ << (list<value>() << element << "id" << cadr(l));
+ if (isNil(cddr(l)))
+ return writeXML<R>(reduce, initial, mklist<value>(f));
+ const list<value> fe = append(f, atomEntriesElements(cddr(l)));
+ return writeXML<R>(reduce, initial, mklist<value>(fe));
+}
+
+/**
+ * Convert a list of values representing an ATOM feed to a list of strings.
+ * The first two values in the list are the feed id and title.
+ */
+const failable<list<std::string>, std::string> writeATOMFeed(const list<value>& l) {
+ const failable<list<std::string>, std::string> ls = writeATOMFeed<list<std::string> >(writeATOMList, list<std::string>(), l);
+ if (!hasValue(ls))
+ return ls;
+ return reverse(list<std::string>(ls));
+}
+
+}
+
+#endif /* tuscany_atom_hpp */
diff --git a/cpp/sca/modules/httpd/mod.cpp b/cpp/sca/modules/httpd/mod.cpp
index feebca4b5c..81e12934e7 100644
--- a/cpp/sca/modules/httpd/mod.cpp
+++ b/cpp/sca/modules/httpd/mod.cpp
@@ -50,6 +50,7 @@
#include "list.hpp"
#include "slist.hpp"
#include "value.hpp"
+#include "element.hpp"
#include "monad.hpp"
#include "../json/json.hpp"
#include "../eval/driver.hpp"
@@ -160,7 +161,7 @@ const value evalLoop(std::istream& is, const value& req, Env& globalEnv) {
*/
const list<value> queryArg(std::string s) {
const list<std::string> t = tokenize("=", s);
- return makeList<value>(car(t).c_str(), cadr(t));
+ return mklist<value>(car(t).c_str(), cadr(t));
}
const list<list<value> > queryArgs(const request_rec* r) {
@@ -218,7 +219,7 @@ const int get(request_rec* r) {
// Convert the expr value to JSON
const JSONContext cx;
- failable<list<std::string>, std::string> jsval = writeJSON(cx, makeList<value>(makeList<value>("id", id), makeList<value>("result", val)));
+ failable<list<std::string>, std::string> jsval = writeJSON(cx, mklist<value>(mklist<value>("id", id), mklist<value>("result", val)));
if (!hasValue(jsval))
return HTTP_INTERNAL_SERVER_ERROR;
@@ -277,7 +278,7 @@ const int post(request_rec* r) {
// Read the JSON request
const list<std::string> req = read(r);
JSONContext cx;
- const list<value> json = readJSON(cx, req);
+ const list<value> json = elementsToValues(readJSON(cx, req));
const list<list<value> > args = postArgs(json);
// Extract the request id, method and params
@@ -298,7 +299,8 @@ const int post(request_rec* r) {
std::cout.flush();
// Convert the expr value to JSON
- failable<list<std::string>, std::string> jsval = writeJSON(cx, makeList<value>(makeList<value>("id", id), makeList<value>("result", val)));
+ const list<value> result = valuesToElements(mklist<value>(mklist<value>("id", id), mklist<value>("result", val)));
+ failable<list<std::string>, std::string> jsval = writeJSON(cx, result);
if (!hasValue(jsval))
return HTTP_INTERNAL_SERVER_ERROR;
diff --git a/cpp/sca/modules/json/json-test.cpp b/cpp/sca/modules/json/json-test.cpp
index 1ebece647b..b7cc4e4eeb 100644
--- a/cpp/sca/modules/json/json-test.cpp
+++ b/cpp/sca/modules/json/json-test.cpp
@@ -20,7 +20,7 @@
/* $Rev$ $Date$ */
/**
- * Test JSON read/write functions.
+ * Test JSON data conversion functions.
*/
#include <assert.h>
@@ -50,34 +50,44 @@ std::ostringstream* jsonWriter(std::ostringstream* os, const std::string& s) {
bool testJSON() {
const JSONContext cx;
- const list<value> phones = makeList<value> (std::string("408-1234"), std::string("650-1234"));
- const list<value> l = makeList<value> (makeList<value> ("phones", phones), makeList<value> ("lastName", std::string("test\ttab")), makeList<value> ("firstName", std::string("test1")));
- print(l, std::cout);
- std::cout << std::endl;
-
- std::ostringstream os;
- writeJSON<std::ostringstream*>(cx, jsonWriter, &os, l);
- std::cout << os.str() << std::endl;
-
- std::istringstream is(os.str());
- const list<std::string> il = makeStreamList(is);
- const list<value> r = readJSON(cx, il);
- print(r, std::cout);
- std::cout << std::endl;
- assert(r == l);
-
- std::ostringstream wos;
- write(writeJSON(cx, r), wos);
- assert(wos.str() == os.str());
-
+ {
+ const list<value> ad = mklist<value>(mklist<value>(attribute, "city", std::string("san francisco")), mklist<value>(attribute, "state", std::string("ca")));
+ const list<value> ac = mklist<value>(mklist<value>(element, "id", std::string("1234")), mklist<value>(attribute, "balance", 1000));
+ const list<value> cr = mklist<value>(mklist<value> (attribute, "name", std::string("jdoe")), cons<value>(element, cons<value>("address", ad)), cons<value>(element, cons<value>("account", ac)));
+ const list<value> c = mklist<value>(cons<value>(element, cons<value>("customer", cr)));
+ std::ostringstream os;
+ writeJSON<std::ostringstream*>(cx, jsonWriter, &os, c);
+ assert(os.str() == "{\"customer\":{\"name\":\"jdoe\",\"address\":{\"city\":\"san francisco\",\"state\":\"ca\"},\"account\":{\"id\":\"1234\",\"balance\":1000}}}");
+ }
+ {
+ const list<value> phones = mklist<value> (std::string("408-1234"), std::string("650-1234"));
+ const list<value> l = mklist<value> (mklist<value> (element, "phones", phones), mklist<value> (attribute, "lastName", std::string("test\ttab")), mklist<value> (attribute, "firstName", std::string("test1")));
+
+ std::ostringstream os;
+ writeJSON<std::ostringstream*>(cx, jsonWriter, &os, l);
+ assert(os.str() == "{\"phones\":[\"408-1234\",\"650-1234\"],\"lastName\":\"test\\u0009tab\",\"firstName\":\"test1\"}");
+
+ std::istringstream is(os.str());
+ const list<std::string> il = streamList(is);
+ const list<value> r = readJSON(cx, il);
+ assert(r == l);
+
+ std::ostringstream wos;
+ write(writeJSON(cx, r), wos);
+ assert(wos.str() == os.str());
+ }
return true;
}
bool testJSONRPC() {
const std::string lm("{\"id\": 1, \"method\": \"system.listMethods\", \"params\": []}");
JSONContext cx;
- const list<value> v = readJSON(cx, makeList(lm));
- std::cout << v << std::endl;
+ const list<value> e = readJSON(cx, mklist(lm));
+ const list<value> v = elementsToValues(e);
+
+ assert(assoc<value>("id", v) == mklist<value>("id", 1));
+ assert(assoc<value>("method", v) == mklist<value>("method", std::string("system.listMethods")));
+ assert(assoc<value>("params", v) == mklist<value>("params", list<value>()));
return true;
}
diff --git a/cpp/sca/modules/json/json.hpp b/cpp/sca/modules/json/json.hpp
index f6ed9202c3..5f3d8c21e0 100644
--- a/cpp/sca/modules/json/json.hpp
+++ b/cpp/sca/modules/json/json.hpp
@@ -23,15 +23,15 @@
#define tuscany_json_hpp
/**
- * JSON read/write functions.
+ * JSON data conversion functions.
*/
-#include <assert.h>
#define XP_UNIX
#include <jsapi.h>
#include <string>
#include "list.hpp"
#include "value.hpp"
+#include "element.hpp"
#include "monad.hpp"
namespace tuscany {
@@ -139,10 +139,9 @@ private:
};
/**
- * Converts JS properties to Tuscany values.
+ * Converts JS properties to values.
*/
-const list<value> jsPropertiesToValues(const JSONContext& cx, const list<value>& propertiesSoFar, JSObject* o,
- JSObject* i) {
+const list<value> jsPropertiesToValues(const JSONContext& cx, const list<value>& propertiesSoFar, JSObject* o, JSObject* i) {
const value jsValToValue(const JSONContext& cx, const jsval& jsv);
@@ -155,14 +154,15 @@ const list<value> jsPropertiesToValues(const JSONContext& cx, const list<value>&
const value val = jsValToValue(cx, jsv);
jsval idv;
JS_IdToValue(cx, id, &idv);
- if(JSVAL_IS_STRING(idv))
- return jsPropertiesToValues(cx, cons<value> (makeList<value> (JS_GetStringBytes(JSVAL_TO_STRING(idv)), val),
- propertiesSoFar), o, i);
+ if(JSVAL_IS_STRING(idv)) {
+ const value type = isList(val)? element : attribute;
+ return jsPropertiesToValues(cx, cons<value> (mklist<value> (type, JS_GetStringBytes(JSVAL_TO_STRING(idv)), val), propertiesSoFar), o, i);
+ }
return jsPropertiesToValues(cx, cons(val, propertiesSoFar), o, i);
}
/**
- * Converts a JS value to a Tuscany value.
+ * Converts a JS val to a value.
*/
const value jsValToValue(const JSONContext& cx, const jsval& jsv) {
switch(JS_TypeOfValue(cx, jsv)) {
@@ -182,7 +182,8 @@ const value jsValToValue(const JSONContext& cx, const jsval& jsv) {
JSObject* i = JS_NewPropertyIterator(cx, o);
if(i == NULL)
return value(list<value> ());
- return jsPropertiesToValues(cx, list<value> (), o, i);
+ const value pv = jsPropertiesToValues(cx, list<value> (), o, i);
+ return pv;
}
default: {
return value();
@@ -203,7 +204,7 @@ failable<bool, std::string> consumeJSON(const JSONContext& cx, JSONParser* parse
}
/**
- * Read JSON tokens from list of strings.
+ * Convert a list of strings representing a JSON document to a list of values.
*/
const failable<list<value>, std::string> readJSON(const JSONContext& cx, const list<std::string>& ilist) {
jsval val;
@@ -222,22 +223,6 @@ const failable<list<value>, std::string> readJSON(const JSONContext& cx, const l
}
/**
- * Returns true if a list represents a JS array.
- */
-const bool isJSArray(const list<value>& l) {
- if(isNil(l))
- return false;
- value v = car(l);
- if(isList(v)) {
- const list<value> p = v;
- if(isSymbol(car(p))) {
- return false;
- }
- }
- return true;
-}
-
-/**
* Converts a list of values to JS array elements.
*/
JSObject* valuesToJSElements(const JSONContext& cx, JSObject* a, const list<value>& l, int i) {
@@ -250,24 +235,12 @@ JSObject* valuesToJSElements(const JSONContext& cx, JSObject* a, const list<valu
}
/**
- * Converts a list of values to JS properties.
- */
-JSObject* valuesToJSProperties(const JSONContext& cx, JSObject* o, const list<value>& l) {
- const jsval valueToJSVal(const JSONContext& cx, const value& val);
- if(isNil(l))
- return o;
- const list<value> p = car(l);
- jsval pv = valueToJSVal(cx, cadr(p));
- JS_SetProperty(cx, o, ((std::string)car(p)).c_str(), &pv);
- return valuesToJSProperties(cx, o, cdr(l));
-}
-
-/**
- * Converts a Tuscany value to a JS value.
+ * Converts a value to a JS val.
*/
const jsval valueToJSVal(const JSONContext& cx, const value& val) {
switch(type(val)) {
- case value::String: {
+ case value::String:
+ case value::Symbol: {
return STRING_TO_JSVAL(JS_NewStringCopyZ(cx, ((std::string)val).c_str()));
}
case value::Boolean: {
@@ -277,10 +250,7 @@ const jsval valueToJSVal(const JSONContext& cx, const value& val) {
return DOUBLE_TO_JSVAL(JS_NewDouble(cx, (double)val));
}
case value::List: {
- if (isJSArray(val)) {
- return OBJECT_TO_JSVAL(valuesToJSElements(cx, JS_NewArrayObject(cx, 0, NULL), val, 0));
- }
- return OBJECT_TO_JSVAL(valuesToJSProperties(cx, JS_NewObject(cx, NULL, NULL, NULL), val));
+ return OBJECT_TO_JSVAL(valuesToJSElements(cx, JS_NewArrayObject(cx, 0, NULL), val, 0));
}
default: {
return JSVAL_VOID;
@@ -288,8 +258,44 @@ const jsval valueToJSVal(const JSONContext& cx, const value& val) {
}
}
+const failable<bool, std::string> writeList(const JSONContext& cx, const list<value>& l, JSObject* o) {
+ if (isNil(l))
+ return true;
+
+ // Write an attribute
+ const value token(car(l));
+
+ if (isTaggedList(token, attribute)) {
+ jsval pv = valueToJSVal(cx, attributeValue(token));
+ JS_SetProperty(cx, o, std::string(attributeName(token)).c_str(), &pv);
+
+ } else if (isTaggedList(token, element)) {
+
+ // Write the value of an element
+ if (elementHasValue(token)) {
+ jsval pv = valueToJSVal(cx, elementValue(token));
+ JS_SetProperty(cx, o, std::string(elementName(token)).c_str(), &pv);
+
+ } else {
+
+ // Write a parent element
+ JSObject* child = JS_NewObject(cx, NULL, NULL, NULL);
+ jsval pv = OBJECT_TO_JSVAL(child);
+ JS_SetProperty(cx, o, std::string(elementName(token)).c_str(), &pv);
+
+ // Write its children
+ const failable<bool, std::string> w = writeList(cx, elementChildren(token), child);
+ if (!hasValue(w))
+ return w;
+ }
+ }
+
+ // Go on
+ return writeList(cx, cdr(l), o);
+}
+
/**
- * Context passed to JSON write callback function.
+ * Context passed to the JSON write callback function.
*/
template<typename R> class JSONWriteContext {
public:
@@ -314,20 +320,25 @@ template<typename R> JSBool writeCallback(const jschar *buf, uint32 len, void *d
* Convert a list of values to a JSON document.
*/
template<typename R> const failable<R, std::string> writeJSON(const JSONContext& cx, const lambda<R(R, std::string)>& reduce, const R& initial, const list<value>& l) {
- jsval val = valueToJSVal(cx, l);
+ JSObject* o = JS_NewObject(cx, NULL, NULL, NULL);
+ jsval val = OBJECT_TO_JSVAL(o);
+ const failable<bool, std::string> w = writeList(cx, l, o);
+ if (!hasValue(w))
+ return std::string(w);
+
JSONWriteContext<R> wcx(cx, reduce, initial);
if (!JS_Stringify(cx, &val, NULL, JSVAL_NULL, writeCallback<R>, &wcx))
return std::string("JS_Stringify failed");
return wcx.accum;
}
+/**
+ * Convert a list of values to a list of strings representing a JSON document.
+ */
const list<std::string> writeJSONList(const list<std::string>& listSoFar, const std::string& s) {
return cons(s, listSoFar);
}
-/**
- * Convert a list of values to a JSON document represented as a list of strings.
- */
const failable<list<std::string>, std::string> writeJSON(const JSONContext& cx, const list<value>& l) {
const failable<list<std::string>, std::string> ls = writeJSON<list<std::string> >(cx, writeJSONList, list<std::string>(), l);
if (!hasValue(ls))
diff --git a/cpp/sca/test/store-script/htdocs/store.html b/cpp/sca/test/store-script/htdocs/store.html
index 42f58ab40c..4a2c65d07c 100644
--- a/cpp/sca/test/store-script/htdocs/store.html
+++ b/cpp/sca/test/store-script/htdocs/store.html
@@ -31,7 +31,7 @@
//var shoppingCart = new tuscany.sca.Reference("shoppingCart");
//@Reference
- //var shoppingTotal = new tuscany.sca.Reference("shoppingTotal");
+ var shoppingTotal = new tuscany.sca.Reference("shoppingTotal");
var catalogItems;
@@ -42,13 +42,16 @@
}
var catalog = "";
- for (var i=0; i<items.length; i++) {
- var item = items[i].name + ' - ' + items[i].price;
- catalog += '<input name="items" type="checkbox" value="' +
- item + '">' + item + ' <br>';
- }
- document.getElementById('catalog').innerHTML=catalog;
- catalogItems = items;
+ for (var i=0; i<items.length; i++) {
+ var item = items[i].name + ' - ' + items[i].price;
+ catalog += '<input name="items" type="checkbox" value="' +
+ item + '">' + item + ' <br>';
+ }
+ document.getElementById('catalog').innerHTML=catalog;
+ catalogItems = items;
+
+ // TEMP
+ shoppingTotal.getTotal(shoppingTotal_getTotalResponse);
}
function shoppingCart_getResponse(feed) {
@@ -65,7 +68,7 @@
if (entries.length != 0) {
try {
- //shoppingTotal.getTotal(shoppingTotal_getTotalResponse);
+ shoppingTotal.getTotal(shoppingTotal_getTotalResponse);
}
catch(e){
alert(e);
diff --git a/cpp/sca/test/store-script/htdocs/store.js b/cpp/sca/test/store-script/htdocs/store.js
index 47af7c01f7..526d36790a 100644
--- a/cpp/sca/test/store-script/htdocs/store.js
+++ b/cpp/sca/test/store-script/htdocs/store.js
@@ -652,7 +652,7 @@ tuscany.sca.Property = function (name) {
tuscany.sca.referenceMap = new Object();
tuscany.sca.referenceMap.catalog = new JSONRpcClient("/Catalog").Service;
//tuscany.sca.referenceMap.shoppingCart = new AtomClient("/ShoppingCart/Cart");
-//tuscany.sca.referenceMap.shoppingTotal = new JSONRpcClient("/ShoppingCart/Total").Service;
+tuscany.sca.referenceMap.shoppingTotal = new JSONRpcClient("/ShoppingCart/Total").Service;
tuscany.sca.Reference = function (name) {
return tuscany.sca.referenceMap[name];
}
diff --git a/cpp/sca/test/store-script/store-script-test.cpp b/cpp/sca/test/store-script/store-script-test.cpp
index 95e7ba0929..8eac2f7b8b 100644
--- a/cpp/sca/test/store-script/store-script-test.cpp
+++ b/cpp/sca/test/store-script/store-script-test.cpp
@@ -52,19 +52,35 @@ const tuscany::value evalLoop(std::istream& is, const tuscany::value& req, tusca
}
bool testEval() {
- std::ifstream is("store.scm", std::ios_base::in);
- std::ostringstream os;
+ {
+ std::ifstream is("store.scm", std::ios_base::in);
+ std::ostringstream os;
+
+ tuscany::setupEvalOut(os);
+ tuscany::Env globalEnv = tuscany::setupEnvironment();
+
+ const tuscany::value req(tuscany::mklist<tuscany::value>("storeui_service", std::string("getcatalog")));
+ const tuscany::value res = evalLoop(is, req, globalEnv);
+
+ std::ostringstream rs;
+ rs << res;
+ assert(contains(rs.str(), "List::(List::(List::(Symbol::name, (String::\"apple\", ())), (List::(Symbol::currency, (String::\"USD\", ())), (List::(Symbol::symbol, (String::\"$\", ())), (List::(Symbol::price, (Number::2.99, ())), ())))), (List::(List::(Symbol::name, (String::\"orange\", ())), (List::(Symbol::currency, (String::\"USD\", ())), (List::(Symbol::symbol, (String::\"$\", ())), (List::(Symbol::price, (Number::3.55, ())), ())))), (List::(List::(Symbol::name, (String::\"pear\", ())), (List::(Symbol::currency, (String::\"USD\", ())), (List::(Symbol::symbol, (String::\"$\", ())), (List::(Symbol::price, (Number::1.55, ())), ())))), ())))"));
+ }
- tuscany::setupEvalOut(os);
- tuscany::Env globalEnv = tuscany::setupEnvironment();
+ {
+ std::ifstream is("store.scm", std::ios_base::in);
+ std::ostringstream os;
- const tuscany::value req(tuscany::makeList<tuscany::value>("storeui_service", std::string("getcatalog")));
- const tuscany::value res = evalLoop(is, req, globalEnv);
+ tuscany::setupEvalOut(os);
+ tuscany::Env globalEnv = tuscany::setupEnvironment();
- std::ostringstream rs;
- rs << res;
- assert(contains(rs.str(), "List::(List::(List::(Symbol::name, (String::\"apple\", ())), (List::(Symbol::currency, (String::\"USD\", ())), (List::(Symbol::symbol, (String::\"$\", ())), (List::(Symbol::price, (Number::2.99, ())), ())))), (List::(List::(Symbol::name, (String::\"orange\", ())), (List::(Symbol::currency, (String::\"USD\", ())), (List::(Symbol::symbol, (String::\"$\", ())), (List::(Symbol::price, (Number::3.55, ())), ())))), (List::(List::(Symbol::name, (String::\"pear\", ())), (List::(Symbol::currency, (String::\"USD\", ())), (List::(Symbol::symbol, (String::\"$\", ())), (List::(Symbol::price, (Number::1.55, ())), ())))), ())))"));
+ const tuscany::value req(tuscany::mklist<tuscany::value>("storeui_service", std::string("gettotal")));
+ const tuscany::value res = evalLoop(is, req, globalEnv);
+ std::ostringstream rs;
+ rs << res;
+ assert(contains(rs.str(), "Number::10"));
+ }
return true;
}
diff --git a/cpp/sca/test/store-script/store.scm b/cpp/sca/test/store-script/store.scm
index 5bda81ca69..323a2ca304 100644
--- a/cpp/sca/test/store-script/store.scm
+++ b/cpp/sca/test/store-script/store.scm
@@ -54,10 +54,15 @@
content
)
+(define (cart_gettotal)
+ 10.0
+)
+
(define (cart_impl op args)
(cond
((equal? op "post") (apply cart_post args))
((equal? op "getall") (apply cart_getall args))
+ ((equal? op "gettotal") (apply cart_gettotal args))
)
)
@@ -75,11 +80,16 @@
(catalog "get")
)
+(define (storeui_gettotal cart)
+ (cart "gettotal")
+)
+
(define (storeui_impl cart catalog op args)
(cond
((equal? op "post") (apply storeui_post (cons cart args)))
((equal? op "getall") (apply storeui_getcart (cons cart args)))
((equal? op "getcatalog") (apply storeui_getcatalog (cons catalog args)))
+ ((equal? op "gettotal") (apply storeui_gettotal (cons cart args)))
)
)
@@ -96,9 +106,11 @@
(define apple (car catalog))
(define full (storeui_service "post" empty apple))
(display (storeui_service "getall" full))
+(display (storeui_service "gettotal"))
(; "Store UI JSON-RPC interop test case")
-(define (system.listMethods) (list "Service.get"))
+(define (system.listMethods) (list "Service.get" "Service.getTotal"))
(define (Service.get) (storeui_service "getcatalog"))
+(define (Service.getTotal) (storeui_service "gettotal"))