diff options
Diffstat (limited to '')
-rw-r--r-- | sca-cpp/trunk/modules/server/mod-eval.cpp | 287 |
1 files changed, 151 insertions, 136 deletions
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); } } |