git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@919720 13f79535-47bb-0310-9956-ffa450edef68
583 lines
20 KiB
C++
583 lines
20 KiB
C++
/*
|
|
* 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
|
|
|
|
/**
|
|
* HTTPD module used to eval component implementations.
|
|
*/
|
|
|
|
#include "string.hpp"
|
|
#include "stream.hpp"
|
|
#include "function.hpp"
|
|
#include "list.hpp"
|
|
#include "tree.hpp"
|
|
#include "value.hpp"
|
|
#include "element.hpp"
|
|
#include "monad.hpp"
|
|
#include "../atom/atom.hpp"
|
|
#include "../json/json.hpp"
|
|
#include "../scdl/scdl.hpp"
|
|
#include "../http/curl.hpp"
|
|
#include "../http/httpd.hpp"
|
|
|
|
extern "C" {
|
|
extern module AP_MODULE_DECLARE_DATA mod_tuscany_eval;
|
|
}
|
|
|
|
namespace tuscany {
|
|
namespace server {
|
|
namespace modeval {
|
|
|
|
/**
|
|
* Server configuration.
|
|
*/
|
|
class ServerConf {
|
|
public:
|
|
ServerConf(server_rec* s) : s(s), home(""), wiringServerName(""), contributionPath(""), compositeName("") {
|
|
}
|
|
|
|
const server_rec* s;
|
|
lambda<value(const list<value>&)> lifecycle;
|
|
string home;
|
|
string wiringServerName;
|
|
string contributionPath;
|
|
string compositeName;
|
|
list<value> implementations;
|
|
list<value> implTree;
|
|
};
|
|
|
|
/**
|
|
* Convert a result represented as a content + failure pair to a
|
|
* failable monad.
|
|
*/
|
|
const failable<value> failableResult(const list<value>& v) {
|
|
if (isNil(cdr(v)))
|
|
return car(v);
|
|
return mkfailure<value>(string(cadr(v)));
|
|
}
|
|
|
|
/**
|
|
* Handle an HTTP GET.
|
|
*/
|
|
const failable<int> 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);
|
|
const list<value> ia = assoc(value("id"), args);
|
|
const list<value> ma = assoc(value("method"), args);
|
|
|
|
// Evaluate a JSON-RPC request and return a JSON result
|
|
if (!isNil(ia) && !isNil(ma)) {
|
|
|
|
// Extract the request id, method and params
|
|
const value id = cadr(ia);
|
|
const value func = c_str(json::funcName(string(cadr(ma))));
|
|
|
|
// Apply the requested function
|
|
const failable<value> val = failableResult(impl(cons(func, httpd::queryParams(args))));
|
|
if (!hasContent(val))
|
|
return mkfailure<int>(reason(val));
|
|
|
|
// Return JSON result
|
|
json::JSONContext cx;
|
|
return httpd::writeResult(json::jsonResult(id, content(val), cx), "application/json-rpc", r);
|
|
}
|
|
|
|
// Evaluate the GET expression
|
|
const list<value> path(pathValues(r->uri));
|
|
const failable<value> val = failableResult(impl(cons<value>("get", mklist<value>(cddr(path)))));
|
|
if (!hasContent(val))
|
|
return mkfailure<int>(reason(val));
|
|
const value c = content(val);
|
|
|
|
// Write returned content-type / content-list pair
|
|
if (isList(cadr<value>(c)))
|
|
return httpd::writeResult(convertValues<string>(cadr<value>(c)), car<value>(c), r);
|
|
|
|
// Write returned ATOM feed or entry
|
|
if (isNil(cddr(path)))
|
|
return httpd::writeResult(atom::writeATOMFeed(atom::feedValuesToElements(c)), "application/atom+xml;type=feed", r);
|
|
else
|
|
return httpd::writeResult(atom::writeATOMEntry(atom::entryValuesToElements(c)), "application/atom+xml;type=entry", r);
|
|
}
|
|
|
|
/**
|
|
* Handle an HTTP POST.
|
|
*/
|
|
const failable<int> post(request_rec* r, const lambda<value(const list<value>&)>& impl) {
|
|
debug(r->uri, "modeval::post::url");
|
|
|
|
// Evaluate a JSON-RPC request and return a JSON result
|
|
const string ct = httpd::contentType(r);
|
|
if (contains(ct, "application/json-rpc") || contains(ct, "text/plain")) {
|
|
|
|
// Read the JSON request
|
|
const int rc = httpd::setupReadPolicy(r);
|
|
if(rc != OK)
|
|
return rc;
|
|
const list<string> ls = httpd::read(r);
|
|
debug(ls, "modeval::post::input");
|
|
json::JSONContext cx;
|
|
const list<value> json = elementsToValues(content(json::readJSON(ls, cx)));
|
|
const list<list<value> > args = httpd::postArgs(json);
|
|
|
|
// Extract the request id, method and params
|
|
const value id = cadr(assoc(value("id"), args));
|
|
const value func = c_str(json::funcName(cadr(assoc(value("method"), args))));
|
|
const list<value> params = (list<value>)cadr(assoc(value("params"), args));
|
|
|
|
// Evaluate the request expression
|
|
const failable<value> val = failableResult(impl(cons<value>(func, params)));
|
|
if (!hasContent(val))
|
|
return mkfailure<int>(reason(val));
|
|
|
|
// Return JSON result
|
|
return httpd::writeResult(json::jsonResult(id, content(val), cx), "application/json-rpc", r);
|
|
}
|
|
|
|
// Evaluate an ATOM POST request and return the location of the corresponding created resource
|
|
if (contains(ct, "application/atom+xml")) {
|
|
|
|
// Read the ATOM entry
|
|
const list<value> path(pathValues(r->uri));
|
|
const int rc = httpd::setupReadPolicy(r);
|
|
if(rc != OK)
|
|
return rc;
|
|
const list<string> ls = httpd::read(r);
|
|
debug(ls, "modeval::post::input");
|
|
const value entry = atom::entryValue(content(atom::readATOMEntry(ls)));
|
|
|
|
// Evaluate the POST expression
|
|
const failable<value> val = failableResult(impl(cons<value>("post", mklist<value>(cddr(path), entry))));
|
|
if (!hasContent(val))
|
|
return mkfailure<int>(reason(val));
|
|
|
|
// Return the created resource location
|
|
debug(content(val), "modeval::post::location");
|
|
apr_table_setn(r->headers_out, "Location", apr_pstrdup(r->pool, httpd::url(content(val), r)));
|
|
r->status = HTTP_CREATED;
|
|
return OK;
|
|
}
|
|
|
|
// Unknown content type, wrap the HTTP request struct in a value and pass it to
|
|
// the component implementation function
|
|
const failable<value> val = failableResult(impl(cons<value>("handle", mklist<value>(httpd::requestValue(r)))));
|
|
if (!hasContent(val))
|
|
return mkfailure<int>(reason(val));
|
|
return (int)content(val);
|
|
}
|
|
|
|
/**
|
|
* Handle an HTTP PUT.
|
|
*/
|
|
const failable<int> put(request_rec* r, const lambda<value(const list<value>&)>& impl) {
|
|
debug(r->uri, "modeval::put::url");
|
|
|
|
// Read the ATOM entry
|
|
const list<value> path(pathValues(r->uri));
|
|
const int rc = httpd::setupReadPolicy(r);
|
|
if(rc != OK)
|
|
return rc;
|
|
const list<string> ls = httpd::read(r);
|
|
debug(ls, "modeval::put::input");
|
|
const value entry = atom::entryValue(content(atom::readATOMEntry(ls)));
|
|
|
|
// Evaluate the PUT expression and update the corresponding resource
|
|
const failable<value> val = failableResult(impl(cons<value>("put", mklist<value>(cddr(path), entry))));
|
|
if (!hasContent(val))
|
|
return mkfailure<int>(reason(val));
|
|
if (val == value(false))
|
|
return HTTP_NOT_FOUND;
|
|
return OK;
|
|
}
|
|
|
|
/**
|
|
* Handle an HTTP DELETE.
|
|
*/
|
|
const failable<int> 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> path(pathValues(r->uri));
|
|
const failable<value> val = failableResult(impl(cons<value>("delete", mklist<value>(cddr(path)))));
|
|
if (!hasContent(val))
|
|
return mkfailure<int>(reason(val));
|
|
if (val == value(false))
|
|
return HTTP_NOT_FOUND;
|
|
return OK;
|
|
}
|
|
|
|
/**
|
|
* Translate a component request.
|
|
*/
|
|
int translate(request_rec *r) {
|
|
gc_scoped_pool pool(r->pool);
|
|
if (strncmp(r->uri, "/components/", 12) != 0)
|
|
return DECLINED;
|
|
r->handler = "mod_tuscany_eval";
|
|
return OK;
|
|
}
|
|
|
|
/**
|
|
* HTTP request handler.
|
|
*/
|
|
int handler(request_rec *r) {
|
|
gc_scoped_pool pool(r->pool);
|
|
if(strcmp(r->handler, "mod_tuscany_eval"))
|
|
return DECLINED;
|
|
httpdDebugRequest(r, "modeval::handler::input");
|
|
|
|
// Get the component implementation lambda
|
|
const ServerConf& sc = httpd::serverConf<ServerConf>(r, &mod_tuscany_eval);
|
|
const list<value> path(pathValues(r->uri));
|
|
const list<value> impl(assoctree<value>(cadr(path), sc.implTree));
|
|
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, l));
|
|
if(r->method_number == M_POST)
|
|
return httpd::reportStatus(post(r, l));
|
|
if(r->method_number == M_PUT)
|
|
return httpd::reportStatus(put(r, l));
|
|
if(r->method_number == M_DELETE)
|
|
return httpd::reportStatus(del(r, l));
|
|
return HTTP_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
/**
|
|
* Convert a list of component references to a list of HTTP proxy lambdas.
|
|
*/
|
|
const value mkrefProxy(const value& ref, const string& base) {
|
|
return lambda<value(const list<value>&)>(http::proxy(base + string(scdl::name(ref))));
|
|
}
|
|
|
|
const list<value> refProxies(const list<value>& refs, const string& base) {
|
|
if (isNil(refs))
|
|
return refs;
|
|
return cons(mkrefProxy(car(refs), base), refProxies(cdr(refs), base));
|
|
}
|
|
|
|
/**
|
|
* Convert a list of component properties to a list of lambda functions that just return
|
|
* the property value.
|
|
*/
|
|
struct propProxy {
|
|
const value v;
|
|
propProxy(const value& v) : v(v) {
|
|
}
|
|
const value operator()(unused const list<value>& params) const {
|
|
return v;
|
|
}
|
|
};
|
|
|
|
const value mkpropProxy(const value& prop) {
|
|
return lambda<value(const list<value>&)>(propProxy(elementValue(prop)));
|
|
}
|
|
|
|
const list<value> propProxies(const list<value>& props) {
|
|
if (isNil(props))
|
|
return props;
|
|
return cons(mkpropProxy(car(props)), propProxies(cdr(props)));
|
|
}
|
|
|
|
/**
|
|
* Evaluate a component and convert it to an applicable lambda function.
|
|
*/
|
|
const value evalComponent(ServerConf& sc, server_rec& server, const value& comp) {
|
|
extern const failable<lambda<value(const list<value>&)> > evalImplementation(const string& cpath, const value& impl, const list<value>& px, const lambda<value(const list<value>&)>& lifecycle);
|
|
|
|
const value impl = scdl::implementation(comp);
|
|
|
|
// Convert component references to configured proxy lambdas
|
|
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/" << string(scdl::name(comp)) << "/";
|
|
else
|
|
base << sc.wiringServerName << "/references/" << string(scdl::name(comp)) << "/";
|
|
const list<value> rpx(refProxies(scdl::references(comp), str(base)));
|
|
|
|
// Convert component proxies to configured proxy lambdas
|
|
const list<value> ppx(propProxies(scdl::properties(comp)));
|
|
|
|
// Evaluate the component implementation and convert it to an applicable lambda function
|
|
const failable<lambda<value(const list<value>&)> > cimpl(evalImplementation(sc.contributionPath, impl, append(rpx, ppx), sc.lifecycle));
|
|
if (!hasContent(cimpl))
|
|
return reason(cimpl);
|
|
return content(cimpl);
|
|
}
|
|
|
|
/**
|
|
* Return a list of component-name + configured-implementation pairs.
|
|
*/
|
|
const list<value> componentToImplementationAssoc(ServerConf& sc, server_rec& server, const list<value>& c) {
|
|
if (isNil(c))
|
|
return c;
|
|
return cons<value>(mklist<value>(scdl::name(car(c)), evalComponent(sc, server, car(c))), componentToImplementationAssoc(sc, server, cdr(c)));
|
|
}
|
|
|
|
/**
|
|
* Read the components declared in a composite.
|
|
*/
|
|
const failable<list<value> > readComponents(const string& path) {
|
|
ifstream is(path);
|
|
if (fail(is))
|
|
return mkfailure<list<value> >(string("Could not read composite: ") + path);
|
|
return scdl::components(readXML(streamList(is)));
|
|
}
|
|
|
|
/**
|
|
* Apply a list of component implementations to a start or restart lifecycle expression.
|
|
* Return the functions returned by the component implementations.
|
|
*/
|
|
const failable<list<value> > applyLifecycleExpr(const list<value>& impls, const list<value>& expr) {
|
|
if (isNil(impls))
|
|
return list<value>();
|
|
|
|
// Evaluate lifecycle expression against a component implementation lambda
|
|
const lambda<value(const list<value>&)> l = cadr<value>(car(impls));
|
|
const failable<value> r = failableResult(l(expr));
|
|
if (!hasContent(r))
|
|
return mkfailure<list<value> >(reason(r));
|
|
const lambda<value(const list<value>&)> rl = content(r);
|
|
|
|
// Use the returned lambda function, if any, from now on
|
|
const lambda<value(const list<value>&)> al = isNil(rl)? l : rl;
|
|
|
|
// Continue with the rest of the list
|
|
const failable<list<value> > nr = applyLifecycleExpr(cdr(impls), expr);
|
|
if (!hasContent(nr))
|
|
return nr;
|
|
return cons<value>(mklist<value>(car<value>(car(impls)), value(al)), content(nr));
|
|
}
|
|
|
|
/**
|
|
* Configure the components declared in the deployed composite.
|
|
*/
|
|
const failable<bool> confComponents(ServerConf& sc, server_rec& server) {
|
|
if (sc.contributionPath == "" || sc.compositeName == "")
|
|
return false;
|
|
|
|
// Read the components and get their implementation lambda functions
|
|
const failable<list<value> > comps = readComponents(sc.contributionPath + sc.compositeName);
|
|
if (!hasContent(comps))
|
|
return mkfailure<bool>(reason(comps));
|
|
sc.implementations = componentToImplementationAssoc(sc, server, content(comps));
|
|
debug(sc.implementations, "modeval::confComponents::implementations");
|
|
|
|
// Store the implementation lambda functions in a tree for fast retrieval
|
|
sc.implTree = mkbtree(sort(sc.implementations));
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Start the components declared in the deployed composite.
|
|
*/
|
|
const failable<bool> startComponents(ServerConf& sc) {
|
|
|
|
// Start the components and record the returned implementation lambda functions
|
|
debug(sc.implementations, "modeval::startComponents::start");
|
|
const failable<list<value> > impls = applyLifecycleExpr(sc.implementations, mklist<value>("start"));
|
|
if (!hasContent(impls))
|
|
return mkfailure<bool>(reason(impls));
|
|
sc.implementations = content(impls);
|
|
debug(sc.implementations, "modeval::startComponents::implementations");
|
|
|
|
// Store the implementation lambda functions in a tree for fast retrieval
|
|
sc.implTree = mkbtree(sort(sc.implementations));
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Cleanup callback, called when the server is stopped or restarted.
|
|
*/
|
|
apr_status_t serverCleanup(void* v) {
|
|
gc_pool pool;
|
|
ServerConf& sc = *(ServerConf*)v;
|
|
debug("modeval::serverCleanup");
|
|
|
|
// Stop the component implementations
|
|
applyLifecycleExpr(sc.implementations, mklist<value>("stop"));
|
|
|
|
// Call the module lifecycle function
|
|
if (isNil(sc.lifecycle))
|
|
return APR_SUCCESS;
|
|
debug("modeval::serverCleanup::stop");
|
|
sc.lifecycle(mklist<value>("stop"));
|
|
|
|
return APR_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* Called after all the configuration commands have been run.
|
|
* Process the server configuration and configure the deployed components.
|
|
*/
|
|
int postConfig(apr_pool_t *p, unused apr_pool_t *plog, unused apr_pool_t *ptemp, server_rec *s) {
|
|
extern const value applyLifecycle(const list<value>&);
|
|
|
|
gc_scoped_pool pool(p);
|
|
ServerConf& sc = httpd::serverConf<ServerConf>(s, &mod_tuscany_eval);
|
|
|
|
// Count the calls to post config
|
|
const string k("tuscany::modeval::postConfig");
|
|
const int count = (int)httpd::userData(k, s);
|
|
httpd::putUserData(k, (void*)(count + 1), s);
|
|
|
|
// Count == 0, do nothing as post config is always called twice,
|
|
// count == 1 is the first start, count > 1 is a restart
|
|
if (count == 0)
|
|
return OK;
|
|
if (count == 1) {
|
|
debug("modeval::postConfig::start");
|
|
const failable<value> r = failableResult(applyLifecycle(mklist<value>("start")));
|
|
if (!hasContent(r))
|
|
return -1;
|
|
sc.lifecycle = content(r);
|
|
}
|
|
if (count > 1) {
|
|
debug("modeval::postConfig::restart");
|
|
const failable<value> r = failableResult(applyLifecycle(mklist<value>("restart")));
|
|
if (!hasContent(r))
|
|
return -1;
|
|
sc.lifecycle = content(r);
|
|
}
|
|
|
|
// Configure the deployed components
|
|
debug(sc.wiringServerName, "modeval::postConfig::wiringServerName");
|
|
debug(sc.contributionPath, "modeval::postConfig::contributionPath");
|
|
debug(sc.compositeName, "modeval::postConfig::compositeName");
|
|
const failable<bool> res = confComponents(sc, *s);
|
|
if (!hasContent(res)) {
|
|
cerr << "[Tuscany] Due to one or more errors mod_tuscany_eval loading failed. Causing apache to stop loading." << endl;
|
|
return -1;
|
|
}
|
|
|
|
// Register a cleanup callback, called when the server is stopped or restarted
|
|
apr_pool_pre_cleanup_register(p, (void*)&sc, serverCleanup);
|
|
|
|
return OK;
|
|
}
|
|
|
|
/**
|
|
* Child process initialization.
|
|
*/
|
|
void childInit(apr_pool_t* p, server_rec* s) {
|
|
gc_scoped_pool pool(p);
|
|
ServerConf* sc = (ServerConf*)ap_get_module_config(s->module_config, &mod_tuscany_eval);
|
|
if(sc == NULL) {
|
|
cerr << "[Tuscany] Due to one or more errors mod_tuscany_eval loading failed. Causing apache to stop loading." << endl;
|
|
exit(APEXIT_CHILDFATAL);
|
|
}
|
|
|
|
// Start the components in the child process
|
|
const failable<bool> res = startComponents(*sc);
|
|
if (!hasContent(res)) {
|
|
cerr << "[Tuscany] Due to one or more errors mod_tuscany_eval loading failed. Causing apache to stop loading." << endl;
|
|
exit(APEXIT_CHILDFATAL);
|
|
}
|
|
|
|
// Register a cleanup callback, called when the child is stopped or restarted
|
|
apr_pool_pre_cleanup_register(p, (void*)sc, serverCleanup);
|
|
}
|
|
|
|
/**
|
|
* Configuration commands.
|
|
*/
|
|
const char* confHome(cmd_parms *cmd, unused void *c, const char *arg) {
|
|
gc_scoped_pool pool(cmd->pool);
|
|
ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_eval);
|
|
sc.home = arg;
|
|
return NULL;
|
|
}
|
|
const char* confWiringServerName(cmd_parms *cmd, unused void *c, const char *arg) {
|
|
gc_scoped_pool pool(cmd->pool);
|
|
ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_eval);
|
|
sc.wiringServerName = arg;
|
|
return NULL;
|
|
}
|
|
const char* confContribution(cmd_parms *cmd, unused void *c, const char *arg) {
|
|
gc_scoped_pool pool(cmd->pool);
|
|
ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_eval);
|
|
sc.contributionPath = arg;
|
|
return NULL;
|
|
}
|
|
const char* confComposite(cmd_parms *cmd, unused void *c, const char *arg) {
|
|
gc_scoped_pool pool(cmd->pool);
|
|
ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_eval);
|
|
sc.compositeName = arg;
|
|
return NULL;
|
|
}
|
|
|
|
const char* confEnv(unused cmd_parms *cmd, unused void *c, const char *name, const char *value) {
|
|
gc_scoped_pool pool(cmd->pool);
|
|
setenv(name, value != NULL? value : "", 1);
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* HTTP server module declaration.
|
|
*/
|
|
const command_rec commands[] = {
|
|
AP_INIT_TAKE1("TuscanyHome", (const char*(*)())confHome, NULL, RSRC_CONF, "Tuscany home directory"),
|
|
AP_INIT_TAKE1("SCAWiringServerName", (const char*(*)())confWiringServerName, NULL, RSRC_CONF, "SCA wiring server name"),
|
|
AP_INIT_TAKE1("SCAContribution", (const char*(*)())confContribution, NULL, RSRC_CONF, "SCA contribution location"),
|
|
AP_INIT_TAKE1("SCAComposite", (const char*(*)())confComposite, NULL, RSRC_CONF, "SCA composite location"),
|
|
AP_INIT_TAKE12("SetEnv", (const char*(*)())confEnv, NULL, OR_FILEINFO, "Environment variable name and optional value"),
|
|
{NULL, NULL, NULL, 0, NO_ARGS, NULL}
|
|
};
|
|
|
|
|
|
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);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
extern "C" {
|
|
|
|
module AP_MODULE_DECLARE_DATA mod_tuscany_eval = {
|
|
STANDARD20_MODULE_STUFF,
|
|
// dir config and merger
|
|
NULL, NULL,
|
|
// server config and merger
|
|
tuscany::httpd::makeServerConf<tuscany::server::modeval::ServerConf>, NULL,
|
|
// commands and hooks
|
|
tuscany::server::modeval::commands, tuscany::server::modeval::registerHooks
|
|
};
|
|
|
|
}
|
|
|
|
#endif
|