diff options
Diffstat (limited to 'sca-cpp/trunk')
24 files changed, 515 insertions, 422 deletions
diff --git a/sca-cpp/trunk/components/cache/mcache.cpp b/sca-cpp/trunk/components/cache/mcache.cpp index b60301bbf2..926fb66674 100644 --- a/sca-cpp/trunk/components/cache/mcache.cpp +++ b/sca-cpp/trunk/components/cache/mcache.cpp @@ -89,15 +89,16 @@ const failable<value, std::string> del(const list<value>& params) { extern "C" { -const tuscany::failable<tuscany::value, std::string> eval(const tuscany::value& func, const tuscany::list<tuscany::value>& params) { +const tuscany::value eval(const tuscany::list<tuscany::value>& params) { + const tuscany::value func(car(params)); if (func == "get") - return tuscany::cache::get(params); + return tuscany::cache::get(cdr(params)); if (func == "post") - return tuscany::cache::post(params); + return tuscany::cache::post(cdr(params)); if (func == "put") - return tuscany::cache::put(params); + return tuscany::cache::put(cdr(params)); if (func == "delete") - return tuscany::cache::del(params); + return tuscany::cache::del(cdr(params)); return tuscany::mkfailure<tuscany::value, std::string>(std::string("Function not supported: ") + std::string(func)); } diff --git a/sca-cpp/trunk/components/cache/memcached-server-test b/sca-cpp/trunk/components/cache/memcached-server-test index 7cd01fe6f5..0dc32f6613 100755 --- a/sca-cpp/trunk/components/cache/memcached-server-test +++ b/sca-cpp/trunk/components/cache/memcached-server-test @@ -22,11 +22,9 @@ ../../modules/server/server-conf tmp cat >>tmp/conf/httpd.conf <<EOF -<Location /mcache> -SetHandler mod_tuscany_eval +<Location /> SCAContribution `pwd`/ SCAComposite mcache.composite -SCAComponent mcache </Location> EOF @@ -34,7 +32,7 @@ apachectl -k start -d `pwd`/tmp mc="memcached -l 127.0.0.1 -m 4 -p 11211" $mc & -sleep 1 +sleep 2 # Test ./mcache-client-test 2>/dev/null @@ -43,5 +41,5 @@ rc=$? # Cleanup kill `ps -f | grep -v grep | grep "$mc" | awk '{ print $2 }'` apachectl -k stop -d `pwd`/tmp -sleep 1 +sleep 2 return $rc diff --git a/sca-cpp/trunk/modules/eval/primitive.hpp b/sca-cpp/trunk/modules/eval/primitive.hpp index 49bb3e2087..37c53fdd0b 100644 --- a/sca-cpp/trunk/modules/eval/primitive.hpp +++ b/sca-cpp/trunk/modules/eval/primitive.hpp @@ -77,6 +77,10 @@ const value listProc(const list<value>& args) { return args; } +const value assocProc(const list<value>& args) { + return assoc(car(args), (list<list<value> >)cadr(args)); +} + const value nulProc(const list<value>& args) { const value v(car(args)); if (isNil(v)) @@ -136,8 +140,28 @@ const value uuidProc(unused const list<value>& args) { return std::string(buf, APR_UUID_FORMATTED_LENGTH); } +const value cadrProc(unused const list<value>& args) { + return cadr((list<value> )car(args)); +} + +const value caddrProc(unused const list<value>& args) { + return caddr((list<value> )car(args)); +} + +const value cadddrProc(unused const list<value>& args) { + return cadddr((list<value> )car(args)); +} + +const value cddrProc(unused const list<value>& args) { + return cddr((list<value> )car(args)); +} + +const value cdddrProc(unused const list<value>& args) { + return cdddr((list<value> )car(args)); +} + const value applyPrimitiveProcedure(const value& proc, list<value>& args) { - const lambda<value(list<value>&)> func(cadr((list<value>)proc)); + const lambda<value(const list<value>&)> func(cadr((list<value>)proc)); return func(args); } @@ -166,7 +190,7 @@ const value primitiveImplementation(const list<value>& proc) { } template<typename F> const value primitiveProcedure(const F& f) { - return mklist<value>(primitiveSymbol, (lambda<value(list<value>&)>)f); + return mklist<value>(primitiveSymbol, (lambda<value(const list<value>&)>)f); } const list<value> primitiveProcedureNames() { @@ -176,11 +200,17 @@ const list<value> primitiveProcedureNames() { l = cons<value>("list", l); l = cons<value>("nul", l); l = cons<value>("=", l); + l = cons<value>("equal?", l); l = cons<value>("+", l); l = cons<value>("-", l); l = cons<value>("*", l); l = cons<value>("/", l); - l = cons<value>("equal?", l); + l = cons<value>("assoc", l); + l = cons<value>("cadr", l); + l = cons<value>("caddr", l); + l = cons<value>("cadddr", l); + l = cons<value>("cddr", l); + l = cons<value>("cdddr", l); l = cons<value>("display", l); l = cons<value>("log", l); l = cons<value>("uuid", l); @@ -194,11 +224,17 @@ const list<value> primitiveProcedureObjects() { l = cons(primitiveProcedure(listProc), l); l = cons(primitiveProcedure(nulProc), l); l = cons(primitiveProcedure(equalProc), l); + l = cons(primitiveProcedure(equalProc), l); l = cons(primitiveProcedure(addProc), l); l = cons(primitiveProcedure(subProc), l); l = cons(primitiveProcedure(mulProc), l); l = cons(primitiveProcedure(divProc), l); - l = cons(primitiveProcedure(equalProc), l); + l = cons(primitiveProcedure(assocProc), l); + l = cons(primitiveProcedure(cadrProc), l); + l = cons(primitiveProcedure(caddrProc), l); + l = cons(primitiveProcedure(cadddrProc), l); + l = cons(primitiveProcedure(cddrProc), l); + l = cons(primitiveProcedure(cdddrProc), l); l = cons(primitiveProcedure(displayProc), l); l = cons(primitiveProcedure(logProc), l); l = cons(primitiveProcedure(uuidProc), l); diff --git a/sca-cpp/trunk/modules/http/http-test b/sca-cpp/trunk/modules/http/http-test index 0aaaec48df..bf6230aec8 100755 --- a/sca-cpp/trunk/modules/http/http-test +++ b/sca-cpp/trunk/modules/http/http-test @@ -20,7 +20,7 @@ # Setup ./httpd-conf tmp 8090 htdocs apachectl -k start -d `pwd`/tmp -sleep 1 +sleep 2 # Test ./curl-test @@ -28,5 +28,5 @@ rc=$? # Cleanup apachectl -k stop -d `pwd`/tmp -sleep 1 +sleep 2 return $rc diff --git a/sca-cpp/trunk/modules/http/httpd-conf b/sca-cpp/trunk/modules/http/httpd-conf index b00ee06ed3..686bfbcec7 100755 --- a/sca-cpp/trunk/modules/http/httpd-conf +++ b/sca-cpp/trunk/modules/http/httpd-conf @@ -27,7 +27,7 @@ mkdir -p $root mkdir -p $root/logs mkdir -p $root/conf cat >$root/conf/httpd.conf <<EOF -ServerName 127.0.0.1 +ServerName http://127.0.0.1:$port Listen $port DocumentRoot $htdocs TypesConfig $here/conf/mime.types diff --git a/sca-cpp/trunk/modules/http/httpd-test b/sca-cpp/trunk/modules/http/httpd-test index 8e1d681d84..762c4c7f6b 100755 --- a/sca-cpp/trunk/modules/http/httpd-test +++ b/sca-cpp/trunk/modules/http/httpd-test @@ -22,7 +22,7 @@ echo "Testing..." # Setup ./httpd-conf tmp 8090 htdocs apachectl -k start -d `pwd`/tmp -sleep 1 +sleep 2 # Test HTTP GET curl http://localhost:8090/index.html 2>/dev/null >tmp/index.html @@ -31,7 +31,7 @@ rc=$? # Cleanup apachectl -k stop -d `pwd`/tmp -sleep 1 +sleep 2 if [ "$rc" = "0" ]; then echo "OK" fi diff --git a/sca-cpp/trunk/modules/http/httpd.hpp b/sca-cpp/trunk/modules/http/httpd.hpp index 05b959f1d2..890fee8f01 100644 --- a/sca-cpp/trunk/modules/http/httpd.hpp +++ b/sca-cpp/trunk/modules/http/httpd.hpp @@ -69,6 +69,11 @@ template<typename C> const C& serverConf(const request_rec* r, const module* mod return *(C*)ap_get_module_config(r->server->module_config, mod); } +template<typename C> C& serverConf(const cmd_parms *cmd, const module* mod) { + return *(C*)ap_get_module_config(cmd->server->module_config, mod); +} + + /** * Returns a directory-scoped module configuration. */ @@ -88,7 +93,9 @@ template<typename C> C& dirConf(const request_rec* r, const module* mod) { const list<std::string> pathTokens(const char* p) { if (p == NULL || p[0] == '\0') return list<std::string>(); - return tokenize("/", p + 1); + if (p[0] == '/') + return tokenize("/", p + 1); + return tokenize("/", p); } const list<value> pathValues(const list<std::string>& l) { @@ -107,7 +114,7 @@ const list<value> path(const char* p) { const std::string path(const list<value>& p) { if (isNil(p)) return ""; - return "/" + car(p) + path(cdr(p)); + return std::string("/") + std::string(car(p)) + path(cdr(p)); } /** @@ -141,11 +148,11 @@ const bool debugRequest(request_rec* r, const std::string& msg) { std::cerr << " content type: " << contentType(r) << std::endl; std::cerr << " content encoding: " << optional(r->content_encoding) << std::endl; apr_table_do(debugHeader, r, r->headers_in, NULL); - std::cerr << " uri: " << optional(r->unparsed_uri) << std::endl; - std::cerr << " path: " << optional(r->uri) << std::endl; + std::cerr << " unparsed uri: " << optional(r->unparsed_uri) << std::endl; + std::cerr << " uri: " << optional(r->uri) << std::endl; std::cerr << " path info: " << optional(r->path_info) << std::endl; std::cerr << " filename: " << optional(r->filename) << std::endl; - std::cerr << " path tokens: " << pathTokens(r->uri) << std::endl; + std::cerr << " uri tokens: " << pathTokens(r->uri) << std::endl; std::cerr << " args: " << optional(r->args) << std::endl; return true; } @@ -159,6 +166,15 @@ const bool debugRequest(request_rec* r, const std::string& msg) { #endif /** + * Return the remaining part of a uri after the given path (aka the path info.) + */ +const list<value> pathInfo(const list<value>& uri, const list<value>& path) { + if (isNil(path)) + return uri; + return pathInfo(cdr(uri), cdr(path)); +} + +/** * Returns a list of key value pairs from the args in a query string. */ const list<value> queryArg(const std::string& s) { diff --git a/sca-cpp/trunk/modules/scdl/scdl-test.cpp b/sca-cpp/trunk/modules/scdl/scdl-test.cpp index c3da1013a8..582d1ee073 100644 --- a/sca-cpp/trunk/modules/scdl/scdl-test.cpp +++ b/sca-cpp/trunk/modules/scdl/scdl-test.cpp @@ -28,7 +28,9 @@ #include <sstream> #include <fstream> #include <string> +#include "list.hpp" #include "slist.hpp" +#include "tree.hpp" #include "scdl.hpp" namespace tuscany { @@ -53,6 +55,9 @@ bool testComponents() { const value catalog = named(std::string("Catalog"), c); assert(name(catalog) == std::string("Catalog")); + + const list<value> t = mkbtree(sort(nameToElementAssoc(c))); + assert(assoctree<value>("Catalog", t) == mklist<value>("Catalog" , cadr(c))); return true; } @@ -86,6 +91,9 @@ bool testReferences() { const value binding = car(bindings(catalog)); assert(uri(binding) == value()); assert(bindingType(binding) == "t:binding.jsonrpc"); + + const list<value> t = mkbtree(sort(referenceToTargetAssoc(references(store)))); + assert(assoctree<value>("shoppingCart", t) == mklist<value>(std::string("shoppingCart"), std::string("ShoppingCart/Cart"))); return true; } diff --git a/sca-cpp/trunk/modules/scdl/scdl.hpp b/sca-cpp/trunk/modules/scdl/scdl.hpp index 4d84610fb0..9d4bf38b50 100644 --- a/sca-cpp/trunk/modules/scdl/scdl.hpp +++ b/sca-cpp/trunk/modules/scdl/scdl.hpp @@ -53,6 +53,16 @@ const value name(const value& l) { } /** + * Convert a list of elements to a name -> element assoc list. + */ +const list<value> nameToElementAssoc(const list<value>& l) { + if (isNil(l)) + return l; + const value e(car(l)); + return cons<value>(mklist<value>(name(e), e), nameToElementAssoc(cdr(l))); +} + +/** * Returns the scdl declaration with the given name. */ struct filterName { @@ -107,17 +117,20 @@ const list<value> references(const value& l) { } /** - * Returns a list of properties in a component. + * Returns the target of a reference. */ -const list<value> properties(const value& l) { - return elementChildren("property", l); +const value target(const value& l) { + return attributeValue("target", l); } /** - * Returns the target of a reference. + * Convert a list of references to a reference name -> target assoc list. */ -const value target(const value& l) { - return attributeValue("target", l); +const list<value> referenceToTargetAssoc(const list<value>& r) { + if (isNil(r)) + return r; + const value ref(car(r)); + return cons<value>(mklist<value>(scdl::name(ref), scdl::target(ref)), referenceToTargetAssoc(cdr(r))); } /** @@ -132,6 +145,13 @@ const list<value> bindings(const value& l) { } /** + * Returns a list of properties in a component. + */ +const list<value> properties(const value& l) { + return elementChildren("property", l); +} + +/** * Returns the type of an implementation. */ const value implementationType(const value& l) { diff --git a/sca-cpp/trunk/modules/server/domain-test.composite b/sca-cpp/trunk/modules/server/domain-test.composite index 48570e64d3..b39f66c30a 100644 --- a/sca-cpp/trunk/modules/server/domain-test.composite +++ b/sca-cpp/trunk/modules/server/domain-test.composite @@ -41,7 +41,7 @@ <service name="client"> <t:binding.http uri="client"/> </service> - <reference name="ref" target="test"> + <reference name="ref" target="server-test"> <t:binding.http/> </reference> </component> diff --git a/sca-cpp/trunk/modules/server/httpd-test b/sca-cpp/trunk/modules/server/httpd-test index 2f50c9f3c3..7dccfbf112 100755 --- a/sca-cpp/trunk/modules/server/httpd-test +++ b/sca-cpp/trunk/modules/server/httpd-test @@ -24,16 +24,14 @@ echo "Testing..." ./server-conf tmp cat >>tmp/conf/httpd.conf <<EOF -<Location /test> -SetHandler mod_tuscany_eval +<Location /> SCAContribution `pwd`/ SCAComposite domain-test.composite -SCAComponent server-test </Location> EOF apachectl -k start -d `pwd`/tmp -sleep 1 +sleep 2 # Test HTTP GET curl http://localhost:8090/index.html 2>/dev/null >tmp/index.html @@ -73,7 +71,7 @@ fi # Cleanup apachectl -k stop -d `pwd`/tmp -sleep 1 +sleep 2 if [ "$rc" = "0" ]; then echo "OK" fi diff --git a/sca-cpp/trunk/modules/server/impl-test.cpp b/sca-cpp/trunk/modules/server/impl-test.cpp index 217c6f5171..171a78f2d5 100644 --- a/sca-cpp/trunk/modules/server/impl-test.cpp +++ b/sca-cpp/trunk/modules/server/impl-test.cpp @@ -51,7 +51,7 @@ const failable<value, std::string> del(unused const list<value>& params) { } const failable<value, std::string> hello(const list<value>& params) { - return value("hello " + std::string(car(params))); + return value(std::string("hello ") + std::string(car(params))); } } @@ -59,17 +59,18 @@ const failable<value, std::string> hello(const list<value>& params) { extern "C" { -const tuscany::failable<tuscany::value, std::string> eval(const tuscany::value& func, const tuscany::list<tuscany::value>& params) { +const tuscany::value eval(const tuscany::list<tuscany::value>& params) { + const tuscany::value func(car(params)); if (func == "get") - return tuscany::server::get(params); + return tuscany::server::get(cdr(params)); if (func == "post") - return tuscany::server::post(params); + return tuscany::server::post(cdr(params)); if (func == "put") - return tuscany::server::put(params); + return tuscany::server::put(cdr(params)); if (func == "del") - return tuscany::server::del(params); + return tuscany::server::del(cdr(params)); if (func == "hello") - return tuscany::server::hello(params); + return tuscany::server::hello(cdr(params)); return tuscany::mkfailure<tuscany::value, std::string>(std::string("Function not supported: ") + std::string(func)); } diff --git a/sca-cpp/trunk/modules/server/mod-cpp.hpp b/sca-cpp/trunk/modules/server/mod-cpp.hpp index 99b69a0d9f..664e9d2e41 100644 --- a/sca-cpp/trunk/modules/server/mod-cpp.hpp +++ b/sca-cpp/trunk/modules/server/mod-cpp.hpp @@ -37,10 +37,8 @@ #include "debug.hpp" #include "monad.hpp" #include "dynlib.hpp" -#include "cache.hpp" #include "../eval/driver.hpp" #include "../http/httpd.hpp" -#include "mod-eval.hpp" namespace tuscany { namespace server { @@ -52,14 +50,14 @@ namespace cpp { */ struct evalImplementation { const lib ilib; - const ilambda impl; + const lambda<value(const list<value>&)> impl; const list<value> px; - evalImplementation(const lib& ilib, const ilambda& impl, const list<value>& px) : ilib(ilib), impl(impl), px(px) { + evalImplementation(const lib& ilib, const lambda<value(const list<value>&)>& impl, const list<value>& px) : ilib(ilib), impl(impl), px(px) { } - const failable<value, std::string> operator()(const value& func, const list<value>& params) const { - debug(cons<value>(func, params), "modeval::cpp::evalImplementation::input"); - const failable<value, std::string> val = impl(func, append(params, px)); - debug(content(val), "modeval::cpp::evalImplementation::result"); + const value operator()(const list<value>& params) const { + debug(params, "modeval::cpp::evalImplementation::input"); + const value val = impl(append(params, px)); + debug(val, "modeval::cpp::evalImplementation::result"); return val; } }; @@ -67,22 +65,15 @@ struct evalImplementation { /** * Read a C++ component implementation. */ -const failable<ilambda, std::string> readLatestImplementation(const std::string path, const list<value>& px) { - const failable<lib, std::string> ilib(dynlib(path)); +const failable<lambda<value(const list<value>&)>, std::string> readImplementation(const std::string path, const list<value>& px) { + const failable<lib, std::string> ilib(dynlib(path + dynlibExt)); if (!hasContent(ilib)) - return mkfailure<ilambda, std::string>(reason(ilib)); + return mkfailure<lambda<value(const list<value>&)>, std::string>(reason(ilib)); - const failable<ilambda, std::string> impl(dynlambda<failable<value, std::string>(value, list<value>)>("eval", content(ilib))); + const failable<lambda<value(const list<value>&)>, std::string> impl(dynlambda<value(const list<value>&)>("eval", content(ilib))); if (!hasContent(impl)) return impl; - return ilambda(evalImplementation(content(ilib), content(impl), px)); -} - -const cached<failable<ilambda, std::string> > readImplementation(const std::string& path, const list<value>& px) { - const lambda<failable<ilambda, std::string>(std::string, list<value>)> ri(readLatestImplementation); - const lambda<unsigned long(std::string)> ft(latestFileTime); - const std::string p(path + dynlibExt); - return cached<failable<ilambda, std::string> >(curry(ri, p, px), curry(ft, p)); + return lambda<value(const list<value>&)>(evalImplementation(content(ilib), content(impl), px)); } } diff --git a/sca-cpp/trunk/modules/server/mod-eval.cpp b/sca-cpp/trunk/modules/server/mod-eval.cpp index aa0a6067a1..d8354c6a58 100644 --- a/sca-cpp/trunk/modules/server/mod-eval.cpp +++ b/sca-cpp/trunk/modules/server/mod-eval.cpp @@ -30,17 +30,16 @@ #include "function.hpp" #include "list.hpp" +#include "tree.hpp" #include "slist.hpp" #include "value.hpp" #include "element.hpp" #include "monad.hpp" -#include "cache.hpp" #include "../atom/atom.hpp" #include "../json/json.hpp" #include "../scdl/scdl.hpp" #include "../http/curl.hpp" #include "../http/httpd.hpp" -#include "mod-eval.hpp" #include "mod-scm.hpp" #include "mod-cpp.hpp" @@ -57,41 +56,41 @@ namespace modeval { */ class ServerConf { public: - ServerConf(server_rec* s) : s(s), home(""), wiringHost("") { + ServerConf(server_rec* s) : s(s), home(""), wiringServerName("") { } const server_rec* s; std::string home; - std::string wiringHost; + std::string wiringServerName; }; /** - * Port number used for wiring requests. Set it to zero to use the current - * server port number, set it to a port number to direct wiring requests - * to that port, for debugging or tracing for example. - */ -int debugWiringPort = 0; - -/** * Directory configuration. */ class DirConf { public: - DirConf(char* dirspec) : dirspec(dirspec), contributionPath(""), compositeName(""), componentName(""), implementationPath("") { + DirConf(char* dirspec) : dirspec(dirspec), contributionPath(""), compositeName("") { } const char* dirspec; std::string contributionPath; std::string compositeName; - std::string componentName; - std::string implementationPath; - cached<failable<value, std::string> > component; - cached<failable<ilambda, std::string> > implementation; + list<value> implementations; }; /** + * Convert a result represented as a content + failure pair to a + * failable monad. + */ +const failable<value, std::string> failableResult(const list<value>& v) { + if (isNil(cdr(v))) + return car(v); + return mkfailure<value, std::string>(cadr(v)); +} + +/** * Handle an HTTP GET. */ -const failable<int, std::string> get(request_rec* r, const ilambda& impl) { - debug(r->uri, "modeval::get::url"); +const failable<int, std::string> get(request_rec* r, const lambda<value(const list<value>&)>& impl) { + debug(r->uri, "modeval::get::uri"); // Inspect the query string const list<list<value> > args = httpd::queryArgs(r); @@ -104,10 +103,9 @@ const failable<int, std::string> get(request_rec* r, const ilambda& impl) { // Extract the request id, method and params const value id = cadr(ia); const value func = std::string(cadr(ma)).c_str(); - const list<value> params = httpd::queryParams(args); // Apply the requested function - const failable<value, std::string> val = impl(func, params); + const failable<value, std::string> val = failableResult(impl(cons(func, httpd::queryParams(args)))); if (!hasContent(val)) return mkfailure<int, std::string>(reason(val)); @@ -117,16 +115,16 @@ const failable<int, std::string> get(request_rec* r, const ilambda& impl) { } // Evaluate an ATOM GET request and return an ATOM feed - const list<value> id(httpd::path(r->path_info)); - if (isNil(id)) { - const failable<value, std::string> val = impl("getall", list<value>()); + const list<value> path(httpd::path(r->uri)); + if (isNil(cddr(path))) { + const failable<value, std::string> val = failableResult(impl(cons<value>("getall", list<value>()))); if (!hasContent(val)) return mkfailure<int, std::string>(reason(val)); return httpd::writeResult(atom::writeATOMFeed(atom::feedValuesToElements(content(val))), "application/atom+xml;type=feed", r); } // Evaluate an ATOM GET and return an ATOM entry - const failable<value, std::string> val = impl("get", mklist<value>(car(id))); + const failable<value, std::string> val = failableResult(impl(cons<value>("get", mklist<value>(caddr(path))))); if (!hasContent(val)) return mkfailure<int, std::string>(reason(val)); return httpd::writeResult(atom::writeATOMEntry(atom::entryValuesToElements(content(val))), "application/atom+xml;type=entry", r); @@ -135,7 +133,7 @@ const failable<int, std::string> get(request_rec* r, const ilambda& impl) { /** * Handle an HTTP POST. */ -const failable<int, std::string> post(request_rec* r, const ilambda& impl) { +const failable<int, std::string> post(request_rec* r, const lambda<value(const list<value>&)>& impl) { const list<std::string> ls = httpd::read(r); debug(r->uri, "modeval::post::url"); debug(ls, "modeval::post::input"); @@ -153,7 +151,7 @@ const failable<int, std::string> post(request_rec* r, const ilambda& impl) { const list<value> params = (list<value>)cadr(assoc(value("params"), args)); // Evaluate the request expression - const failable<value, std::string> val = impl(func, params); + const failable<value, std::string> val = failableResult(impl(cons<value>(func, params))); if (!hasContent(val)) return mkfailure<int, std::string>(reason(val)); @@ -166,7 +164,7 @@ const failable<int, std::string> post(request_rec* r, const ilambda& impl) { // Evaluate the request expression const value entry = atom::entryValue(content(atom::readEntry(ls))); - const failable<value, std::string> val = impl("post", mklist<value>(entry)); + const failable<value, std::string> val = failableResult(impl(cons<value>("post", mklist<value>(entry)))); if (!hasContent(val)) return mkfailure<int, std::string>(reason(val)); @@ -182,15 +180,15 @@ const failable<int, std::string> post(request_rec* r, const ilambda& impl) { /** * Handle an HTTP PUT. */ -const failable<int, std::string> put(request_rec* r, const ilambda& impl) { +const failable<int, std::string> put(request_rec* r, const lambda<value(const list<value>&)>& impl) { const list<std::string> ls = httpd::read(r); debug(r->uri, "modeval::put::url"); debug(ls, "modeval::put::input"); // Evaluate an ATOM PUT request - const list<value> id(httpd::path(r->path_info)); + const list<value> path(httpd::path(r->uri)); const value entry = atom::entryValue(content(atom::readEntry(ls))); - const failable<value, std::string> val = impl("put", mklist<value>(car(id), entry)); + const failable<value, std::string> val = failableResult(impl(cons<value>("put", mklist<value>(caddr(path), entry)))); if (!hasContent(val)) return mkfailure<int, std::string>(reason(val)); if (val == value(false)) @@ -201,12 +199,12 @@ const failable<int, std::string> put(request_rec* r, const ilambda& impl) { /** * Handle an HTTP DELETE. */ -const failable<int, std::string> del(request_rec* r, const ilambda& impl) { +const failable<int, std::string> del(request_rec* r, const lambda<value(const list<value>&)>& impl) { debug(r->uri, "modeval::delete::url"); // Evaluate an ATOM delete request - const list<value> id(httpd::path(r->path_info)); - const failable<value, std::string> val = impl("delete", mklist<value>(car(id))); + const list<value> path(httpd::path(r->uri)); + const failable<value, std::string> val = failableResult(impl(cons<value>("delete", mklist<value>(caddr(path))))); if (!hasContent(val)) return mkfailure<int, std::string>(reason(val)); if (val == value(false)) @@ -215,53 +213,13 @@ const failable<int, std::string> del(request_rec* r, const ilambda& impl) { } /** - * Read the SCDL configuration of a component. - */ -const failable<value, std::string> readComponent(const std::string& path, const std::string& name) { - - // Read composite - std::ifstream is(path); - if (is.fail() || is.bad()) - return mkfailure<value, std::string>("Could not read composite: " + path); - - // Return the component - const list<value> c = scdl::components(readXML(streamList(is))); - const value comp = scdl::named(name, c); - if (isNil(comp)) - return mkfailure<value, std::string>("Could not find component: " + name); - return comp; -} - -const cached<failable<value, std::string> > component(DirConf* conf) { - const std::string path(conf->contributionPath + conf->compositeName); - const lambda<failable<value, std::string>(std::string, std::string)> rc(readComponent); - const lambda<unsigned long(std::string)> ft(latestFileTime); - return cached<failable<value, std::string> >(curry(rc, path, conf->componentName), curry(ft, path)); -} - -/** - * Convert a list of component references to a list of HTTP proxy lambdas. - */ -const value mkproxy(const value& ref, const std::string& base, const http::CURLSession& ch) { - return lambda<value(list<value>&)>(http::proxy(base + std::string(scdl::name(ref)), ch)); -} - -const list<value> proxies(const list<value>& refs, const std::string& base, const http::CURLSession& ch) { - if (isNil(refs)) - return refs; - return cons(mkproxy(car(refs), base, ch), proxies(cdr(refs), base, ch)); -} - -/** - * Returns the component implementation with the given implementation type and path. - * For now only Scheme and C++ implementations are supported. + * Translate a component request. */ -const cached<failable<ilambda, std::string> > implementation(const std::string& itype, const std::string& path, const list<value>& px) { - if (itype.find(".scheme") != std::string::npos) - return latest(scm::readImplementation(path, px)); - if (itype.find(".cpp") != std::string::npos) - return latest(cpp::readImplementation(path, px)); - return cached<failable<ilambda, std::string> >(); +int translate(request_rec *r) { + if (strncmp(r->uri, "/components/", 12) != 0) + return DECLINED; + r->handler = "mod_tuscany_eval"; + return OK; } /** @@ -277,80 +235,137 @@ int handler(request_rec *r) { if(rc != OK) return rc; - // Retrieve the latest component configuration - DirConf& conf = httpd::dirConf<DirConf>(r, &mod_tuscany_eval); - conf.component = latest(conf.component); - const failable<value, std::string> comp(content(conf.component)); - if (!hasContent(comp)) - return HTTP_NOT_FOUND; - - // Retrieve the latest implementation - const value ielement= scdl::implementation(content(comp)); - const std::string path = conf.contributionPath + std::string(scdl::uri(ielement)); - if (path != conf.implementationPath) { - - // Convert component references to configured proxy lambdas - const ServerConf& sconf = httpd::serverConf<ServerConf>(r, &mod_tuscany_eval); - std::ostringstream base; - if (sconf.wiringHost == "") - base << "http://localhost:" << ap_get_server_port(r) << "/references/" << std::string(scdl::name(content(comp))) << "/"; - else - base << "http://" << sconf.wiringHost << "/references/" << std::string(scdl::name(content(comp))) << "/"; - http::CURLSession ch; - const list<value> px(proxies(scdl::references(content(comp)), base.str(), ch)); - - conf.implementation = implementation(elementName(ielement), path, px); - conf.implementationPath = path; - } - else - conf.implementation = latest(conf.implementation); - const failable<ilambda, std::string> impl(content(conf.implementation)); - if (!hasContent(impl)) + // Get the component implementation lambda + DirConf& dc = httpd::dirConf<DirConf>(r, &mod_tuscany_eval); + const list<value> path(httpd::path(r->uri)); + const list<value> impl(assoctree<value>(cadr(path), dc.implementations)); + if (isNil(impl)) return HTTP_NOT_FOUND; // Handle HTTP method + const lambda<value(const list<value>&)> l(cadr<value>(impl)); if (r->header_only) return OK; if(r->method_number == M_GET) - return httpd::reportStatus(get(r, content(impl))); + return httpd::reportStatus(get(r, l)); if(r->method_number == M_POST) - return httpd::reportStatus(post(r, content(impl))); + return httpd::reportStatus(post(r, l)); if(r->method_number == M_PUT) - return httpd::reportStatus(put(r, content(impl))); + return httpd::reportStatus(put(r, l)); if(r->method_number == M_DELETE) - return httpd::reportStatus(del(r, content(impl))); + return httpd::reportStatus(del(r, l)); return HTTP_NOT_IMPLEMENTED; } /** - * Configuration commands. + * Convert a list of component references to a list of HTTP proxy lambdas. */ -const char *confHome(cmd_parms *cmd, unused void *dummy, const char *arg) { - ServerConf *c = (ServerConf*)ap_get_module_config(cmd->server->module_config, &mod_tuscany_eval); - c->home = arg; - return NULL; +const value mkproxy(const value& ref, const std::string& base) { + return lambda<value(const list<value>&)>(http::proxy(base + std::string(scdl::name(ref)))); +} + +const list<value> proxies(const list<value>& refs, const std::string& base) { + if (isNil(refs)) + return refs; + return cons(mkproxy(car(refs), base), proxies(cdr(refs), base)); +} + +/** + * Return a configured component implementation. + * For now only Scheme and C++ implementations are supported. + */ +const failable<lambda<value(const list<value>&)>, std::string> readImplementation(const std::string& itype, const std::string& path, const list<value>& px) { + if (itype.find(".scheme") != std::string::npos) + return scm::readImplementation(path, px); + if (itype.find(".cpp") != std::string::npos) + return cpp::readImplementation(path, px); + return mkfailure<lambda<value(const list<value>&)>, std::string>("Unsupported implementation type: " + itype); +} + +const value confImplementation(DirConf& dc, ServerConf& sc, server_rec& server, const value& comp) { + const value impl = scdl::implementation(comp); + const std::string path = dc.contributionPath + std::string(scdl::uri(impl)); + + // Convert component references to configured proxy lambdas + std::ostringstream base; + if (sc.wiringServerName == "") + base << (server.server_scheme == NULL? "http" : server.server_scheme) + << "://" << (server.server_hostname == NULL? "localhost" : server.server_hostname) + << ":" << (server.port == 0? 80 : server.port) + << "/references/" << std::string(scdl::name(comp)) << "/"; + else + base << sc.wiringServerName << "/references/" << std::string(scdl::name(comp)) << "/"; + const list<value> px(proxies(scdl::references(comp), base.str())); + + // Read and configure the implementation + const failable<lambda<value(const list<value>&)>, std::string> cimpl(readImplementation(elementName(impl), path, px)); + if (!hasContent(cimpl)) + return reason(cimpl); + return content(cimpl); +} + +/** + * Return a tree of component-name + configured-implementation pairs. + */ +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))); +} + +const list<value> componentToImplementationTree(DirConf& dc, ServerConf& sc, server_rec& server, const list<value>& c) { + return mkbtree(sort(componentToImplementationAssoc(dc, sc, server, c))); +} + +/** + * Read the components declared in a composite. + */ +const failable<list<value>, std::string> readComponents(const std::string& path) { + std::ifstream is(path); + if (is.fail() || is.bad()) + return mkfailure<list<value>, std::string>("Could not read composite: " + path); + return scdl::components(readXML(streamList(is))); } -const char *confWiringHost(cmd_parms *cmd, unused void *dummy, const char *arg) { - ServerConf *c = (ServerConf*)ap_get_module_config(cmd->server->module_config, &mod_tuscany_eval); - c->wiringHost = arg; + +/** + * Configure the components declared in the deployed composite. + */ +const bool confComponents(DirConf& dc, ServerConf& sc, server_rec& server) { + if (dc.contributionPath == "" || dc.compositeName == "") + return true; + const failable<list<value>, std::string> comps = readComponents(dc.contributionPath + dc.compositeName); + if (!hasContent(comps)) + return true; + dc.implementations = componentToImplementationTree(dc, sc, server, content(comps)); + debug(dc.implementations, "modeval::confComponents::implementations"); + return true; +} + +/** + * Configuration commands. + */ +const char *confHome(cmd_parms *cmd, unused void *c, const char *arg) { + ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_eval); + sc.home = arg; return NULL; } -const char *confContribution(unused cmd_parms *cmd, void *c, const char *arg) { - DirConf* conf = (DirConf*)c; - conf->contributionPath = arg; - conf->component = component(conf); +const char *confWiringServerName(cmd_parms *cmd, unused void *c, const char *arg) { + ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_eval); + sc.wiringServerName = arg; return NULL; } -const char *confComposite(unused cmd_parms *cmd, void *c, const char *arg) { - DirConf* conf = (DirConf*)c; - conf->compositeName = arg; - conf->component = component(conf); +const char *confContribution(cmd_parms *cmd, void *c, const char *arg) { + ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_eval); + DirConf& dc = *(DirConf*)c; + dc.contributionPath = arg; + confComponents(dc, sc, *cmd->server); return NULL; } -const char *confComponent(unused cmd_parms *cmd, void *c, const char *arg) { - DirConf* conf = (DirConf*)c; - conf->componentName = arg; - conf->component = component(conf); +const char *confComposite(cmd_parms *cmd, void *c, const char *arg) { + ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_eval); + DirConf& dc = *(DirConf*)c; + dc.compositeName = arg; + confComponents(dc, sc, *cmd->server); return NULL; } @@ -359,19 +374,18 @@ const char *confComponent(unused cmd_parms *cmd, void *c, const char *arg) { */ const command_rec commands[] = { AP_INIT_TAKE1("TuscanyHome", (const char*(*)())confHome, NULL, RSRC_CONF, "Tuscany home directory"), - AP_INIT_TAKE1("SCAWiringHost", (const char*(*)())confWiringHost, NULL, RSRC_CONF, "SCA wiring host"), + AP_INIT_TAKE1("SCAWiringServerName", (const char*(*)())confWiringServerName, NULL, RSRC_CONF, "SCA wiring server name"), AP_INIT_TAKE1("SCAContribution", (const char*(*)())confContribution, NULL, ACCESS_CONF, "SCA contribution location"), AP_INIT_TAKE1("SCAComposite", (const char*(*)())confComposite, NULL, ACCESS_CONF, "SCA composite location"), - AP_INIT_TAKE1("SCAComponent", (const char*(*)())confComponent, NULL, ACCESS_CONF, "SCA component name"), {NULL, NULL, NULL, 0, NO_ARGS, NULL} }; int postConfig(unused apr_pool_t *p, unused apr_pool_t *plog, unused apr_pool_t *ptemp, unused server_rec *s) { - return OK; + return OK; } void childInit(unused apr_pool_t* p, server_rec* svr_rec) { - ServerConf *c = (ServerConf*)ap_get_module_config(svr_rec->module_config, &mod_tuscany_eval); + ServerConf* c = (ServerConf*)ap_get_module_config(svr_rec->module_config, &mod_tuscany_eval); if(c == NULL) { std::cerr << "[Tuscany] Due to one or more errors mod_tuscany_eval loading failed. Causing apache to stop loading." << std::endl; exit(APEXIT_CHILDFATAL); @@ -382,6 +396,7 @@ void registerHooks(unused apr_pool_t *p) { ap_hook_post_config(postConfig, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_child_init(childInit, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_handler(handler, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_translate_name(translate, NULL, NULL, APR_HOOK_FIRST); } } diff --git a/sca-cpp/trunk/modules/server/mod-eval.hpp b/sca-cpp/trunk/modules/server/mod-eval.hpp deleted file mode 100644 index a350538956..0000000000 --- a/sca-cpp/trunk/modules/server/mod-eval.hpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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_modeval_hpp -#define tuscany_modeval_hpp - -/** - * Defines the signature of component implementation lambdas - * expected by mod-eval. - */ - -#include <string> - -#include "function.hpp" -#include "list.hpp" -#include "value.hpp" -#include "monad.hpp" - -namespace tuscany { -namespace server { -namespace modeval { - -/** - * Represents a component implementation lambda function. - */ -typedef lambda<failable<value, std::string>(value, list<value>)> ilambda; - -} -} -} - -#endif /* tuscany_modeval_hpp */ diff --git a/sca-cpp/trunk/modules/server/mod-scm.hpp b/sca-cpp/trunk/modules/server/mod-scm.hpp index 586b90190f..c454c6a216 100644 --- a/sca-cpp/trunk/modules/server/mod-scm.hpp +++ b/sca-cpp/trunk/modules/server/mod-scm.hpp @@ -36,11 +36,9 @@ #include "value.hpp" #include "debug.hpp" #include "monad.hpp" -#include "cache.hpp" #include "../eval/primitive.hpp" #include "../eval/driver.hpp" #include "../http/httpd.hpp" -#include "mod-eval.hpp" namespace tuscany { namespace server { @@ -64,36 +62,30 @@ struct evalImplementation { const list<value> px; evalImplementation(const value& impl, const list<value>& px) : impl(impl), px(eval::quotedParameters(primitiveProcedures(px))) { } - const failable<value, std::string> operator()(const value& func, const list<value>& params) const { - const value expr = cons<value>(func, append(eval::quotedParameters(params), px)); + const value operator()(const list<value>& params) const { + const value expr = cons<value>(car(params), append(eval::quotedParameters(cdr(params)), px)); debug(expr, "modeval::scm::evalImplementation::input"); gc_pool pool; eval::Env globalEnv = eval::setupEnvironment(pool); const value val = eval::evalScript(expr, impl, globalEnv, pool); debug(val, "modeval::scm::evalImplementation::result"); if (isNil(val)) - return mkfailure<value, std::string>("Could not evaluate expression"); - return val; + return mklist<value>(value(), std::string("Could not evaluate expression")); + return mklist<value>(val); } }; /** * Read a script component implementation. */ -const failable<ilambda, std::string> readLatestImplementation(const std::string path, const list<value>& px) { +const failable<lambda<value(const list<value>&)>, std::string> readImplementation(const std::string path, const list<value>& px) { std::ifstream is(path.c_str(), std::ios_base::in); if (is.fail() || is.bad()) - return mkfailure<ilambda, std::string>("Could not read implementation: " + path); + return mkfailure<lambda<value(const list<value>&)>, std::string>("Could not read implementation: " + path); const value impl = eval::readScript(is); if (isNil(impl)) - return mkfailure<ilambda, std::string>("Could not read implementation: " + path); - return ilambda(evalImplementation(impl, px)); -} - -const cached<failable<ilambda, std::string> > readImplementation(const std::string& path, const list<value>& px) { - const lambda<failable<ilambda, std::string>(std::string, list<value>)> ri(readLatestImplementation); - const lambda<unsigned long(std::string)> ft(latestFileTime); - return cached<failable<ilambda, std::string> >(curry(ri, path, px), curry(ft, path)); + return mkfailure<lambda<value(const list<value>&)>, std::string>("Could not read implementation: " + path); + return lambda<value(const list<value>&)>(evalImplementation(impl, px)); } } diff --git a/sca-cpp/trunk/modules/server/mod-wiring.cpp b/sca-cpp/trunk/modules/server/mod-wiring.cpp index 0d5262d730..1bb5d1a687 100644 --- a/sca-cpp/trunk/modules/server/mod-wiring.cpp +++ b/sca-cpp/trunk/modules/server/mod-wiring.cpp @@ -20,7 +20,8 @@ /* $Rev$ $Date$ */ /** - * HTTPD module used to wire component references. + * HTTPD module used to wire component references and route requests to + * target service components. */ #include <sys/stat.h> @@ -32,10 +33,10 @@ #include "list.hpp" #include "slist.hpp" +#include "tree.hpp" #include "value.hpp" #include "debug.hpp" #include "monad.hpp" -#include "cache.hpp" #include "../scdl/scdl.hpp" #include "../http/httpd.hpp" @@ -52,11 +53,11 @@ namespace modwiring { */ class ServerConf { public: - ServerConf(server_rec* s) : s(s), home(""), wiringHost("") { + ServerConf(server_rec* s) : s(s), home(""), wiringServerName("") { } const server_rec* s; std::string home; - std::string wiringHost; + std::string wiringServerName; }; /** @@ -74,27 +75,11 @@ public: const char* dirspec; std::string contributionPath; std::string compositeName; - cached<failable<list<value>, std::string> > components; + list<value> references; + list<value> services; }; /** - * Read the SCDL configuration of the deployed components. - */ -const failable<list<value>, std::string> readComponents(const std::string& path) { - std::ifstream is(path); - if (is.fail() || is.bad()) - return mkfailure<list<value>, std::string>("Could not read composite: " + path); - return scdl::components(readXML(streamList(is))); -} - -const cached<failable<list<value>, std::string> > components(DirConf* conf) { - const std::string path(conf->contributionPath + conf->compositeName); - const lambda<failable<list<value>, std::string>(std::string)> rc(readComponents); - const lambda<unsigned long(std::string)> ft(latestFileTime); - return cached<failable<list<value>, std::string> >(curry(rc, path), curry(ft, path)); -} - -/** * Returns true if a URI is absolute. */ const bool isAbsolute(const std::string& uri) { @@ -102,34 +87,29 @@ const bool isAbsolute(const std::string& uri) { } /** - * Translate an HTTP request URI. Wire a URI in the form /references/component-name/reference-name - * to the target of the reference. + * Route a /references/component-name/reference-name request, + * to the target of the component reference. */ -int translate(request_rec *r) { - if (strncmp(r->uri, "/references/", 12) != 0) - return DECLINED; - httpdDebugRequest(r, "modwiring::translate::input"); - debug(r->uri, "modwiring::translate::uri"); +int translateReference(request_rec *r) { + httpdDebugRequest(r, "modwiring::translateReference::input"); + debug(r->uri, "modwiring::translateReference::uri"); - // Find the requested component, reference and its target configuration - DirConf& conf = httpd::dirConf<DirConf>(r, &mod_tuscany_wiring); - conf.components = latest(conf.components); - const failable<list<value>, std::string> comps(content(conf.components)); - if (!hasContent(comps)) - return HTTP_INTERNAL_SERVER_ERROR; + // Find the requested component + DirConf& dc = httpd::dirConf<DirConf>(r, &mod_tuscany_wiring); const list<value> rpath(httpd::path(r->uri)); - const value comp(scdl::named(cadr(rpath), list<value>(content(comps)))); + const list<value> comp(assoctree(cadr(rpath), dc.references)); if (isNil(comp)) return HTTP_NOT_FOUND; - const value ref(scdl::named(caddr(rpath), scdl::references(comp))); + + // Find the requested reference and target configuration + const list<value> ref(assoctree<value>(caddr(rpath), cadr(comp))); if (isNil(ref)) return HTTP_NOT_FOUND; - const std::string target(scdl::target(ref)); + const std::string target(cadr(ref)); + debug(target, "modwiring::translateReference::target"); - // Absolute target URI + // Route to an absolute target URI using mod_proxy or an HTTP client redirect if (isAbsolute(target)) { - - // Wire using mod_proxy if (useModProxy) { r->filename = apr_pstrdup(r->pool, std::string("proxy:" + target).c_str()); r->proxyreq = PROXYREQ_REVERSE; @@ -137,21 +117,85 @@ int translate(request_rec *r) { return OK; } - // Wire using an HTTP client redirect r->status = HTTP_MOVED_TEMPORARILY; apr_table_setn(r->headers_out, "Location", apr_pstrdup(r->pool, target.c_str())); r->handler = "mod_tuscany_wiring"; return OK; - } - // Local internal redirect - r->filename = apr_pstrdup(r->pool, std::string("/redirect:/" + target).c_str()); + // Route to a relative target URI using a local internal redirect + r->filename = apr_pstrdup(r->pool, std::string("/redirect:/components/" + target).c_str()); r->handler = "mod_tuscany_wiring"; return OK; } /** + * Find a leaf matching a request path in a tree of URI paths. + */ +const int matchPath(const list<value>& k, const list<value>& p) { + if (isNil(p)) + return true; + if (isNil(k)) + return false; + if (car(k) != car(p)) + return false; + return matchPath(cdr(k), cdr(p)); +} + +const list<value> assocPath(const value& k, const list<value>& tree) { + if (isNil(tree)) + return tree; + if (matchPath(k, car<value>(car(tree)))) + return car(tree); + if (k < car<value>(car(tree))) + return assocPath(k, cadr(tree)); + return assocPath(k, caddr(tree)); +} + +/** + * Route a service request to the component providing the requested service. + */ +int translateService(request_rec *r) { + httpdDebugRequest(r, "modwiring::translateService::input"); + debug(r->uri, "modwiring::translateService::uri"); + + // Find the requested component + DirConf& dc = httpd::dirConf<DirConf>(r, &mod_tuscany_wiring); + const list<value> path(httpd::path(r->uri)); + const list<value> svc(assocPath(path, dc.services)); + if (isNil(svc)) + return DECLINED; + debug(svc, "modwiring::translateService::service"); + + // Build a component-name + path-info URI + const list<value> target(cons<value>(cadr(svc), httpd::pathInfo(path, car(svc)))); + debug(target, "modwiring::translateService::target"); + + // Dispatch to the target component using a local internal redirect + const std::string redir(std::string("/redirect:/components") + httpd::path(target)); + debug(redir, "modwiring::translateService::redirect"); + r->filename = apr_pstrdup(r->pool, redir.c_str()); + r->handler = "mod_tuscany_wiring"; + return OK; +} + +/** + * Translate an HTTP service or reference request and route it + * to the target component. + */ +int translate(request_rec *r) { + if (!strncmp(r->uri, "/components/", 12) != 0) + return DECLINED; + + // Translate a component reference request + if (!strncmp(r->uri, "/references/", 12) != 0) + return translateReference(r); + + // Translate a service request + return translateService(r); +} + +/** * Construct a redirect URI. */ const std::string redirect(const std::string& file, const std::string& pi) { @@ -163,7 +207,7 @@ const std::string redirect(const std::string& file, const std::string& pi, const } /** - * HTTP request internal redirect handler. + * HTTP request handler, redirect to a target component. */ int handler(request_rec *r) { if(strcmp(r->handler, "mod_tuscany_wiring")) @@ -175,6 +219,7 @@ int handler(request_rec *r) { return DECLINED; debug(r->uri, "modwiring::handler::uri"); debug(r->filename, "modwiring::handler::filename"); + debug(r->path_info, "modwiring::handler::path info"); if (r->args == NULL) { ap_internal_redirect(apr_pstrdup(r->pool, redirect(r->filename + 10, r->path_info).c_str()), r); @@ -185,28 +230,109 @@ int handler(request_rec *r) { } /** + * Read the components declared in a composite. + */ +const failable<list<value>, std::string> readComponents(const std::string& path) { + std::ifstream is(path); + if (is.fail() || is.bad()) + return mkfailure<list<value>, std::string>("Could not read composite: " + path); + return scdl::components(readXML(streamList(is))); +} + +/** + * Return a tree of component-name + references pairs. The references are + * arranged in trees of reference-name + reference-target pairs. + */ +const list<value> componentReferenceToTargetTree(const value& c) { + return mklist<value>(scdl::name(c), mkbtree(sort(scdl::referenceToTargetAssoc(scdl::references(c))))); +} + +const list<value> componentReferenceToTargetAssoc(const list<value>& c) { + if (isNil(c)) + return c; + return cons<value>(componentReferenceToTargetTree(car(c)), componentReferenceToTargetAssoc(cdr(c))); +} + +const list<value> componentReferenceToTargetTree(const list<value>& c) { + return mkbtree(sort(componentReferenceToTargetAssoc(c))); +} + +/** + * Return a tree of service-URI-path + component-name pairs. Service-URI-paths are + * represented as lists of URI path fragments. + */ +const list<value> defaultBindingURI(const std::string& cn, const std::string& sn) { + return mklist<value>(cn, sn); +} + +const list<value> bindingToComponentAssoc(const std::string& cn, const std::string& sn, const list<value>& b) { + if (isNil(b)) + return b; + const value uri(scdl::uri(car(b))); + if (isNil(uri)) + return cons<value>(mklist<value>(defaultBindingURI(cn, sn), cn), bindingToComponentAssoc(cn, sn, cdr(b))); + return cons<value>(mklist<value>(httpd::path(std::string(uri).c_str()), cn), bindingToComponentAssoc(cn, sn, cdr(b))); +} + +const list<value> serviceToComponentAssoc(const std::string& cn, const list<value>& s) { + if (isNil(s)) + return s; + const std::string sn(scdl::name(car(s))); + const list<value> btoc(bindingToComponentAssoc(cn, sn, scdl::bindings(car(s)))); + if (isNil(btoc)) + return cons<value>(mklist<value>(defaultBindingURI(cn, sn), cn), serviceToComponentAssoc(cn, cdr(s))); + return append<value>(btoc, serviceToComponentAssoc(cn, cdr(s))); +} + +const list<value> uriToComponentAssoc(const list<value>& c) { + if (isNil(c)) + return c; + return append<value>(serviceToComponentAssoc(scdl::name(car(c)), scdl::services(car(c))), uriToComponentAssoc(cdr(c))); +} + +const list<value> uriToComponentTree(const list<value>& c) { + return mkbtree(sort(uriToComponentAssoc(c))); +} + +/** + * Configure the components declared in the server's deployment composite. + */ +const bool confComponents(DirConf& dc) { + if (dc.contributionPath == "" || dc.compositeName == "") + return true; + const failable<list<value>, std::string> comps = readComponents(dc.contributionPath + dc.compositeName); + if (!hasContent(comps)) + return true; + dc.references = componentReferenceToTargetTree(content(comps)); + debug(dc.references, "modwiring::confComponents::references"); + dc.services = uriToComponentTree(content(comps)); + debug(dc.services, "modwiring::confComponents::services"); + return true; +} + +/** * Configuration commands. */ -const char *confHome(cmd_parms *cmd, unused void *dummy, const char *arg) { - ServerConf *c = (ServerConf*)ap_get_module_config(cmd->server->module_config, &mod_tuscany_wiring); - c->home = arg; +const char *confHome(cmd_parms *cmd, unused void *c, const char *arg) { + ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_wiring); + sc.home = arg; return NULL; } -const char *confWiringHost(cmd_parms *cmd, unused void *dummy, const char *arg) { - ServerConf *c = (ServerConf*)ap_get_module_config(cmd->server->module_config, &mod_tuscany_wiring); - c->wiringHost = arg; +const char *confWiringServerName(cmd_parms *cmd, unused void *c, const char *arg) { + ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_wiring); + sc.wiringServerName = arg; return NULL; } const char *confContribution(unused cmd_parms *cmd, void *c, const char *arg) { - DirConf* conf = (DirConf*)c; - conf->contributionPath = arg; - conf->components = components(conf); + DirConf& dc = *(DirConf*)c; + dc.contributionPath = arg; + confComponents(dc); return NULL; } const char *confComposite(unused cmd_parms *cmd, void *c, const char *arg) { - DirConf* conf = (DirConf*)c; - conf->compositeName = arg; - conf->components = components(conf); + DirConf& dc = *(DirConf*)c; + dc.compositeName = arg; + confComponents(dc); return NULL; } @@ -215,7 +341,7 @@ const char *confComposite(unused cmd_parms *cmd, void *c, const char *arg) { */ const command_rec commands[] = { AP_INIT_TAKE1("TuscanyHome", (const char*(*)())confHome, NULL, RSRC_CONF, "Tuscany home directory"), - AP_INIT_TAKE1("SCAWiringHost", (const char*(*)())confWiringHost, NULL, RSRC_CONF, "SCA wiring host"), + AP_INIT_TAKE1("SCAWiringServerName", (const char*(*)())confWiringServerName, NULL, ACCESS_CONF, "SCA wiring server name"), AP_INIT_TAKE1("SCAContribution", (const char*(*)())confContribution, NULL, ACCESS_CONF, "SCA contribution location"), AP_INIT_TAKE1("SCAComposite", (const char*(*)())confComposite, NULL, ACCESS_CONF, "SCA composite location"), {NULL, NULL, NULL, 0, NO_ARGS, NULL} diff --git a/sca-cpp/trunk/modules/server/server-test b/sca-cpp/trunk/modules/server/server-test index 9c517f38b6..4c90711a30 100755 --- a/sca-cpp/trunk/modules/server/server-test +++ b/sca-cpp/trunk/modules/server/server-test @@ -22,23 +22,14 @@ ./server-conf tmp cat >>tmp/conf/httpd.conf <<EOF -<Location /test> -SetHandler mod_tuscany_eval +<Location /> SCAContribution `pwd`/ SCAComposite domain-test.composite -SCAComponent server-test -</Location> - -<Location /cpp> -SetHandler mod_tuscany_eval -SCAContribution `pwd`/ -SCAComposite domain-test.composite -SCAComponent cpp-test </Location> EOF apachectl -k start -d `pwd`/tmp -sleep 1 +sleep 2 # Test ./client-test 2>/dev/null @@ -46,5 +37,5 @@ rc=$? # Cleanup apachectl -k stop -d `pwd`/tmp -sleep 1 +sleep 2 return $rc diff --git a/sca-cpp/trunk/modules/server/wiring-test b/sca-cpp/trunk/modules/server/wiring-test index 5f77d4c6f8..5b3a678f7f 100755 --- a/sca-cpp/trunk/modules/server/wiring-test +++ b/sca-cpp/trunk/modules/server/wiring-test @@ -24,29 +24,14 @@ echo "Testing..." ./server-conf tmp cat >>tmp/conf/httpd.conf <<EOF -<Location /test> -SetHandler mod_tuscany_eval -SCAContribution `pwd`/ -SCAComposite domain-test.composite -SCAComponent server-test -</Location> - -<Location /client> -SetHandler mod_tuscany_eval -SCAContribution `pwd`/ -SCAComposite domain-test.composite -SCAComponent client-test -</Location> - -<Location /references> -SetHandler mod_tuscany_wiring +<Location /> SCAContribution `pwd`/ SCAComposite domain-test.composite </Location> EOF apachectl -k start -d `pwd`/tmp -sleep 1 +sleep 2 # Test HTTP GET curl http://localhost:8090/index.html 2>/dev/null >tmp/index.html @@ -86,7 +71,7 @@ fi # Cleanup apachectl -k stop -d `pwd`/tmp -sleep 1 +sleep 2 if [ "$rc" = "0" ]; then echo "OK" fi diff --git a/sca-cpp/trunk/test/store-script/htdocs/store.html b/sca-cpp/trunk/test/store-script/htdocs/store.html index 0378b454cc..f8c6027abe 100644 --- a/sca-cpp/trunk/test/store-script/htdocs/store.html +++ b/sca-cpp/trunk/test/store-script/htdocs/store.html @@ -162,7 +162,7 @@ <br>
<input type="button" onClick="checkoutCart()" value="Checkout">
<input type="button" onClick="deleteCart()" value="Empty">
- <a href="../ShoppingCart/">(feed)</a>
+ <a href="../shoppingCart/">(feed)</a>
</form>
</div>
</body>
diff --git a/sca-cpp/trunk/test/store-script/htdocs/store.js b/sca-cpp/trunk/test/store-script/htdocs/store.js index 9cb09f4b78..9cd8eb526d 100644 --- a/sca-cpp/trunk/test/store-script/htdocs/store.js +++ b/sca-cpp/trunk/test/store-script/htdocs/store.js @@ -650,9 +650,9 @@ 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"); -tuscany.sca.referenceMap.shoppingTotal = new JSONRpcClient("/Total").Service; +tuscany.sca.referenceMap.catalog = new JSONRpcClient("/catalog").Service; +tuscany.sca.referenceMap.shoppingCart = new AtomClient("/shoppingCart"); +tuscany.sca.referenceMap.shoppingTotal = new JSONRpcClient("/total").Service; tuscany.sca.Reference = function (name) { return tuscany.sca.referenceMap[name]; } diff --git a/sca-cpp/trunk/test/store-script/shopping-cart.scm b/sca-cpp/trunk/test/store-script/shopping-cart.scm index 01ca62df40..b7672345d7 100644 --- a/sca-cpp/trunk/test/store-script/shopping-cart.scm +++ b/sca-cpp/trunk/test/store-script/shopping-cart.scm @@ -14,21 +14,29 @@ ; Post a new item to the cart, create a new cart if necessary (define (post item cache) (define id (uuid)) - (define cart (cons item (getcart cartId cache))) + (define newItem (list (car item) id (caddr item))) + (define cart (cons newItem (getcart cartId cache))) (cache "put" cartId cart) id ) ; Return the content of the cart (define (getall cache) - (define cart (getcart cartId cache)) - (cons "Your Cart" (cons cartId cart)) + (cons "Your Cart" (cons cartId (getcart cartId cache))) +) + +; Find an item in the cart +(define (find id cart) + (if (nul cart) + (cons "Item" (list "0" (list))) + (if (= id (cadr (car cart))) + (car cart) + (find id (cdr cart)))) ) ; Get an item from the cart (define (get id cache) - (define entry (list (list 'name "Apple") (list 'currencyCode "USD") (list 'currencySymbol "$") (list 'price 2.99))) - (cons "Item" (list id entry)) + (find id (getcart cartId cache)) ) ; Delete the cart @@ -38,12 +46,14 @@ ; Return the price of an item (define (price item) - (car (cdr (car (cdr (cdr (cdr (cdr (car (cdr (cdr item)))))))))) + (cadr (assoc 'price (caddr item))) ) ; Sum the prices of a list of items (define (sum items) - (if (nul items) 0 (+ (price (car items)) (sum (cdr items)))) + (if (nul items) + 0 + (+ (price (car items)) (sum (cdr items)))) ) ; Return the total price of the items in the cart diff --git a/sca-cpp/trunk/test/store-script/store-composite-test b/sca-cpp/trunk/test/store-script/store-composite-test index 43923fca36..b41c4e5393 100755 --- a/sca-cpp/trunk/test/store-script/store-composite-test +++ b/sca-cpp/trunk/test/store-script/store-composite-test @@ -24,43 +24,7 @@ echo "Testing..." ../../modules/server/server-conf tmp cat >>tmp/conf/httpd.conf <<EOF -<Location /Catalog> -SetHandler mod_tuscany_eval -SCAContribution `pwd`/ -SCAComposite store.composite -SCAComponent Catalog -</Location> - -<Location /Total> -SetHandler mod_tuscany_eval -SCAContribution `pwd`/ -SCAComposite store.composite -SCAComponent ShoppingCart -</Location> - -<Location /ShoppingCart> -SetHandler mod_tuscany_eval -SCAContribution `pwd`/ -SCAComposite store.composite -SCAComponent ShoppingCart -</Location> - -<Location /CurrencyConverter> -SetHandler mod_tuscany_eval -SCAContribution `pwd`/ -SCAComposite store.composite -SCAComponent CurrencyConverter -</Location> - -<Location /Cache> -SetHandler mod_tuscany_eval -SCAContribution `pwd`/ -SCAComposite store.composite -SCAComponent Cache -</Location> - -<Location /references> -SetHandler mod_tuscany_wiring +<Location /> SCAContribution `pwd`/ SCAComposite store.composite </Location> @@ -70,7 +34,7 @@ apachectl -k start -d `pwd`/tmp mc="memcached -l 127.0.0.1 -m 4 -p 11211" $mc & -sleep 1 +sleep 2 # Test HTTP GET curl http://localhost:8090/store.html 2>/dev/null >tmp/store.html @@ -80,7 +44,7 @@ rc=$? # Cleanup apachectl -k stop -d `pwd`/tmp kill `ps -f | grep -v grep | grep "$mc" | awk '{ print $2 }'` -sleep 1 +sleep 2 if [ "$rc" = "0" ]; then echo "OK" fi diff --git a/sca-cpp/trunk/test/store-script/store.composite b/sca-cpp/trunk/test/store-script/store.composite index 2cfadf3f71..cc00ae2d65 100644 --- a/sca-cpp/trunk/test/store-script/store.composite +++ b/sca-cpp/trunk/test/store-script/store.composite @@ -25,26 +25,19 @@ <component name="Store"> <!-- <t:implementation.widget location="store.html"/> --> <t:implementation.scheme uri="store.scm"/> - <service name="Widget"> <t:binding.http uri="store"/> </service> - <reference name="catalog" target="Catalog"> - <t:binding.jsonrpc uri="Catalog"/> - </reference> - <reference name="shoppingCart" target="ShoppingCart/Cart"> - <t:binding.atom/> - </reference> - <reference name="shoppingTotal" target="ShoppingCart/Total"> - <t:binding.jsonrpc/> - </reference> + <reference name="catalog" target="Catalog"/> + <reference name="shoppingCart" target="ShoppingCart/Cart"/> + <reference name="shoppingTotal" target="ShoppingCart/Total"/> </component> <component name="Catalog"> <t:implementation.scheme uri="fruits-catalog.scm"/> <property name="currencyCode">USD</property> <service name="Catalog"> - <t:binding.jsonrpc uri="Catalog"/> + <t:binding.jsonrpc uri="catalog"/> </service> <reference name="currencyConverter" target="CurrencyConverter"/> </component> @@ -52,27 +45,25 @@ <component name="ShoppingCart"> <t:implementation.scheme uri="shopping-cart.scm"/> <service name="ShoppingCart"> - <t:binding.atom uri="ShoppingCart"/> + <t:binding.atom uri="shoppingCart"/> </service> <service name="Total"> - <t:binding.jsonrpc uri="Total"/> + <t:binding.jsonrpc uri="total"/> </service> - <reference name="cache" target="Cache"> - <t:binding.atom/> - </reference> + <reference name="cache" target="Cache"/> </component> <component name="CurrencyConverter"> <t:implementation.scheme uri="currency-converter.scm"/> <service name="CurrencyConverter"> - <t:binding.jsonrpc uri="CurrencyConverter"/> + <t:binding.jsonrpc uri="currencyConverter"/> </service> </component> <component name="Cache"> <t:implementation.cpp uri="../../components/cache/.libs/libmcache"/> <service name="Cache"> - <t:binding.atom uri="Cache"/> + <t:binding.atom uri="cache"/> </service> </component> |