diff options
Diffstat (limited to 'sca-cpp/trunk/modules')
-rw-r--r-- | sca-cpp/trunk/modules/http/curl.hpp | 17 | ||||
-rw-r--r-- | sca-cpp/trunk/modules/json/json-test.cpp | 43 | ||||
-rw-r--r-- | sca-cpp/trunk/modules/json/json.hpp | 96 | ||||
-rw-r--r-- | sca-cpp/trunk/modules/server/mod-eval.hpp | 48 |
4 files changed, 135 insertions, 69 deletions
diff --git a/sca-cpp/trunk/modules/http/curl.hpp b/sca-cpp/trunk/modules/http/curl.hpp index d836eaa2f0..4e96411ec6 100644 --- a/sca-cpp/trunk/modules/http/curl.hpp +++ b/sca-cpp/trunk/modules/http/curl.hpp @@ -73,7 +73,7 @@ public: private: CURL* h; - bool owner; + const bool owner; friend CURL* handle(const CURLSession& c); }; @@ -217,15 +217,12 @@ const failable<value> evalExpr(const value& expr, const string& url, const CURLS if (!hasContent(res)) return mkfailure<value>(reason(res)); - // Return result - failable<list<value> > jsres = json::readJSON(cadr<list<string> >(content(res)), cx); - if (!hasContent(jsres)) - return mkfailure<value>(reason(jsres)); - const list<value> val = elementsToValues(content(jsres)); - - const value rval(cadr<value>(cadr<value>(val))); - debug(rval, "http::evalExpr::result"); - return rval; + // Parse and return JSON-RPC result + const failable<value> rval = json::jsonResultValue(cadr<list<string> >(content(res)), cx); + if (!hasContent(rval)) + return mkfailure<value>(reason(rval)); + debug(content(rval), "http::evalExpr::result"); + return content(rval); } /** diff --git a/sca-cpp/trunk/modules/json/json-test.cpp b/sca-cpp/trunk/modules/json/json-test.cpp index b4a6ba8746..41ac24a22e 100644 --- a/sca-cpp/trunk/modules/json/json-test.cpp +++ b/sca-cpp/trunk/modules/json/json-test.cpp @@ -54,17 +54,18 @@ bool testJSON() { const list<value> ac = mklist<value>(mklist<value>(element, "id", string("1234")), mklist<value>(attribute, "balance", 1000)); const list<value> cr = mklist<value>(mklist<value> (attribute, "name", 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))); + ostringstream os; writeJSON<ostream*>(jsonWriter, &os, c, cx); - assert(str(os) == "{\"customer\":{\"name\":\"jdoe\",\"address\":{\"city\":\"san francisco\",\"state\":\"ca\"},\"account\":{\"id\":\"1234\",\"balance\":1000}}}"); + assert(str(os) == "{\"customer\":{\"@name\":\"jdoe\",\"address\":{\"@city\":\"san francisco\",\"@state\":\"ca\"},\"account\":{\"id\":\"1234\",\"@balance\":1000}}}"); } { const list<value> phones = mklist<value> (string("408-1234"), string("650-1234")); - const list<value> l = mklist<value> (mklist<value> (element, "phones", phones), mklist<value> (element, "lastName", string("test\ttab")), mklist<value> (element, "firstName", string("test1"))); + const list<value> l = mklist<value> (mklist<value> (element, "phones", phones), mklist<value> (element, "lastName", string("test\ttab")), mklist<value> (attribute, "firstName", string("test1"))); ostringstream os; writeJSON<ostream*>(jsonWriter, &os, l, cx); - assert(str(os) == "{\"phones\":[\"408-1234\",\"650-1234\"],\"lastName\":\"test\\u0009tab\",\"firstName\":\"test1\"}"); + assert(str(os) == "{\"phones\":[\"408-1234\",\"650-1234\"],\"lastName\":\"test\\u0009tab\",\"@firstName\":\"test1\"}"); istringstream is(str(os)); const list<string> il = streamList(is); @@ -75,6 +76,18 @@ bool testJSON() { write(content(writeJSON(r, cx)), wos); assert(str(wos) == str(os)); } + { + const list<value> l = mklist<value>(list<value>() + "ns1:echoString" + (list<value>() + "@xmlns:ns1" + string("http://ws.apache.org/axis2/services/echo")) + (list<value>() + "text" + string("Hello World!"))); + cout << "l: " << l << endl; + ostringstream wos; + write(content(writeJSON(valuesToElements(l), cx)), wos); + assert(str(wos) == "{\"ns1:echoString\":{\"@xmlns:ns1\":\"http://ws.apache.org/axis2/services/echo\",\"text\":\"Hello World!\"}}"); + + istringstream is(str(wos)); + const list<string> il = streamList(is); + const list<value> r = elementsToValues(content(readJSON(il, cx))); + assert(r == l); + } return true; } @@ -121,6 +134,30 @@ bool testJSONRPC() { write(content(writeJSON(e, cx)), os); assert(str(os) == f); } + { + const list<value> arg = mklist<value>(list<value>() + "ns1:echoString" + (list<value>() + "@xmlns:ns1" + string("http://ws.apache.org/axis2/services/echo")) + (list<value>() + "text" + string("Hello World!"))); + const failable<list<string> > r = jsonRequest(1, "echo", mklist<value>(arg), cx); + ostringstream os; + write(content(r), os); + assert(str(os) == "{\"id\":1,\"method\":\"echo\",\"params\":[{\"ns1:echoString\":{\"@xmlns:ns1\":\"http://ws.apache.org/axis2/services/echo\",\"text\":\"Hello World!\"}}]}"); + + istringstream is(str(os)); + const list<string> il = streamList(is); + const list<value> ir = elementsToValues(content(readJSON(il, cx))); + assert(car<value>(cadr<value>(caddr<value>(ir))) == arg); + } + { + const list<value> res = mklist<value>(list<value>() + "ns1:echoString" + (list<value>() + "@xmlns:ns1" + string("http://ws.apache.org/axis2/c/samples")) + (list<value>() + "text" + string("Hello World!"))); + const failable<list<string> > r = jsonResult(1, res, cx); + ostringstream os; + write(content(r), os); + assert(str(os) == "{\"id\":1,\"result\":{\"ns1:echoString\":{\"@xmlns:ns1\":\"http://ws.apache.org/axis2/c/samples\",\"text\":\"Hello World!\"}}}"); + + istringstream is(str(os)); + const list<string> il = streamList(is); + const list<value> ir = elementsToValues(content(readJSON(il, cx))); + assert(cdr<value>(cadr<value>(ir)) == res); + } return true; } diff --git a/sca-cpp/trunk/modules/json/json.hpp b/sca-cpp/trunk/modules/json/json.hpp index 1116511455..4c36b8b477 100644 --- a/sca-cpp/trunk/modules/json/json.hpp +++ b/sca-cpp/trunk/modules/json/json.hpp @@ -131,6 +131,22 @@ private: }; /** + * Returns true if a list represents a JS array. + */ +const bool isJSArray(const list<value>& l) { + if(isNil(l)) + return true; + const value v = car(l); + if (isSymbol(v)) + return false; + if(isList(v)) { + if(isSymbol(car<value>(v))) + return false; + } + return true; +} + +/** * Converts JS properties to values. */ const list<value> jsPropertiesToValues(const list<value>& propertiesSoFar, JSObject* o, JSObject* i, const JSONContext& cx) { @@ -144,11 +160,16 @@ const list<value> jsPropertiesToValues(const list<value>& propertiesSoFar, JSObj if(!JS_GetPropertyById(cx, o, id, &jsv)) return propertiesSoFar; const value val = jsValToValue(jsv, cx); + jsval idv; JS_IdToValue(cx, id, &idv); if(JSVAL_IS_STRING(idv)) { - const value type = isList(val)? element : element; - return jsPropertiesToValues(cons<value> (mklist<value> (type, JS_GetStringBytes(JSVAL_TO_STRING(idv)), val), propertiesSoFar), o, i, cx); + const string name = JS_GetStringBytes(JSVAL_TO_STRING(idv)); + if (substr(name, 0, 1) == atsign) + return jsPropertiesToValues(cons<value>(mklist<value>(attribute, c_str(substr(name, 1)), val), propertiesSoFar), o, i, cx); + if (isList(val) && !isJSArray(val)) + return jsPropertiesToValues(cons<value>(cons<value>(element, cons<value>(c_str(name), list<value>(val))), propertiesSoFar), o, i, cx); + return jsPropertiesToValues(cons<value> (mklist<value> (element, c_str(name), val), propertiesSoFar), o, i, cx); } return jsPropertiesToValues(cons(val, propertiesSoFar), o, i, cx); } @@ -227,39 +248,11 @@ JSObject* valuesToJSElements(JSObject* a, const list<value>& l, int i, const JSO } /** - * Returns true if a list represents a JS array. - */ -const bool isJSArray(const list<value>& l) { - if(isNil(l)) - return false; - const 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 properties. - */ -JSObject* valuesToJSProperties(JSObject* o, const list<value>& l, const JSONContext& cx) { - const jsval valueToJSVal(const value& val, const JSONContext& cx); - if(isNil(l)) - return o; - const list<value> p = car(l); - jsval pv = valueToJSVal(caddr(p), cx); - JS_SetProperty(cx, o, c_str((string)cadr(p)), &pv); - return valuesToJSProperties(o, cdr(l), cx); -} - -/** * Converts a value to a JS val. */ const jsval valueToJSVal(const value& val, const JSONContext& cx) { + JSObject* valuesToJSProperties(JSObject* o, const list<value>& l, const JSONContext& cx); + switch(type(val)) { case value::String: case value::Symbol: { @@ -282,16 +275,19 @@ const jsval valueToJSVal(const value& val, const JSONContext& cx) { } } -const failable<bool> writeList(const list<value>& l, JSObject* o, const JSONContext& cx) { +/** + * Converts a list of values to JS properties. + */ +JSObject* valuesToJSProperties(JSObject* o, const list<value>& l, const JSONContext& cx) { if (isNil(l)) - return true; + return o; // Write an attribute const value token(car(l)); if (isTaggedList(token, attribute)) { jsval pv = valueToJSVal(attributeValue(token), cx); - JS_SetProperty(cx, o, c_str(string(attributeName(token))), &pv); + JS_SetProperty(cx, o, c_str(atsign + string(attributeName(token))), &pv); } else if (isTaggedList(token, element)) { @@ -308,14 +304,12 @@ const failable<bool> writeList(const list<value>& l, JSObject* o, const JSONCont JS_SetProperty(cx, o, c_str(string(elementName(token))), &pv); // Write its children - const failable<bool> w = writeList(elementChildren(token), child, cx); - if (!hasContent(w)) - return w; + valuesToJSProperties(child, elementChildren(token), cx); } } // Go on - return writeList(cdr(l), o, cx); + return valuesToJSProperties(o, cdr(l), cx); } /** @@ -344,11 +338,7 @@ 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> writeJSON(const lambda<R(const string&, const R)>& reduce, const R& initial, const list<value>& l, const JSONContext& cx) { - JSObject* o = JS_NewObject(cx, NULL, NULL, NULL); - jsval val = OBJECT_TO_JSVAL(o); - const failable<bool> w = writeList(l, o, cx); - if (!hasContent(w)) - return mkfailure<R>(reason(w)); + jsval val = OBJECT_TO_JSVAL(valuesToJSProperties(JS_NewObject(cx, NULL, NULL, NULL), l, cx)); WriteContext<R> wcx(reduce, initial, cx); if (!JS_Stringify(cx, &val, NULL, JSVAL_NULL, writeCallback<R>, &wcx)) @@ -367,7 +357,7 @@ const failable<list<string> > writeJSON(const list<value>& l, const JSONContext& } /** - * Convert a function + params to a JSON request. + * Convert a list of function + params to a JSON-RPC request. */ const failable<list<string> > jsonRequest(const value& id, const value& func, const value& params, json::JSONContext& cx) { const list<value> r = mklist<value>(mklist<value>("id", id), mklist<value>("method", string(func)), mklist<value>("params", params)); @@ -375,13 +365,27 @@ const failable<list<string> > jsonRequest(const value& id, const value& func, co } /** - * Convert a value to a JSON result. + * Convert a value to a JSON-RPC result. */ const failable<list<string> > jsonResult(const value& id, const value& val, JSONContext& cx) { return writeJSON(valuesToElements(mklist<value>(mklist<value>("id", id), mklist<value>("result", val))), cx); } /** + * Convert a JSON-RPC result to a value. + */ +const failable<value> jsonResultValue(const list<string>& s, JSONContext& cx) { + const failable<list<value> > jsres = json::readJSON(s, cx); + if (!hasContent(jsres)) + return mkfailure<value>(reason(jsres)); + const list<value> rval(cadr<value>(elementsToValues(content(jsres)))); + const value val = cadr(rval); + if (isList(val) && !isJSArray(val)) + return value(mklist<value>(val)); + return val; +} + +/** * Return a portable function name from a JSON-RPC function name. * Strip the "system." and "Service." prefixes added by some JSON-RPC clients. */ diff --git a/sca-cpp/trunk/modules/server/mod-eval.hpp b/sca-cpp/trunk/modules/server/mod-eval.hpp index f5c4266cc1..dfc376c55c 100644 --- a/sca-cpp/trunk/modules/server/mod-eval.hpp +++ b/sca-cpp/trunk/modules/server/mod-eval.hpp @@ -269,19 +269,45 @@ int handler(request_rec *r) { /** * Convert a list of component references to a list of HTTP proxy lambdas. */ -const value mkproxy(const value& ref, const string& base) { +const value mkrefProxy(const value& ref, const string& base) { return lambda<value(const list<value>&)>(http::proxy(base + string(scdl::name(ref)))); } -const list<value> proxies(const list<value>& refs, const string& base) { +const list<value> refProxies(const list<value>& refs, const string& base) { if (isNil(refs)) return refs; - return cons(mkproxy(car(refs), base), proxies(cdr(refs), base)); + return cons(mkrefProxy(car(refs), base), refProxies(cdr(refs), base)); } -extern const failable<lambda<value(const list<value>&)> > evalImplementation(const string& cpath, const value& impl, const list<value>& px); +/** + * Convert a list of component properties to a list of lambda functions that just return + * the property value. + */ +struct propProxy { + const value v; + propProxy(const value& v) : v(v) { + } + const value operator()(unused const list<value>& params) const { + return v; + } +}; + +const value mkpropProxy(const value& prop) { + return lambda<value(const list<value>&)>(propProxy(elementValue(prop))); +} + +const list<value> propProxies(const list<value>& props) { + if (isNil(props)) + return props; + return cons(mkpropProxy(car(props)), propProxies(cdr(props))); +} + +/** + * Evaluate a component and convert it to an applicable lambda function. + */ +const value evalComponent(DirConf& dc, ServerConf& sc, server_rec& server, const value& comp) { + extern const failable<lambda<value(const list<value>&)> > evalImplementation(const string& cpath, const value& impl, const list<value>& px); -const value confImplementation(DirConf& dc, ServerConf& sc, server_rec& server, const value& comp) { const value impl = scdl::implementation(comp); // Convert component references to configured proxy lambdas @@ -293,11 +319,13 @@ const value confImplementation(DirConf& dc, ServerConf& sc, server_rec& server, << "/references/" << string(scdl::name(comp)) << "/"; else base << sc.wiringServerName << "/references/" << string(scdl::name(comp)) << "/"; - const list<value> px(proxies(scdl::references(comp), str(base))); + const list<value> rpx(refProxies(scdl::references(comp), str(base))); + + // Convert component proxies to configured proxy lambdas + const list<value> ppx(propProxies(scdl::properties(comp))); - // Evaluate the component implementation and convert it to an - // applicable lambda function - const failable<lambda<value(const list<value>&)> > cimpl(evalImplementation(dc.contributionPath, impl, px)); + // Evaluate the component implementation and convert it to an applicable lambda function + const failable<lambda<value(const list<value>&)> > cimpl(evalImplementation(dc.contributionPath, impl, append(rpx, ppx))); if (!hasContent(cimpl)) return reason(cimpl); return content(cimpl); @@ -309,7 +337,7 @@ const value confImplementation(DirConf& dc, ServerConf& sc, server_rec& server, const list<value> componentToImplementationAssoc(DirConf& dc, ServerConf& sc, server_rec& server, const list<value>& c) { if (isNil(c)) return c; - return cons<value>(mklist<value>(scdl::name(car(c)), confImplementation(dc, sc, server, car(c))), componentToImplementationAssoc(dc, sc, server, cdr(c))); + return cons<value>(mklist<value>(scdl::name(car(c)), evalComponent(dc, sc, server, car(c))), componentToImplementationAssoc(dc, sc, server, cdr(c))); } const list<value> componentToImplementationTree(DirConf& dc, ServerConf& sc, server_rec& server, const list<value>& c) { |