diff options
author | jsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68> | 2009-12-26 03:25:34 +0000 |
---|---|---|
committer | jsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68> | 2009-12-26 03:25:34 +0000 |
commit | 0999fd565d6d629df87d3db38a84d4701b494b3b (patch) | |
tree | 287bb29d011a1c1616ca434ce6c51ab57b63dda2 /sca-cpp/trunk/modules/server | |
parent | bd4c1d47aeaf1d4bca76d5713e705b0869d3f2f7 (diff) |
Simplified server configuration, HTTPD modules now use deployment composite to route service requests, minor fixes to store integration test.
git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@893939 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'sca-cpp/trunk/modules/server')
-rw-r--r-- | sca-cpp/trunk/modules/server/domain-test.composite | 2 | ||||
-rwxr-xr-x | sca-cpp/trunk/modules/server/httpd-test | 8 | ||||
-rw-r--r-- | sca-cpp/trunk/modules/server/impl-test.cpp | 15 | ||||
-rw-r--r-- | sca-cpp/trunk/modules/server/mod-cpp.hpp | 31 | ||||
-rw-r--r-- | sca-cpp/trunk/modules/server/mod-eval.cpp | 287 | ||||
-rw-r--r-- | sca-cpp/trunk/modules/server/mod-eval.hpp | 50 | ||||
-rw-r--r-- | sca-cpp/trunk/modules/server/mod-scm.hpp | 24 | ||||
-rw-r--r-- | sca-cpp/trunk/modules/server/mod-wiring.cpp | 244 | ||||
-rwxr-xr-x | sca-cpp/trunk/modules/server/server-test | 15 | ||||
-rwxr-xr-x | sca-cpp/trunk/modules/server/wiring-test | 21 |
10 files changed, 373 insertions, 324 deletions
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 |