summaryrefslogtreecommitdiffstats
path: root/sca-cpp/trunk/modules/server/mod-eval.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--sca-cpp/trunk/modules/server/mod-eval.cpp287
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);
}
}