summaryrefslogtreecommitdiffstats
path: root/sca-cpp/trunk/modules
diff options
context:
space:
mode:
authorjsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68>2009-11-23 05:25:33 +0000
committerjsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68>2009-11-23 05:25:33 +0000
commit585f81b9436e137c3ed784d9a91efa9e6e792e03 (patch)
treef40f0179601320ace0b454698dc76aaeddfc6a5d /sca-cpp/trunk/modules
parent3c6b7d709c7197078f8261f8e3464b0f217c988e (diff)
Refactored httpd server integration, split http support and server logic in two modules. Added functions to load component implementations packaged as dynamic libraries. Minor monad code cleanup, converted cast operators to separate functions.
git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@883249 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to '')
-rw-r--r--sca-cpp/trunk/modules/atom/atom-test.cpp8
-rw-r--r--sca-cpp/trunk/modules/atom/atom.hpp8
-rw-r--r--sca-cpp/trunk/modules/http/curl-test.cpp161
-rw-r--r--sca-cpp/trunk/modules/http/curl.hpp39
-rwxr-xr-xsca-cpp/trunk/modules/http/http-test12
-rwxr-xr-xsca-cpp/trunk/modules/http/httpd-conf2
-rwxr-xr-xsca-cpp/trunk/modules/http/httpd-test41
-rw-r--r--sca-cpp/trunk/modules/http/httpd.hpp146
-rw-r--r--sca-cpp/trunk/modules/http/mod-eval.cpp532
-rw-r--r--sca-cpp/trunk/modules/json/json-test.cpp20
-rw-r--r--sca-cpp/trunk/modules/json/json.hpp10
-rwxr-xr-xsca-cpp/trunk/modules/scdl/scdl-testbin477277 -> 0 bytes
-rw-r--r--sca-cpp/trunk/modules/server/Makefile.am36
-rw-r--r--sca-cpp/trunk/modules/server/client-test.cpp251
-rw-r--r--sca-cpp/trunk/modules/server/htdocs/entry.xml (renamed from sca-cpp/trunk/modules/http/htdocs/entry.xml)0
-rw-r--r--sca-cpp/trunk/modules/server/htdocs/feed.xml (renamed from sca-cpp/trunk/modules/http/htdocs/feed.xml)0
-rw-r--r--sca-cpp/trunk/modules/server/htdocs/index.html21
-rw-r--r--sca-cpp/trunk/modules/server/htdocs/json-request.txt (renamed from sca-cpp/trunk/modules/http/htdocs/json-request.txt)0
-rw-r--r--sca-cpp/trunk/modules/server/htdocs/json-result.txt (renamed from sca-cpp/trunk/modules/http/htdocs/json-result.txt)0
-rwxr-xr-xsca-cpp/trunk/modules/server/http-test43
-rw-r--r--sca-cpp/trunk/modules/server/httpd-client.scm (renamed from sca-cpp/trunk/modules/http/httpd-client.scm)0
-rwxr-xr-xsca-cpp/trunk/modules/server/httpd-test80
-rw-r--r--sca-cpp/trunk/modules/server/httpd-test.composite (renamed from sca-cpp/trunk/modules/http/httpd-test.composite)0
-rw-r--r--sca-cpp/trunk/modules/server/httpd-test.scm (renamed from sca-cpp/trunk/modules/http/httpd-test.scm)0
-rw-r--r--sca-cpp/trunk/modules/server/mod-cpp.hpp91
-rw-r--r--sca-cpp/trunk/modules/server/mod-eval.cpp387
-rw-r--r--sca-cpp/trunk/modules/server/mod-eval.hpp50
-rw-r--r--sca-cpp/trunk/modules/server/mod-scm.hpp92
-rw-r--r--sca-cpp/trunk/modules/server/mod-wiring.cpp (renamed from sca-cpp/trunk/modules/http/mod-wiring.cpp)83
-rwxr-xr-xsca-cpp/trunk/modules/server/server-conf32
-rwxr-xr-xsca-cpp/trunk/modules/server/wiring-test (renamed from sca-cpp/trunk/modules/http/wiring-test)17
31 files changed, 1315 insertions, 847 deletions
diff --git a/sca-cpp/trunk/modules/atom/atom-test.cpp b/sca-cpp/trunk/modules/atom/atom-test.cpp
index 7c14b954a0..ba651e8eb2 100644
--- a/sca-cpp/trunk/modules/atom/atom-test.cpp
+++ b/sca-cpp/trunk/modules/atom/atom-test.cpp
@@ -82,13 +82,13 @@ bool testEntry() {
assert(os.str() == itemEntry);
}
{
- const list<value> a = readEntry(mklist(itemEntry));
+ const list<value> a = content(readEntry(mklist(itemEntry)));
std::ostringstream os;
writeATOMEntry<std::ostringstream*>(writer, &os, a);
assert(os.str() == itemEntry);
}
{
- const list<value> a = readEntry(mklist(incompleteEntry));
+ const list<value> a = content(readEntry(mklist(incompleteEntry)));
std::ostringstream os;
writeATOMEntry<std::ostringstream*>(writer, &os, a);
assert(os.str() == completedEntry);
@@ -135,7 +135,7 @@ bool testFeed() {
assert(os.str() == emptyFeed);
}
{
- const list<value> a = readFeed(mklist(emptyFeed));
+ const list<value> a = content(readFeed(mklist(emptyFeed)));
std::ostringstream os;
writeATOMFeed<std::ostringstream*>(writer, &os, a);
assert(os.str() == emptyFeed);
@@ -171,7 +171,7 @@ bool testFeed() {
assert(os.str() == itemFeed);
}
{
- const list<value> a = readFeed(mklist(itemFeed));
+ const list<value> a = content(readFeed(mklist(itemFeed)));
std::ostringstream os;
writeATOMFeed<std::ostringstream*>(writer, &os, a);
assert(os.str() == itemFeed);
diff --git a/sca-cpp/trunk/modules/atom/atom.hpp b/sca-cpp/trunk/modules/atom/atom.hpp
index 5054c635a0..ac19b93e38 100644
--- a/sca-cpp/trunk/modules/atom/atom.hpp
+++ b/sca-cpp/trunk/modules/atom/atom.hpp
@@ -113,9 +113,9 @@ template<typename R> const failable<R, std::string> writeATOMEntry(const lambda<
const failable<list<std::string>, std::string> writeATOMEntry(const list<value>& l) {
const failable<list<std::string>, std::string> ls = writeATOMEntry<list<std::string> >(rcons<std::string>, list<std::string>(), l);
- if (!hasValue(ls))
+ if (!hasContent(ls))
return ls;
- return reverse(list<std::string>(ls));
+ return reverse(list<std::string>(content(ls)));
}
/**
@@ -139,9 +139,9 @@ template<typename R> const failable<R, std::string> writeATOMFeed(const lambda<R
*/
const failable<list<std::string>, std::string> writeATOMFeed(const list<value>& l) {
const failable<list<std::string>, std::string> ls = writeATOMFeed<list<std::string> >(rcons<std::string>, list<std::string>(), l);
- if (!hasValue(ls))
+ if (!hasContent(ls))
return ls;
- return reverse(list<std::string>(ls));
+ return reverse(list<std::string>(content(ls)));
}
/**
diff --git a/sca-cpp/trunk/modules/http/curl-test.cpp b/sca-cpp/trunk/modules/http/curl-test.cpp
index 863aa98828..0a6fbcd8a6 100644
--- a/sca-cpp/trunk/modules/http/curl-test.cpp
+++ b/sca-cpp/trunk/modules/http/curl-test.cpp
@@ -53,16 +53,15 @@ const bool testGet() {
CURLHandle ch;
{
std::ostringstream os;
- const failable<list<std::ostringstream*>, std::string> r = get<std::ostringstream*>(curlWriter, &os, "http://localhost:8091", ch);
- assert(hasValue(r));
+ const failable<list<std::ostringstream*>, std::string> r = get<std::ostringstream*>(curlWriter, &os, "http://localhost:8090", ch);
+ assert(hasContent(r));
assert(contains(os.str(), "HTTP/1.1 200 OK"));
assert(contains(os.str(), "It works"));
}
{
- const failable<value, std::string> r = get("http://localhost:8091", ch);
- assert(hasValue(r));
- const value val = r;
- assert(contains(val, "It works"));
+ const failable<value, std::string> r = get("http://localhost:8090", ch);
+ assert(hasContent(r));
+ assert(contains(content(r), "It works"));
}
return true;
}
@@ -70,10 +69,9 @@ const bool testGet() {
const bool testGetLoop(const int count, CURLHandle& ch) {
if (count == 0)
return true;
- const failable<value, std::string> r = get("http://localhost:8091", ch);
- assert(hasValue(r));
- const value val = r;
- assert(contains(val, "It works"));
+ const failable<value, std::string> r = get("http://localhost:8090", ch);
+ assert(hasContent(r));
+ assert(contains(content(r), "It works"));
return testGetLoop(count - 1, ch);
}
@@ -95,142 +93,6 @@ const bool testGetPerf() {
return true;
}
-const bool testEval() {
- CURLHandle ch;
- const value val = evalExpr(mklist<value>(std::string("echo"), std::string("Hello")), "http://localhost:8091/test", ch);
- assert(val == std::string("Hello"));
- return true;
-}
-
-const bool testEvalLoop(const int count, CURLHandle& ch) {
- if (count == 0)
- return true;
- const value val = evalExpr(mklist<value>(std::string("echo"), std::string("Hello")), "http://localhost:8091/test", ch);
- assert(val == std::string("Hello"));
- return testEvalLoop(count - 1, ch);
-}
-
-const value blob(std::string(3000, 'A'));
-const list<value> blobs = mklist(blob, blob, blob, blob, blob);
-
-const bool testBlobEvalLoop(const int count, CURLHandle& ch) {
- if (count == 0)
- return true;
- const value val = evalExpr(mklist<value>(std::string("echo"), blobs), "http://localhost:8091/test", ch);
- assert(val == blobs);
- return testBlobEvalLoop(count - 1, ch);
-}
-
-const bool testEvalPerf() {
- const int count = 50;
- CURLHandle ch;
- struct timeval start;
- struct timeval end;
- {
- testEvalLoop(5, ch);
-
- gettimeofday(&start, NULL);
-
- testEvalLoop(count, ch);
-
- gettimeofday(&end, NULL);
- std::cout << "JSON-RPC eval echo test " << duration(start, end, count) << " ms" << std::endl;
- }
- {
- testBlobEvalLoop(5, ch);
-
- gettimeofday(&start, NULL);
-
- testBlobEvalLoop(count, ch);
-
- gettimeofday(&end, NULL);
- std::cout << "JSON-RPC eval blob test " << duration(start, end, count) << " ms" << std::endl;
- }
- return true;
-}
-
-const bool testFeed() {
- return true;
-}
-
-bool testPost() {
- const list<value> i = list<value>()
- << (list<value>() << "name" << std::string("Apple"))
- << (list<value>() << "price" << std::string("$2.99"));
- const list<value> a = mklist<value>(std::string("item"), std::string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
- CURLHandle ch;
- value rc = post(a, "http://localhost:8091/test", ch);
- assert(rc == value(true));
- return true;
-}
-
-const bool testPostLoop(const int count, const value& val, CURLHandle& ch) {
- if (count == 0)
- return true;
- const value rc = post(val, "http://localhost:8091/test", ch);
- assert(rc == value(true));
- return testPostLoop(count - 1, val, ch);
-}
-
-const bool testPostPerf() {
- const int count = 50;
- CURLHandle ch;
- struct timeval start;
- struct timeval end;
- {
- const list<value> i = list<value>()
- << (list<value>() << "name" << std::string("Apple"))
- << (list<value>() << "price" << std::string("$2.99"));
- const list<value> val = mklist<value>(std::string("item"), std::string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
- testPostLoop(5, val, ch);
-
- gettimeofday(&start, NULL);
-
- testPostLoop(count, val, ch);
-
- gettimeofday(&end, NULL);
- std::cout << "ATOMPub POST small test " << duration(start, end, count) << " ms" << std::endl;
- }
- {
- const list<value> i = list<value>()
- << (list<value>() << "name" << std::string("Apple"))
- << (list<value>() << "blob1" << blob)
- << (list<value>() << "blob2" << blob)
- << (list<value>() << "blob3" << blob)
- << (list<value>() << "blob4" << blob)
- << (list<value>() << "blob5" << blob)
- << (list<value>() << "price" << std::string("$2.99"));
- const list<value> val = mklist<value>(std::string("item"), std::string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
- testPostLoop(5, val, ch);
-
- gettimeofday(&start, NULL);
-
- testPostLoop(count, val, ch);
-
- gettimeofday(&end, NULL);
- std::cout << "ATOMPub POST blob test " << duration(start, end, count) << " ms" << std::endl;
- }
- return true;
-}
-
-const bool testPut() {
- const list<value> i = list<value>()
- << (list<value>() << "name" << std::string("Apple"))
- << (list<value>() << "price" << std::string("$2.99"));
- const list<value> a = mklist<value>(std::string("item"), std::string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
- CURLHandle ch;
- value rc = put(a, "http://localhost:8091/test/111", ch);
- assert(rc == value(true));
- return true;
-}
-
-const bool testDel() {
- CURLHandle ch;
- value rc = del("http://localhost:8091/test/123456789", ch);
- assert(rc == value(true));
- return true;
-}
-
}
}
@@ -239,13 +101,6 @@ int main() {
tuscany::http::testGet();
tuscany::http::testGetPerf();
- tuscany::http::testPost();
- tuscany::http::testPostPerf();
- tuscany::http::testEval();
- tuscany::http::testEvalPerf();
- tuscany::http::testFeed();
- tuscany::http::testPut();
- tuscany::http::testDel();
std::cout << "OK" << std::endl;
diff --git a/sca-cpp/trunk/modules/http/curl.hpp b/sca-cpp/trunk/modules/http/curl.hpp
index 5ee3a090b0..6c3a3a47dc 100644
--- a/sca-cpp/trunk/modules/http/curl.hpp
+++ b/sca-cpp/trunk/modules/http/curl.hpp
@@ -209,29 +209,29 @@ const failable<value, std::string> evalExpr(const value& expr, const std::string
// Convert expression to a JSON-RPC request
json::JSONContext cx;
const failable<list<std::string>, std::string> jsreq = jsonRequest(1, car<value>(expr), cdr<value>(expr), cx);
- if (!hasValue(jsreq))
+ if (!hasContent(jsreq))
return mkfailure<value, std::string>(reason(jsreq));
if (logContent) {
std::cout<< "content: " << std::endl;
- write(jsreq, std::cout);
+ write(content(jsreq), std::cout);
std::cout<< std::endl;
std::cout.flush();
}
// POST it to the URL
const list<std::string> h = mklist<std::string>("Content-Type: application/json-rpc");
- const failable<list<list<std::string> >, std::string> res = apply<list<std::string> >(mklist<list<std::string> >(h, jsreq), rcons<std::string>, list<std::string>(), url, "POST", ch);
- if (!hasValue(res))
+ const failable<list<list<std::string> >, std::string> res = apply<list<std::string> >(mklist<list<std::string> >(h, content(jsreq)), rcons<std::string>, list<std::string>(), url, "POST", ch);
+ if (!hasContent(res))
return mkfailure<value, std::string>(reason(res));
// Return result
if (logContent) {
std::cout << "content:" << std::endl;
- write(cadr<list<std::string> >(res), std::cout);
+ write(cadr<list<std::string> >(content(res)), std::cout);
std::cout << std::endl;
}
- const list<value> val = elementsToValues(json::readJSON(cadr<list<std::string> >(res), cx));
+ const list<value> val = elementsToValues(content(json::readJSON(cadr<list<std::string> >(content(res)), cx)));
return cadr<value>(cadr<value>(val));
}
@@ -250,9 +250,8 @@ const failable<value, std::string> get(const std::string& url, const CURLHandle&
// Get the contents of the resource at the given URL
const failable<list<list<std::string> >, std::string> res = get<list<std::string> >(rcons<std::string>, list<std::string>(), url, ch);
- if (!hasValue(res))
+ if (!hasContent(res))
return mkfailure<value, std::string>(reason(res));
- const list<list<std::string> > ls = res;
const std::string ct;
if (ct.find("application/atom+xml") != std::string::npos) {
@@ -261,7 +260,7 @@ const failable<value, std::string> get(const std::string& url, const CURLHandle&
// Return the content as a string value
std::ostringstream os;
- write(reverse(cadr(ls)), os);
+ write(reverse(cadr(content(res))), os);
return value(os.str());
}
@@ -272,19 +271,19 @@ const failable<value, std::string> post(const value& val, const std::string& url
// Convert value to an ATOM entry
const failable<list<std::string>, std::string> entry = atom::writeATOMEntry(atom::entryValuesToElements(val));
- if (!hasValue(entry))
+ if (!hasContent(entry))
return mkfailure<value, std::string>(reason(entry));
if (logContent) {
std::cout << "content:" << std::endl;
- write(list<std::string>(entry), std::cout);
+ write(list<std::string>(content(entry)), std::cout);
std::cout << std::endl;
}
// POST it to the URL
const list<std::string> h = mklist<std::string>("Content-Type: application/atom+xml");
- const list<list<std::string> > req = mklist<list<std::string> >(h, entry);
+ const list<list<std::string> > req = mklist<list<std::string> >(h, content(entry));
const failable<list<list<std::string> >, std::string> res = apply<list<std::string> >(req, rcons<std::string>, list<std::string>(), url, "POST", ch);
- if (!hasValue(res))
+ if (!hasContent(res))
return mkfailure<value, std::string>(reason(res));
return value(true);
}
@@ -296,19 +295,19 @@ const failable<value, std::string> put(const value& val, const std::string& url,
// Convert value to an ATOM entry
const failable<list<std::string>, std::string> entry = atom::writeATOMEntry(atom::entryValuesToElements(val));
- if (!hasValue(entry))
+ if (!hasContent(entry))
return mkfailure<value, std::string>(reason(entry));
if (logContent) {
std::cout << "content:" << std::endl;
- write(list<std::string>(entry), std::cout);
+ write(list<std::string>(content(entry)), std::cout);
std::cout << std::endl;
}
// PUT it to the URL
const list<std::string> h = mklist<std::string>("Content-Type: application/atom+xml");
- const list<list<std::string> > req = mklist<list<std::string> >(h, entry);
+ const list<list<std::string> > req = mklist<list<std::string> >(h, content(entry));
const failable<list<list<std::string> >, std::string> res = apply<list<std::string> >(req, rcons<std::string>, list<std::string>(), url, "PUT", ch);
- if (!hasValue(res))
+ if (!hasContent(res))
return mkfailure<value, std::string>(reason(res));
return value(true);
}
@@ -319,7 +318,7 @@ const failable<value, std::string> put(const value& val, const std::string& url,
const failable<value, std::string> del(const std::string& url, const CURLHandle& ch) {
const list<list<std::string> > req = mklist(list<std::string>(), list<std::string>());
const failable<list<list<std::string> >, std::string> res = apply<list<std::string> >(req, rcons<std::string>, list<std::string>(), url, "DELETE", ch);
- if (!hasValue(res))
+ if (!hasContent(res))
return mkfailure<value, std::string>(reason(res));
return value(true);
}
@@ -333,9 +332,9 @@ struct proxy {
const value operator()(const list<value>& args) const {
failable<value, std::string> val = evalExpr(args, url, ch);
- if (!hasValue(val))
+ if (!hasContent(val))
return value();
- return val;
+ return content(val);
}
const std::string url;
diff --git a/sca-cpp/trunk/modules/http/http-test b/sca-cpp/trunk/modules/http/http-test
index d70db8d469..1ab0da64b9 100755
--- a/sca-cpp/trunk/modules/http/http-test
+++ b/sca-cpp/trunk/modules/http/http-test
@@ -18,17 +18,7 @@
# under the License.
# Setup
-./httpd-conf tmp 8091 htdocs
-cat >>tmp/conf/httpd.conf <<EOF
-
-<Location /test>
-SetHandler mod_tuscany_eval
-SCAContribution `pwd`/
-SCAComposite httpd-test.composite
-SCAComponent httpd-test
-</Location>
-EOF
-
+./httpd-conf tmp 8090 htdocs
apachectl -k start -d `pwd`/tmp
sleep 1
diff --git a/sca-cpp/trunk/modules/http/httpd-conf b/sca-cpp/trunk/modules/http/httpd-conf
index 10a5b47ac2..b00ee06ed3 100755
--- a/sca-cpp/trunk/modules/http/httpd-conf
+++ b/sca-cpp/trunk/modules/http/httpd-conf
@@ -31,7 +31,5 @@ ServerName 127.0.0.1
Listen $port
DocumentRoot $htdocs
TypesConfig $here/conf/mime.types
-LoadModule mod_tuscany_eval $here/.libs/libmod_tuscany_eval.so
-LoadModule mod_tuscany_wiring $here/.libs/libmod_tuscany_wiring.so
EOF
diff --git a/sca-cpp/trunk/modules/http/httpd-test b/sca-cpp/trunk/modules/http/httpd-test
index 1d9b3cb34d..57c35c5cc9 100755
--- a/sca-cpp/trunk/modules/http/httpd-test
+++ b/sca-cpp/trunk/modules/http/httpd-test
@@ -21,16 +21,6 @@ echo "Testing..."
# Setup
./httpd-conf tmp 8090 htdocs
-cat >>tmp/conf/httpd.conf <<EOF
-
-<Location /test>
-SetHandler mod_tuscany_eval
-SCAContribution `pwd`/
-SCAComposite httpd-test.composite
-SCAComponent httpd-test
-</Location>
-EOF
-
apachectl -k start -d `pwd`/tmp
sleep 1
@@ -39,37 +29,6 @@ curl http://localhost:8090/index.html 2>/dev/null >tmp/index.html
diff tmp/index.html htdocs/index.html
rc=$?
-# Test ATOMPub
-if [ "$rc" = "0" ]; then
- curl http://localhost:8090/test/ >tmp/feed.xml 2>/dev/null
- diff tmp/feed.xml htdocs/feed.xml
- rc=$?
-fi
-if [ "$rc" = "0" ]; then
- curl http://localhost:8090/test/111 >tmp/entry.xml 2>/dev/null
- diff tmp/entry.xml htdocs/entry.xml
- rc=$?
-fi
-if [ "$rc" = "0" ]; then
- curl http://localhost:8090/test/ -X POST -H "Content-type: application/atom+xml" --data @htdocs/entry.xml 2>/dev/null
- rc=$?
-fi
-if [ "$rc" = "0" ]; then
- curl http://localhost:8090/test/111 -X PUT -H "Content-type: application/atom+xml" --data @htdocs/entry.xml 2>/dev/null
- rc=$?
-fi
-if [ "$rc" = "0" ]; then
- curl http://localhost:8090/test/111 -X DELETE 2>/dev/null
- rc=$?
-fi
-
-# Test JSON-RPC
-if [ "$rc" = "0" ]; then
- curl http://localhost:8090/test/ -X POST -H "Content-type: application/json-rpc" --data @htdocs/json-request.txt >tmp/json-result.txt 2>/dev/null
- diff tmp/json-result.txt htdocs/json-result.txt
- rc=$?
-fi
-
# Cleanup
apachectl -k stop -d `pwd`/tmp
sleep 2
diff --git a/sca-cpp/trunk/modules/http/httpd.hpp b/sca-cpp/trunk/modules/http/httpd.hpp
index 1271afc03c..a9ced05208 100644
--- a/sca-cpp/trunk/modules/http/httpd.hpp
+++ b/sca-cpp/trunk/modules/http/httpd.hpp
@@ -23,7 +23,7 @@
#define tuscany_httpd_hpp
/**
- * HTTPD module utility functions.
+ * HTTPD module implementation functions.
*/
#include <string>
@@ -62,6 +62,32 @@ bool logRequests = false;
bool logContent = false;
/**
+ * Returns a server-scoped module configuration.
+ */
+template<typename C> void* makeServerConf(apr_pool_t *p, server_rec *s) {
+ C* c = new (apr_palloc(p, sizeof(C))) C(s);
+ apr_pool_cleanup_register(p, c, gc_pool_cleanupCallback<C>, apr_pool_cleanup_null) ;
+ return c;
+}
+
+template<typename C> const C& serverConf(const request_rec* r, const module* mod) {
+ return *(C*)ap_get_module_config(r->server->module_config, mod);
+}
+
+/**
+ * Returns a directory-scoped module configuration.
+ */
+template<typename C> void *makeDirConf(apr_pool_t *p, char *dirspec) {
+ C* c = new (apr_palloc(p, sizeof(C))) C(dirspec);
+ apr_pool_cleanup_register(p, c, gc_pool_cleanupCallback<C>, apr_pool_cleanup_null) ;
+ return c;
+}
+
+template<typename C> C& dirConf(const request_rec* r, const module* mod) {
+ return *(C*)ap_get_module_config(r->per_dir_config, mod);
+}
+
+/**
* Convert a path string to a list of values.
*/
const list<std::string> pathTokens(const char* p) {
@@ -111,6 +137,8 @@ int logHeader(void* r, const char* key, const char* value) {
}
const bool logRequest(request_rec* r, const std::string& msg) {
+ if (!logRequests)
+ return true;
std::cout << msg << std::endl;
std::cout << "protocol: " << optional(r->protocol) << std::endl;
std::cout << "method: " << optional(r->method) << std::endl;
@@ -128,6 +156,32 @@ const bool logRequest(request_rec* r, const std::string& msg) {
return true;
}
+const bool logValue(const value& v, const std::string& msg) {
+ if (!logContent)
+ return true;
+ std::cout<< msg << ": " << v << std::endl;
+ std::cout.flush();
+ return true;
+}
+
+const bool logValue(const failable<value, std::string>& v, const std::string& msg) {
+ if (!logContent)
+ return true;
+ std::cout<< msg << ": " << v << std::endl;
+ std::cout.flush();
+ return true;
+}
+
+const bool logStrings(const list<std::string>& ls, const std::string& msg) {
+ if (!logContent)
+ return true;
+ std::cout<< msg << ": " << std::endl;
+ write(ls, std::cout);
+ std::cout<< std::endl;
+ std::cout.flush();
+ return true;
+}
+
/**
* Returns a list of key value pairs from the args in a query string.
*/
@@ -144,6 +198,19 @@ const list<list<value> > queryArgs(const request_rec* r) {
}
/**
+ * Returns a list of param values other than the id and method args from a list
+ * of key value pairs.
+ */
+const list<value> queryParams(const list<list<value> >& a) {
+ if (isNil(a))
+ return list<value>();
+ const list<value> p = car(a);
+ if (car(p) == value("id") || car(p) == value("method"))
+ return queryParams(cdr(a));
+ return cons(cadr(p), queryParams(cdr(a)));
+}
+
+/**
* Converts the args received in a POST to a list of key value pairs.
*/
const list<list<value> > postArgs(const list<value>& a) {
@@ -153,6 +220,83 @@ const list<list<value> > postArgs(const list<value>& a) {
return cons(l, postArgs(cdr(a)));
}
+/**
+ * Setup the HTTP read policy.
+ */
+const int setupReadPolicy(request_rec* r) {
+ const int rc = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK);
+ if(rc != OK)
+ return rc;
+ ap_should_client_block(r);
+ if(r->read_chunked == true && r->remaining == 0)
+ r->chunked = true;
+ //apr_table_setn(r->headers_out, "Connection", "close");
+ return OK;
+}
+
+/**
+ * Read the content of a POST or PUT.
+ */
+const list<std::string> read(request_rec* r) {
+ char b[2048];
+ const int n = ap_get_client_block(r, b, 2048);
+ if (n <= 0)
+ return list<std::string>();
+ return cons(std::string(b, n), read(r));
+}
+
+/**
+ * Convert a URI value to an absolute URL.
+ */
+const char* url(const value& v, request_rec* r) {
+ std::string u = r->uri;
+ u.append("/");
+ u.append(v);
+ return ap_construct_url(r->pool, u.c_str(), r);
+}
+
+/**
+ * Convert an ATOM entry to a value.
+ */
+const value feedEntry(const list<value>& e) {
+ const list<value> v = elementsToValues(mklist<value>(caddr(e)));
+ return cons(car(e), mklist<value>(cadr(e), cdr<value>(car(v))));
+}
+
+/**
+ * Write an HTTP result.
+ */
+const failable<int, std::string> writeResult(const failable<list<std::string>, std::string>& ls, const std::string& ct, request_rec* r) {
+ if (!hasContent(ls))
+ return mkfailure<int, std::string>(reason(ls));
+ std::ostringstream os;
+ write(content(ls), os);
+ if (logContent) {
+ std::cout<< "content: " << std::endl << os.str() << std::endl;
+ std::cout.flush();
+ }
+
+ const std::string etag(ap_md5(r->pool, (const unsigned char*)std::string(os.str()).c_str()));
+ const char* match = apr_table_get(r->headers_in, "If-None-Match");
+ apr_table_setn(r->headers_out, "ETag", apr_pstrdup(r->pool, etag.c_str()));
+ if (match != NULL && etag == match) {
+ r->status = HTTP_NOT_MODIFIED;
+ return OK;
+ }
+ ap_set_content_type(r, ct.c_str());
+ ap_rputs(std::string(os.str()).c_str(), r);
+ return OK;
+}
+
+/**
+ * Report request execution status.
+ */
+const int reportStatus(const failable<int, std::string>& rc) {
+ if (!hasContent(rc))
+ return HTTP_INTERNAL_SERVER_ERROR;
+ return content(rc);
+}
+
}
}
diff --git a/sca-cpp/trunk/modules/http/mod-eval.cpp b/sca-cpp/trunk/modules/http/mod-eval.cpp
deleted file mode 100644
index 6fef2be2cb..0000000000
--- a/sca-cpp/trunk/modules/http/mod-eval.cpp
+++ /dev/null
@@ -1,532 +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$ */
-
-/**
- * HTTPD module used to eval component implementations.
- */
-
-#include <sys/stat.h>
-
-#include <string>
-#include <iostream>
-#include <sstream>
-#include <fstream>
-
-#include "list.hpp"
-#include "slist.hpp"
-#include "value.hpp"
-#include "element.hpp"
-#include "monad.hpp"
-#include "../atom/atom.hpp"
-#include "../json/json.hpp"
-#include "../eval/driver.hpp"
-#include "../scdl/scdl.hpp"
-#include "../cache/cache.hpp"
-#include "curl.hpp"
-#include "httpd.hpp"
-
-extern "C" {
-extern module AP_MODULE_DECLARE_DATA mod_tuscany_eval;
-}
-
-namespace tuscany {
-namespace httpd {
-namespace modeval {
-
-/**
- * Server configuration.
- */
-class ServerConf {
-public:
- ServerConf() : home("") {
- }
- std::string home;
-};
-
-const ServerConf& serverConf(const request_rec* r) {
- return *(ServerConf*)ap_get_module_config(r->server->module_config, &mod_tuscany_eval);
-}
-
-/**
- * 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() : contributionPath(""), compositeName(""), componentName(""), implementationPath("") {
- }
- std::string contributionPath;
- std::string compositeName;
- std::string componentName;
- std::string implementationPath;
- cache::cached<failable<value, std::string> > component;
- cache::cached<failable<value, std::string> > implementation;
-};
-
-DirConf& dirConf(const request_rec* r) {
- return *(DirConf*)ap_get_module_config(r->per_dir_config, &mod_tuscany_eval);
-}
-
-/**
- * Evaluate an expression against a component implementation.
- */
-const failable<value, std::string> evalExpr(const value& expr, const value& impl) {
- gc_pool pool;
- eval::Env globalEnv = eval::setupEnvironment(pool);
- if (logContent) {
- std::cout<< "expr: " << expr << std::endl;
- std::cout.flush();
- }
- const value val = eval::evalScript(expr, impl, globalEnv, pool);
- if (logContent) {
- std::cout<< "val: " << val << std::endl;
- std::cout.flush();
- }
-
- if (isNil(val))
- return mkfailure<value, std::string>("Could not evaluate expression");
- return val;
-}
-
-/**
- * Returns a list of param values other than the id and method args from a list
- * of key value pairs.
- */
-const list<value> queryParams(const list<list<value> >& a) {
- if (isNil(a))
- return list<value>();
- const list<value> p = car(a);
- if (car(p) == value("id") || car(p) == value("method"))
- return queryParams(cdr(a));
- return cons(cadr(p), queryParams(cdr(a)));
-}
-
-/**
- * Write an HTTP result.
- */
-const failable<int, std::string> writeResult(const failable<list<std::string>, std::string>& ls, const std::string& ct, request_rec* r) {
- if (!hasValue(ls))
- return mkfailure<int, std::string>(reason(ls));
- std::ostringstream os;
- write(ls, os);
- if (logContent) {
- std::cout<< "content: " << std::endl << os.str() << std::endl;
- std::cout.flush();
- }
-
- const std::string etag(ap_md5(r->pool, (const unsigned char*)std::string(os.str()).c_str()));
- const char* match = apr_table_get(r->headers_in, "If-None-Match");
- apr_table_setn(r->headers_out, "ETag", apr_pstrdup(r->pool, etag.c_str()));
- if (match != NULL && etag == match) {
- r->status = HTTP_NOT_MODIFIED;
- return OK;
- }
- ap_set_content_type(r, ct.c_str());
- ap_rputs(std::string(os.str()).c_str(), r);
- return OK;
-}
-
-/**
- * Handle an HTTP GET.
- */
-const failable<int, std::string> get(request_rec* r, const value& impl, const list<value>& px) {
-
- // Inspect the query string
- const list<list<value> > args = 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 = std::string(cadr(ma)).c_str();
- const list<value> params = queryParams(args);
-
- // Evaluate the request expression
- const failable<value, std::string> val = evalExpr(cons<value>(func, eval::quotedParameters(append(params, px))), impl);
- if (!hasValue(val))
- return mkfailure<int, std::string>(reason(val));
-
- // Return JSON result
- json::JSONContext cx;
- return writeResult(json::jsonResult(id, val, cx), "application/json-rpc", r);
- }
-
- // Evaluate an ATOM GET request and return an ATOM feed
- const list<value> id(path(r->path_info));
- if (isNil(id)) {
- const failable<value, std::string> val = evalExpr(cons<value>("getall", eval::quotedParameters(px)), impl);
- if (!hasValue(val))
- return mkfailure<int, std::string>(reason(val));
- const value feed = val;
- return writeResult(atom::writeATOMFeed(atom::feedValuesToElements(feed)), "application/atom+xml;type=feed", r);
- }
-
- // Evaluate an ATOM GET and return an ATOM entry
- const failable<value, std::string> val = evalExpr(cons<value>("get", eval::quotedParameters(cons<value>(car(id), px))), impl);
- if (!hasValue(val))
- return mkfailure<int, std::string>(reason(val));
- const value entry = val;
- return writeResult(atom::writeATOMEntry(atom::entryValuesToElements(entry)), "application/atom+xml;type=entry", r);
-
-}
-
-/**
- * Read the content of a POST.
- */
-const list<std::string> read(request_rec* r) {
- char b[2048];
- const int n = ap_get_client_block(r, b, 2048);
- if (n <= 0)
- return list<std::string>();
- return cons(std::string(b, n), read(r));
-}
-
-/**
- * Convert a URI value to an absolute URL.
- */
-const char* url(const value& v, request_rec* r) {
- std::string u = r->uri;
- u.append("/");
- u.append(v);
- return ap_construct_url(r->pool, u.c_str(), r);
-}
-
-/**
- * Convert an ATOM entry to a value.
- */
-const value feedEntry(const list<value>& e) {
- const list<value> v = elementsToValues(mklist<value>(caddr(e)));
- return cons(car(e), mklist<value>(cadr(e), cdr<value>(car(v))));
-}
-
-/**
- * Handle an HTTP POST.
- */
-const failable<int, std::string> post(request_rec* r, const value& impl, const list<value>& px) {
- const list<std::string> ls = read(r);
- if (logContent) {
- std::cout<< "content: " << std::endl;
- write(ls, std::cout);
- std::cout<< std::endl;
- std::cout.flush();
- }
-
- // Evaluate a JSON-RPC request and return a JSON result
- const std::string ct = contentType(r);
- if (ct.find("application/json-rpc") != std::string::npos || ct.find("text/plain") != std::string::npos) {
- json::JSONContext cx;
- const list<value> json = elementsToValues(json::readJSON(ls, cx));
- const list<list<value> > args = postArgs(json);
-
- // Extract the request id, method and params
- const value id = cadr(assoc(value("id"), args));
- const value func = std::string(cadr(assoc(value("method"), args))).c_str();
- const list<value> params = (list<value>)cadr(assoc(value("params"), args));
-
- // Evaluate the request expression
- const failable<value, std::string> val = evalExpr(cons<value>(func, eval::quotedParameters(append(params, px))), impl);
- if (!hasValue(val))
- return mkfailure<int, std::string>(reason(val));
-
- // Return JSON result
- return writeResult(json::jsonResult(id, val, cx), "application/json-rpc", r);
- }
-
- // Evaluate an ATOM POST request and return the created resource location
- if (ct.find("application/atom+xml") != std::string::npos) {
-
- // Evaluate the request expression
- const value entry = feedEntry(atom::readEntry(ls));
- const failable<value, std::string> val = evalExpr(cons<value>("post", eval::quotedParameters(cons<value>(entry, px))), impl);
- if (!hasValue(val))
- return mkfailure<int, std::string>(reason(val));
-
- // Return the created resource location
- apr_table_setn(r->headers_out, "Location", apr_pstrdup(r->pool, url(val, r)));
- r->status = HTTP_CREATED;
- return OK;
- }
-
- return HTTP_NOT_IMPLEMENTED;
-}
-
-/**
- * Handle an HTTP PUT.
- */
-const failable<int, std::string> put(request_rec* r, const value& impl, const list<value>& px) {
- const list<std::string> ls = read(r);
- if (logContent) {
- std::cout<< "content: " << std::endl;
- write(ls, std::cout);
- std::cout<< std::endl;
- std::cout.flush();
- }
-
- // Evaluate an ATOM PUT request
- const list<value> id(path(r->path_info));
- const value entry = feedEntry(atom::readEntry(ls));
- const failable<value, std::string> val = evalExpr(cons<value>("put", eval::quotedParameters(append(mklist<value>(entry, car(id)), px))), impl);
- if (!hasValue(val))
- return mkfailure<int, std::string>(reason(val));
- if (val == value(false))
- return HTTP_NOT_FOUND;
- return OK;
-}
-
-/**
- * Handle an HTTP DELETE.
- */
-const failable<int, std::string> del(request_rec* r, const value& impl, const list<value>& px) {
-
- // Evaluate an ATOM delete request
- const list<value> id(path(r->path_info));
- const failable<value, std::string> val = evalExpr(cons<value>("delete", eval::quotedParameters(cons<value>(car(id), px))), impl);
- if (!hasValue(val))
- return mkfailure<int, std::string>(reason(val));
- if (val == value(false))
- return HTTP_NOT_FOUND;
- return OK;
-}
-
-/**
- * Report request execution status.
- */
-const int reportStatus(const failable<int, std::string>& rc) {
- if (!hasValue(rc))
- return HTTP_INTERNAL_SERVER_ERROR;
- return rc;
-}
-
-/**
- * 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 cache::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(cache::latestFileTime);
- return cache::cached<failable<value, std::string> >(curry(rc, path, conf->componentName), curry(ft, path));
-}
-
-/**
- * Read a component implementation.
- */
-const failable<value, std::string> readImplementation(const std::string path) {
- std::ifstream is(path.c_str(), std::ios_base::in);
- if (is.fail() || is.bad())
- return mkfailure<value, std::string>("Could not read implementation: " + path);
- const value impl = eval::readScript(is);
- if (isNil(impl))
- return mkfailure<value, std::string>("Could not read implementation: " + path);
- return impl;
-}
-
-const cache::cached<failable<value, std::string> > implementation(const std::string& path) {
- const lambda<failable<value, std::string>(std::string)> ri(readImplementation);
- const lambda<unsigned long(std::string)> ft(cache::latestFileTime);
- return cache::cached<failable<value, std::string> >(curry(ri, path), 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::CURLHandle& ch) {
- return eval::primitiveProcedure(http::proxy(base + std::string(scdl::name(ref)), ch));
-}
-
-const list<value> proxies(const list<value>& refs, const std::string& base, const http::CURLHandle& ch) {
- if (isNil(refs))
- return refs;
- return cons(mkproxy(car(refs), base, ch), proxies(cdr(refs), base, ch));
-}
-
-/**
- * HTTP request handler.
- */
-int handler(request_rec *r) {
- if(strcmp(r->handler, "mod_tuscany_eval"))
- return DECLINED;
-
- // Log the request
- if(logRequests)
- logRequest(r, "mod_tuscany_eval::handler");
-
- // Set up the read policy
- const int rc = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK);
- if(rc != OK)
- return rc;
- ap_should_client_block(r);
- if(r->read_chunked == true && r->remaining == 0)
- r->chunked = true;
- //apr_table_setn(r->headers_out, "Connection", "close");
-
- // Retrieve the latest component configuration
- DirConf& conf = dirConf(r);
- conf.component = cache::latest(conf.component);
- const failable<value, std::string> comp(conf.component);
- if (!hasValue(comp))
- return HTTP_NOT_FOUND;
-
- // Retrieve the latest implementation
- const std::string path = conf.contributionPath + std::string(scdl::uri(scdl::implementation(comp)));
- if (path != conf.implementationPath) {
- conf.implementationPath = path;
- conf.implementation = cache::latest(implementation(path));
- }
- else
- conf.implementation = cache::latest(conf.implementation);
- const failable<value, std::string> impl(conf.implementation);
- if (!hasValue(impl))
- return HTTP_NOT_FOUND;
-
- // Convert component references to configured proxy lambdas
- std::ostringstream base;
- base << "http://localhost:" << (debugWiringPort == 0? ap_get_server_port(r) : debugWiringPort) << "/references/" << std::string(scdl::name(comp)) << "/";
- http::CURLHandle ch;
- const list<value> px(proxies(scdl::references(comp), base.str(), ch));
-
- // Handle HTTP method
- if (r->header_only)
- return OK;
- if(r->method_number == M_GET)
- return reportStatus(get(r, impl, px));
- if(r->method_number == M_POST)
- return reportStatus(post(r, impl, px));
- if(r->method_number == M_PUT)
- return reportStatus(put(r, impl, px));
- if(r->method_number == M_DELETE)
- return reportStatus(del(r, impl, px));
- return HTTP_NOT_IMPLEMENTED;
-}
-
-/**
- * Configuration commands.
- */
-const char *confHome(cmd_parms *cmd, 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 char *confContribution(cmd_parms *cmd, void *c, const char *arg) {
- DirConf* conf = (DirConf*)c;
- conf->contributionPath = arg;
- conf->component = component(conf);
- return NULL;
-}
-const char *confComposite(cmd_parms *cmd, void *c, const char *arg) {
- DirConf* conf = (DirConf*)c;
- conf->compositeName = arg;
- conf->component = component(conf);
- return NULL;
-}
-const char *confComponent(cmd_parms *cmd, void *c, const char *arg) {
- DirConf* conf = (DirConf*)c;
- conf->componentName = arg;
- conf->component = component(conf);
- return NULL;
-}
-
-void *makeDirConf(apr_pool_t *p, char *dirspec) {
- DirConf* c = new (apr_palloc(p, sizeof(DirConf))) DirConf();
- apr_pool_cleanup_register(p, c, gc_pool_cleanupCallback<DirConf>, apr_pool_cleanup_null) ;
- return c;
-}
-void* makeServerConf(apr_pool_t *p, server_rec *s) {
- ServerConf* c = new (apr_palloc(p, sizeof(ServerConf))) ServerConf();
- apr_pool_cleanup_register(p, c, gc_pool_cleanupCallback<ServerConf>, apr_pool_cleanup_null) ;
- return c;
-}
-
-/**
- * HTTP server module declaration.
- */
-const command_rec commands[] = {
- AP_INIT_TAKE1("TuscanyHome", (const char*(*)())confHome, NULL, RSRC_CONF, "Tuscany home directory"),
- 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}
-};
-
-int postConfig(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) {
- return OK;
-}
-
-void childInit(apr_pool_t* p, server_rec* svr_rec) {
- 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);
- }
-}
-
-void registerHooks(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);
-}
-
-}
-}
-}
-
-extern "C" {
-
-module AP_MODULE_DECLARE_DATA mod_tuscany_eval = {
- STANDARD20_MODULE_STUFF,
- // dir config
- tuscany::httpd::modeval::makeDirConf,
- // dir merger, default is to override
- NULL,
- // server config
- tuscany::httpd::modeval::makeServerConf,
- // merge server config
- NULL,
- // command table
- tuscany::httpd::modeval::commands,
- // register hooks
- tuscany::httpd::modeval::registerHooks
-};
-
-}
diff --git a/sca-cpp/trunk/modules/json/json-test.cpp b/sca-cpp/trunk/modules/json/json-test.cpp
index fd506cea65..4d1bbffd5a 100644
--- a/sca-cpp/trunk/modules/json/json-test.cpp
+++ b/sca-cpp/trunk/modules/json/json-test.cpp
@@ -70,11 +70,11 @@ bool testJSON() {
std::istringstream is(os.str());
const list<std::string> il = streamList(is);
- const list<value> r = readJSON(il, cx);
+ const list<value> r = content(readJSON(il, cx));
assert(r == l);
std::ostringstream wos;
- write(writeJSON(r, cx), wos);
+ write(content(writeJSON(r, cx)), wos);
assert(wos.str() == os.str());
}
return true;
@@ -84,7 +84,7 @@ bool testJSONRPC() {
JSONContext cx;
{
const std::string lm("{\"id\": 1, \"method\": \"system.listMethods\", \"params\": []}");
- const list<value> e = readJSON(mklist(lm), cx);
+ const list<value> e = content(readJSON(mklist(lm), cx));
const list<value> v = elementsToValues(e);
assert(assoc<value>("id", v) == mklist<value>("id", 1));
assert(assoc<value>("method", v) == mklist<value>("method", std::string("system.listMethods")));
@@ -92,16 +92,16 @@ bool testJSONRPC() {
}
{
const std::string i("{\"id\":3,\"result\":[{\"price\":\"$2.99\",\"name\":\"Apple\"},{\"price\":\"$3.55\",\"name\":\"Orange\"},{\"price\":\"$1.55\",\"name\":\"Pear\"}]}");
- const list<value> e = readJSON(mklist(i), cx);
+ const list<value> e = content(readJSON(mklist(i), cx));
const std::string i2("{\"id\":3,\"result\":{\"0\":{\"price\":\"$2.99\",\"name\":\"Apple\"},\"1\":{\"price\":\"$3.55\",\"name\":\"Orange\"},\"2\":{\"price\":\"$1.55\",\"name\":\"Pear\"}}}");
- const list<value> e2 = readJSON(mklist(i), cx);
+ const list<value> e2 = content(readJSON(mklist(i), cx));
assert(e == e2);
}
{
const std::string i("{\"id\":3,\"result\":[{\"price\":\"$2.99\",\"name\":\"Apple\"},{\"price\":\"$3.55\",\"name\":\"Orange\"},{\"price\":\"$1.55\",\"name\":\"Pear\"}]}");
- const list<value> e = readJSON(mklist(i), cx);
+ const list<value> e = content(readJSON(mklist(i), cx));
std::ostringstream os;
- write(writeJSON(e, cx), os);
+ write(content(writeJSON(e, cx)), os);
assert(os.str() == i);
const list<value> v = elementsToValues(e);
const list<value> r = valuesToElements(v);
@@ -111,16 +111,16 @@ bool testJSONRPC() {
const list<value> r = mklist<value>(mklist<value>("id", 1), mklist<value>("result", mklist<value>(std::string("Service.get"), std::string("Service.getTotal"))));
const list<value> e = valuesToElements(r);
std::ostringstream os;
- write(writeJSON(e, cx), os);
+ write(content(writeJSON(e, cx)), os);
assert(os.str() == "{\"id\":1,\"result\":[\"Service.get\",\"Service.getTotal\"]}");
}
{
const std::string f("{\"id\":1,\"result\":[\"Sample Feed\",\"123456789\",[\"Item\",\"111\",{\"javaClass\":\"services.Item\",\"name\":\"Apple\",\"currencyCode\":\"USD\",\"currencySymbol\":\"$\",\"price\":2.99}],[\"Item\",\"222\",{\"javaClass\":\"services.Item\",\"name\":\"Orange\",\"currencyCode\":\"USD\",\"currencySymbol\":\"$\",\"price\":3.55}],[\"Item\",\"333\",{\"javaClass\":\"services.Item\",\"name\":\"Pear\",\"currencyCode\":\"USD\",\"currencySymbol\":\"$\",\"price\":1.55}]]}");
- const list<value> r = readJSON(mklist(f), cx);
+ const list<value> r = content(readJSON(mklist(f), cx));
const list<value> v = elementsToValues(r);
const list<value> e = valuesToElements(v);
std::ostringstream os;
- write(writeJSON(e, cx), os);
+ write(content(writeJSON(e, cx)), os);
assert(os.str() == f);
}
return true;
diff --git a/sca-cpp/trunk/modules/json/json.hpp b/sca-cpp/trunk/modules/json/json.hpp
index f6c8eb5fe8..7b18d237ec 100644
--- a/sca-cpp/trunk/modules/json/json.hpp
+++ b/sca-cpp/trunk/modules/json/json.hpp
@@ -217,7 +217,7 @@ const failable<list<value>, std::string> readJSON(const list<std::string>& ilist
if(!JS_FinishJSONParse(cx, parser, JSVAL_NULL))
return mkfailure<list<value>, std::string>("JS_FinishJSONParse failed");
- if(!hasValue(consumed))
+ if(!hasContent(consumed))
return mkfailure<list<value>, std::string>(reason(consumed));
return list<value>(jsValToValue(val, cx));
@@ -318,7 +318,7 @@ const failable<bool, std::string> writeList(const list<value>& l, JSObject* o, c
// Write its children
const failable<bool, std::string> w = writeList(elementChildren(token), child, cx);
- if (!hasValue(w))
+ if (!hasContent(w))
return w;
}
}
@@ -356,7 +356,7 @@ template<typename R> const failable<R, std::string> writeJSON(const lambda<R(std
JSObject* o = JS_NewObject(cx, NULL, NULL, NULL);
jsval val = OBJECT_TO_JSVAL(o);
const failable<bool, std::string> w = writeList(l, o, cx);
- if (!hasValue(w))
+ if (!hasContent(w))
return mkfailure<R, std::string>(reason(w));
WriteContext<R> wcx(reduce, initial, cx);
@@ -370,9 +370,9 @@ template<typename R> const failable<R, std::string> writeJSON(const lambda<R(std
*/
const failable<list<std::string>, std::string> writeJSON(const list<value>& l, const JSONContext& cx) {
const failable<list<std::string>, std::string> ls = writeJSON<list<std::string> >(rcons<std::string>, list<std::string>(), l, cx);
- if (!hasValue(ls))
+ if (!hasContent(ls))
return ls;
- return reverse(list<std::string>(ls));
+ return reverse(list<std::string>(content(ls)));
}
/**
diff --git a/sca-cpp/trunk/modules/scdl/scdl-test b/sca-cpp/trunk/modules/scdl/scdl-test
deleted file mode 100755
index acef45d225..0000000000
--- a/sca-cpp/trunk/modules/scdl/scdl-test
+++ /dev/null
Binary files differ
diff --git a/sca-cpp/trunk/modules/server/Makefile.am b/sca-cpp/trunk/modules/server/Makefile.am
new file mode 100644
index 0000000000..204c8e4ae4
--- /dev/null
+++ b/sca-cpp/trunk/modules/server/Makefile.am
@@ -0,0 +1,36 @@
+# 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.
+
+noinst_PROGRAMS = client-test
+
+libdir=$(prefix)/lib
+lib_LTLIBRARIES = libmod_tuscany_eval.la libmod_tuscany_wiring.la
+
+INCLUDES = -I. -I$(top_builddir)/kernel -I${LIBXML2_INCLUDE} -I${HTTPD_INCLUDE} -I${APR_INCLUDE} -I${JS_INCLUDE} -I${CURL_INCLUDE}
+
+libmod_tuscany_eval_la_SOURCES = mod-eval.cpp
+libmod_tuscany_eval_la_LIBADD = -lpthread -L${LIBXML2_LIB} -lxml2 -L${APR_LIB} -lapr-1 -laprutil-1 -L${CURL_LIB} -lcurl -L${JS_LIB} -lmozjs
+
+libmod_tuscany_wiring_la_SOURCES = mod-wiring.cpp
+libmod_tuscany_wiring_la_LIBADD = -lpthread -L${LIBXML2_LIB} -lxml2 -L${APR_LIB} -lapr-1 -laprutil-1 -L${CURL_LIB} -lcurl -L${JS_LIB} -lmozjs
+
+client_test_SOURCES = client-test.cpp
+client_test_LDADD = -lpthread -L${LIBXML2_LIB} -lxml2 -L${APR_LIB} -lapr-1 -laprutil-1 -L${CURL_LIB} -lcurl -L${JS_LIB} -lmozjs
+
+TESTS = httpd-test http-test wiring-test
+
+
diff --git a/sca-cpp/trunk/modules/server/client-test.cpp b/sca-cpp/trunk/modules/server/client-test.cpp
new file mode 100644
index 0000000000..b43cb92c52
--- /dev/null
+++ b/sca-cpp/trunk/modules/server/client-test.cpp
@@ -0,0 +1,251 @@
+/*
+ * 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$ */
+
+/**
+ * Test HTTP client functions.
+ */
+
+#include <assert.h>
+#include <sys/time.h>
+#include <time.h>
+#include <iostream>
+#include <sstream>
+#include <string>
+#include "slist.hpp"
+#include "../http/curl.hpp"
+
+namespace tuscany {
+namespace server {
+
+const bool contains(const std::string& str, const std::string& pattern) {
+ return str.find(pattern) != str.npos;
+}
+
+const double duration(struct timeval start, struct timeval end, int count) {
+ long t = (end.tv_sec * 1000 + end.tv_usec / 1000) - (start.tv_sec * 1000 + start.tv_usec / 1000);
+ return (double)t / (double)count;
+}
+
+std::ostringstream* curlWriter(const std::string& s, std::ostringstream* os) {
+ (*os) << s;
+ return os;
+}
+
+const bool testGet() {
+ http::CURLHandle ch;
+ {
+ std::ostringstream os;
+ const failable<list<std::ostringstream*>, std::string> r = http::get<std::ostringstream*>(curlWriter, &os, "http://localhost:8090", ch);
+ assert(hasContent(r));
+ assert(contains(os.str(), "HTTP/1.1 200 OK"));
+ assert(contains(os.str(), "It works"));
+ }
+ {
+ const failable<value, std::string> r = http::get("http://localhost:8090", ch);
+ assert(hasContent(r));
+ assert(contains(content(r), "It works"));
+ }
+ return true;
+}
+
+const bool testGetLoop(const int count, http::CURLHandle& ch) {
+ if (count == 0)
+ return true;
+ const failable<value, std::string> r = get("http://localhost:8090", ch);
+ assert(hasContent(r));
+ assert(contains(content(r), "It works"));
+ return testGetLoop(count - 1, ch);
+}
+
+const bool testGetPerf() {
+ const int count = 50;
+ http::CURLHandle ch;
+ struct timeval start;
+ struct timeval end;
+ {
+ testGetLoop(5, ch);
+
+ gettimeofday(&start, NULL);
+
+ testGetLoop(count, ch);
+
+ gettimeofday(&end, NULL);
+ std::cout << "Static GET test " << duration(start, end, count) << " ms" << std::endl;
+ }
+ return true;
+}
+
+const bool testEval() {
+ http::CURLHandle ch;
+ const value val = content(http::evalExpr(mklist<value>(std::string("echo"), std::string("Hello")), "http://localhost:8090/test", ch));
+ assert(val == std::string("Hello"));
+ return true;
+}
+
+const bool testEvalLoop(const int count, http::CURLHandle& ch) {
+ if (count == 0)
+ return true;
+ const value val = content(http::evalExpr(mklist<value>(std::string("echo"), std::string("Hello")), "http://localhost:8090/test", ch));
+ assert(val == std::string("Hello"));
+ return testEvalLoop(count - 1, ch);
+}
+
+const value blob(std::string(3000, 'A'));
+const list<value> blobs = mklist(blob, blob, blob, blob, blob);
+
+const bool testBlobEvalLoop(const int count, http::CURLHandle& ch) {
+ if (count == 0)
+ return true;
+ const value val = content(http::evalExpr(mklist<value>(std::string("echo"), blobs), "http://localhost:8090/test", ch));
+ assert(val == blobs);
+ return testBlobEvalLoop(count - 1, ch);
+}
+
+const bool testEvalPerf() {
+ const int count = 50;
+ http::CURLHandle ch;
+ struct timeval start;
+ struct timeval end;
+ {
+ testEvalLoop(5, ch);
+
+ gettimeofday(&start, NULL);
+
+ testEvalLoop(count, ch);
+
+ gettimeofday(&end, NULL);
+ std::cout << "JSON-RPC eval echo test " << duration(start, end, count) << " ms" << std::endl;
+ }
+ {
+ testBlobEvalLoop(5, ch);
+
+ gettimeofday(&start, NULL);
+
+ testBlobEvalLoop(count, ch);
+
+ gettimeofday(&end, NULL);
+ std::cout << "JSON-RPC eval blob test " << duration(start, end, count) << " ms" << std::endl;
+ }
+ return true;
+}
+
+const bool testFeed() {
+ return true;
+}
+
+bool testPost() {
+ const list<value> i = list<value>()
+ << (list<value>() << "name" << std::string("Apple"))
+ << (list<value>() << "price" << std::string("$2.99"));
+ const list<value> a = mklist<value>(std::string("item"), std::string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
+ http::CURLHandle ch;
+ value rc = content(http::post(a, "http://localhost:8090/test", ch));
+ assert(rc == value(true));
+ return true;
+}
+
+const bool testPostLoop(const int count, const value& val, http::CURLHandle& ch) {
+ if (count == 0)
+ return true;
+ const value rc = content(http::post(val, "http://localhost:8090/test", ch));
+ assert(rc == value(true));
+ return testPostLoop(count - 1, val, ch);
+}
+
+const bool testPostPerf() {
+ const int count = 50;
+ http::CURLHandle ch;
+ struct timeval start;
+ struct timeval end;
+ {
+ const list<value> i = list<value>()
+ << (list<value>() << "name" << std::string("Apple"))
+ << (list<value>() << "price" << std::string("$2.99"));
+ const list<value> val = mklist<value>(std::string("item"), std::string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
+ testPostLoop(5, val, ch);
+
+ gettimeofday(&start, NULL);
+
+ testPostLoop(count, val, ch);
+
+ gettimeofday(&end, NULL);
+ std::cout << "ATOMPub POST small test " << duration(start, end, count) << " ms" << std::endl;
+ }
+ {
+ const list<value> i = list<value>()
+ << (list<value>() << "name" << std::string("Apple"))
+ << (list<value>() << "blob1" << blob)
+ << (list<value>() << "blob2" << blob)
+ << (list<value>() << "blob3" << blob)
+ << (list<value>() << "blob4" << blob)
+ << (list<value>() << "blob5" << blob)
+ << (list<value>() << "price" << std::string("$2.99"));
+ const list<value> val = mklist<value>(std::string("item"), std::string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
+ testPostLoop(5, val, ch);
+
+ gettimeofday(&start, NULL);
+
+ testPostLoop(count, val, ch);
+
+ gettimeofday(&end, NULL);
+ std::cout << "ATOMPub POST blob test " << duration(start, end, count) << " ms" << std::endl;
+ }
+ return true;
+}
+
+const bool testPut() {
+ const list<value> i = list<value>()
+ << (list<value>() << "name" << std::string("Apple"))
+ << (list<value>() << "price" << std::string("$2.99"));
+ const list<value> a = mklist<value>(std::string("item"), std::string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
+ http::CURLHandle ch;
+ value rc = content(http::put(a, "http://localhost:8090/test/111", ch));
+ assert(rc == value(true));
+ return true;
+}
+
+const bool testDel() {
+ http::CURLHandle ch;
+ value rc = content(http::del("http://localhost:8090/test/123456789", ch));
+ assert(rc == value(true));
+ return true;
+}
+
+}
+}
+
+int main() {
+ std::cout << "Testing..." << std::endl;
+
+ tuscany::server::testGet();
+ tuscany::server::testGetPerf();
+ tuscany::server::testPost();
+ tuscany::server::testPostPerf();
+ tuscany::server::testEval();
+ tuscany::server::testEvalPerf();
+ tuscany::server::testFeed();
+ tuscany::server::testPut();
+ tuscany::server::testDel();
+
+ std::cout << "OK" << std::endl;
+
+ return 0;
+}
diff --git a/sca-cpp/trunk/modules/http/htdocs/entry.xml b/sca-cpp/trunk/modules/server/htdocs/entry.xml
index 86b8a10547..86b8a10547 100644
--- a/sca-cpp/trunk/modules/http/htdocs/entry.xml
+++ b/sca-cpp/trunk/modules/server/htdocs/entry.xml
diff --git a/sca-cpp/trunk/modules/http/htdocs/feed.xml b/sca-cpp/trunk/modules/server/htdocs/feed.xml
index 5e37de6580..5e37de6580 100644
--- a/sca-cpp/trunk/modules/http/htdocs/feed.xml
+++ b/sca-cpp/trunk/modules/server/htdocs/feed.xml
diff --git a/sca-cpp/trunk/modules/server/htdocs/index.html b/sca-cpp/trunk/modules/server/htdocs/index.html
new file mode 100644
index 0000000000..1bfb3e30c2
--- /dev/null
+++ b/sca-cpp/trunk/modules/server/htdocs/index.html
@@ -0,0 +1,21 @@
+<!--
+ 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.
+-->
+
+<html><body><h1>It works!</h1></body></html>
+
diff --git a/sca-cpp/trunk/modules/http/htdocs/json-request.txt b/sca-cpp/trunk/modules/server/htdocs/json-request.txt
index b4bd07fc46..b4bd07fc46 100644
--- a/sca-cpp/trunk/modules/http/htdocs/json-request.txt
+++ b/sca-cpp/trunk/modules/server/htdocs/json-request.txt
diff --git a/sca-cpp/trunk/modules/http/htdocs/json-result.txt b/sca-cpp/trunk/modules/server/htdocs/json-result.txt
index 121bf74902..121bf74902 100644
--- a/sca-cpp/trunk/modules/http/htdocs/json-result.txt
+++ b/sca-cpp/trunk/modules/server/htdocs/json-result.txt
diff --git a/sca-cpp/trunk/modules/server/http-test b/sca-cpp/trunk/modules/server/http-test
new file mode 100755
index 0000000000..6d23911c31
--- /dev/null
+++ b/sca-cpp/trunk/modules/server/http-test
@@ -0,0 +1,43 @@
+#!/bin/sh
+
+# 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.
+
+# Setup
+../http/httpd-conf tmp 8090 htdocs
+./server-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+
+<Location /test>
+SetHandler mod_tuscany_eval
+SCAContribution `pwd`/
+SCAComposite httpd-test.composite
+SCAComponent httpd-test
+</Location>
+EOF
+
+apachectl -k start -d `pwd`/tmp
+sleep 1
+
+# Test
+./client-test
+rc=$?
+
+# Cleanup
+apachectl -k stop -d `pwd`/tmp
+sleep 2
+return $rc
diff --git a/sca-cpp/trunk/modules/http/httpd-client.scm b/sca-cpp/trunk/modules/server/httpd-client.scm
index 12275693f4..12275693f4 100644
--- a/sca-cpp/trunk/modules/http/httpd-client.scm
+++ b/sca-cpp/trunk/modules/server/httpd-client.scm
diff --git a/sca-cpp/trunk/modules/server/httpd-test b/sca-cpp/trunk/modules/server/httpd-test
new file mode 100755
index 0000000000..7fa2112f75
--- /dev/null
+++ b/sca-cpp/trunk/modules/server/httpd-test
@@ -0,0 +1,80 @@
+#!/bin/sh
+
+# 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.
+
+echo "Testing..."
+
+# Setup
+../http/httpd-conf tmp 8090 htdocs
+./server-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+
+<Location /test>
+SetHandler mod_tuscany_eval
+SCAContribution `pwd`/
+SCAComposite httpd-test.composite
+SCAComponent httpd-test
+</Location>
+EOF
+
+apachectl -k start -d `pwd`/tmp
+sleep 1
+
+# Test HTTP GET
+curl http://localhost:8090/index.html 2>/dev/null >tmp/index.html
+diff tmp/index.html htdocs/index.html
+rc=$?
+
+# Test ATOMPub
+if [ "$rc" = "0" ]; then
+ curl http://localhost:8090/test/ >tmp/feed.xml 2>/dev/null
+ diff tmp/feed.xml htdocs/feed.xml
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ curl http://localhost:8090/test/111 >tmp/entry.xml 2>/dev/null
+ diff tmp/entry.xml htdocs/entry.xml
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ curl http://localhost:8090/test/ -X POST -H "Content-type: application/atom+xml" --data @htdocs/entry.xml 2>/dev/null
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ curl http://localhost:8090/test/111 -X PUT -H "Content-type: application/atom+xml" --data @htdocs/entry.xml 2>/dev/null
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ curl http://localhost:8090/test/111 -X DELETE 2>/dev/null
+ rc=$?
+fi
+
+# Test JSON-RPC
+if [ "$rc" = "0" ]; then
+ curl http://localhost:8090/test/ -X POST -H "Content-type: application/json-rpc" --data @htdocs/json-request.txt >tmp/json-result.txt 2>/dev/null
+ diff tmp/json-result.txt htdocs/json-result.txt
+ rc=$?
+fi
+
+# Cleanup
+apachectl -k stop -d `pwd`/tmp
+sleep 2
+if [ "$rc" = "0" ]; then
+ echo "OK"
+fi
+return $rc
diff --git a/sca-cpp/trunk/modules/http/httpd-test.composite b/sca-cpp/trunk/modules/server/httpd-test.composite
index 875d26ae1b..875d26ae1b 100644
--- a/sca-cpp/trunk/modules/http/httpd-test.composite
+++ b/sca-cpp/trunk/modules/server/httpd-test.composite
diff --git a/sca-cpp/trunk/modules/http/httpd-test.scm b/sca-cpp/trunk/modules/server/httpd-test.scm
index 0566eaf36f..0566eaf36f 100644
--- a/sca-cpp/trunk/modules/http/httpd-test.scm
+++ b/sca-cpp/trunk/modules/server/httpd-test.scm
diff --git a/sca-cpp/trunk/modules/server/mod-cpp.hpp b/sca-cpp/trunk/modules/server/mod-cpp.hpp
new file mode 100644
index 0000000000..cb24b76f6c
--- /dev/null
+++ b/sca-cpp/trunk/modules/server/mod-cpp.hpp
@@ -0,0 +1,91 @@
+/*
+ * 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_modcpp_hpp
+#define tuscany_modcpp_hpp
+
+/**
+ * Evaluation functions used by mod-eval to evaluate implementation.cpp
+ * component implementations.
+ */
+
+#include <string>
+#include <iostream>
+#include <fstream>
+
+#include "function.hpp"
+#include "list.hpp"
+#include "value.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 {
+namespace modeval {
+namespace cpp {
+
+/**
+ * Evaluate a C++ component implementation function.
+ */
+struct evalImplementation {
+ const lib ilib;
+ const ilambda impl;
+ evalImplementation(const lib& ilib, const ilambda& impl) : ilib(ilib), impl(impl) {
+ }
+ const failable<value, std::string> operator()(const value& func, const list<value>& params) const {
+ httpd::logValue(cons<value>(func, params), "expr");
+ const failable<value, std::string> val = impl(func, params);
+ httpd::logValue(content(val), "val");
+ return val;
+ }
+};
+
+/**
+ * Read a C++ component implementation.
+ */
+const failable<ilambda, std::string> readLatestImplementation(const std::string path) {
+ const failable<lib, std::string> ilib(dynlib(path));
+ if (!hasContent(ilib))
+ return mkfailure<ilambda, std::string>(reason(ilib));
+
+ const failable<ilambda, std::string> impl(dynlambda<failable<value, std::string>(value, list<value>)>("eval", content(ilib)));
+ if (!hasContent(impl))
+ return impl;
+ return ilambda(evalImplementation(content(ilib), content(impl)));
+}
+
+const cached<failable<ilambda, std::string> > readImplementation(const std::string& path) {
+ const lambda<failable<ilambda, std::string>(std::string)> 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), curry(ft, p));
+}
+
+}
+}
+}
+}
+
+#endif /* tuscany_modcpp_hpp */
diff --git a/sca-cpp/trunk/modules/server/mod-eval.cpp b/sca-cpp/trunk/modules/server/mod-eval.cpp
new file mode 100644
index 0000000000..f843b9bdc5
--- /dev/null
+++ b/sca-cpp/trunk/modules/server/mod-eval.cpp
@@ -0,0 +1,387 @@
+/*
+ * 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$ */
+
+/**
+ * HTTPD module used to eval component implementations.
+ */
+
+#include <string>
+#include <iostream>
+#include <sstream>
+#include <fstream>
+
+#include "function.hpp"
+#include "list.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"
+
+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("") {
+ }
+ server_rec* s;
+ std::string home;
+};
+
+/**
+ * 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("") {
+ }
+ 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;
+};
+
+/**
+ * Handle an HTTP GET.
+ */
+const failable<int, std::string> get(request_rec* r, const ilambda& impl, const list<value>& px) {
+
+ // 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 = 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, append(params, px));
+ if (!hasContent(val))
+ return mkfailure<int, std::string>(reason(val));
+
+ // Return JSON result
+ json::JSONContext cx;
+ return httpd::writeResult(json::jsonResult(id, content(val), cx), "application/json-rpc", r);
+ }
+
+ // 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", px);
+ 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", cons<value>(car(id), px));
+ 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);
+}
+
+/**
+ * Handle an HTTP POST.
+ */
+const failable<int, std::string> post(request_rec* r, const ilambda& impl, const list<value>& px) {
+ const list<std::string> ls = httpd::read(r);
+ httpd::logStrings(ls, "content");
+
+ // Evaluate a JSON-RPC request and return a JSON result
+ const std::string ct = httpd::contentType(r);
+ if (ct.find("application/json-rpc") != std::string::npos || ct.find("text/plain") != std::string::npos) {
+ 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 = std::string(cadr(assoc(value("method"), args))).c_str();
+ const list<value> params = (list<value>)cadr(assoc(value("params"), args));
+
+ // Evaluate the request expression
+ const failable<value, std::string> val = impl(func, append(params, px));
+ if (!hasContent(val))
+ return mkfailure<int, std::string>(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 created resource location
+ if (ct.find("application/atom+xml") != std::string::npos) {
+
+ // Evaluate the request expression
+ const value entry = httpd::feedEntry(content(atom::readEntry(ls)));
+ const failable<value, std::string> val = impl("post", cons<value>(entry, px));
+ if (!hasContent(val))
+ return mkfailure<int, std::string>(reason(val));
+
+ // Return the created resource location
+ apr_table_setn(r->headers_out, "Location", apr_pstrdup(r->pool, httpd::url(content(val), r)));
+ r->status = HTTP_CREATED;
+ return OK;
+ }
+
+ return HTTP_NOT_IMPLEMENTED;
+}
+
+/**
+ * Handle an HTTP PUT.
+ */
+const failable<int, std::string> put(request_rec* r, const ilambda& impl, const list<value>& px) {
+ const list<std::string> ls = httpd::read(r);
+ httpd::logStrings(ls, "content");
+
+ // Evaluate an ATOM PUT request
+ const list<value> id(httpd::path(r->path_info));
+ const value entry = httpd::feedEntry(content(atom::readEntry(ls)));
+ const failable<value, std::string> val = impl("put", append(mklist<value>(entry, car(id)), px));
+ if (!hasContent(val))
+ return mkfailure<int, std::string>(reason(val));
+ if (val == value(false))
+ return HTTP_NOT_FOUND;
+ return OK;
+}
+
+/**
+ * Handle an HTTP DELETE.
+ */
+const failable<int, std::string> del(request_rec* r, const ilambda& impl, const list<value>& px) {
+
+ // Evaluate an ATOM delete request
+ const list<value> id(httpd::path(r->path_info));
+ const failable<value, std::string> val = impl("delete", cons<value>(car(id), px));
+ if (!hasContent(val))
+ return mkfailure<int, std::string>(reason(val));
+ if (val == value(false))
+ return HTTP_NOT_FOUND;
+ return OK;
+}
+
+/**
+ * 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::CURLHandle& ch) {
+ return eval::primitiveProcedure(http::proxy(base + std::string(scdl::name(ref)), ch));
+}
+
+const list<value> proxies(const list<value>& refs, const std::string& base, const http::CURLHandle& 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.
+ */
+const cached<failable<ilambda, std::string> > implementation(const std::string& itype, const std::string& path) {
+ if (itype.find(".scheme") != std::string::npos)
+ return latest(scm::readImplementation(path));
+ if (itype.find(".cpp") != std::string::npos)
+ return latest(cpp::readImplementation(path));
+ return cached<failable<ilambda, std::string> >();
+}
+
+/**
+ * HTTP request handler.
+ */
+int handler(request_rec *r) {
+ if(strcmp(r->handler, "mod_tuscany_eval"))
+ return DECLINED;
+ httpd::logRequest(r, "mod_tuscany_eval::handler");
+
+ // Set up the read policy
+ const int rc = httpd::setupReadPolicy(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) {
+ conf.implementationPath = path;
+ conf.implementation = implementation(elementName(ielement), path);
+ }
+ else
+ conf.implementation = latest(conf.implementation);
+ const failable<ilambda, std::string> impl(content(conf.implementation));
+ if (!hasContent(impl))
+ return HTTP_NOT_FOUND;
+
+ // Convert component references to configured proxy lambdas
+ std::ostringstream base;
+ base << "http://localhost:" << (debugWiringPort == 0? ap_get_server_port(r) : debugWiringPort) << "/references/" << std::string(scdl::name(content(comp))) << "/";
+ http::CURLHandle ch;
+ const list<value> px(proxies(scdl::references(content(comp)), base.str(), ch));
+
+ // Handle HTTP method
+ if (r->header_only)
+ return OK;
+ if(r->method_number == M_GET)
+ return httpd::reportStatus(get(r, content(impl), px));
+ if(r->method_number == M_POST)
+ return httpd::reportStatus(post(r, content(impl), px));
+ if(r->method_number == M_PUT)
+ return httpd::reportStatus(put(r, content(impl), px));
+ if(r->method_number == M_DELETE)
+ return httpd::reportStatus(del(r, content(impl), px));
+ return HTTP_NOT_IMPLEMENTED;
+}
+
+/**
+ * Configuration commands.
+ */
+const char *confHome(cmd_parms *cmd, 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 char *confContribution(cmd_parms *cmd, void *c, const char *arg) {
+ DirConf* conf = (DirConf*)c;
+ conf->contributionPath = arg;
+ conf->component = component(conf);
+ return NULL;
+}
+const char *confComposite(cmd_parms *cmd, void *c, const char *arg) {
+ DirConf* conf = (DirConf*)c;
+ conf->compositeName = arg;
+ conf->component = component(conf);
+ return NULL;
+}
+const char *confComponent(cmd_parms *cmd, void *c, const char *arg) {
+ DirConf* conf = (DirConf*)c;
+ conf->componentName = arg;
+ conf->component = component(conf);
+ 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("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}
+};
+
+int postConfig(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) {
+ return OK;
+}
+
+void childInit(apr_pool_t* p, server_rec* svr_rec) {
+ 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);
+ }
+}
+
+void registerHooks(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);
+}
+
+}
+}
+}
+
+extern "C" {
+
+module AP_MODULE_DECLARE_DATA mod_tuscany_eval = {
+ STANDARD20_MODULE_STUFF,
+ // dir config and merger
+ tuscany::httpd::makeDirConf<tuscany::server::modeval::DirConf>, NULL,
+ // server config and merger
+ tuscany::httpd::makeServerConf<tuscany::server::modeval::ServerConf>, NULL,
+ // commands and hooks
+ tuscany::server::modeval::commands, tuscany::server::modeval::registerHooks
+};
+
+}
diff --git a/sca-cpp/trunk/modules/server/mod-eval.hpp b/sca-cpp/trunk/modules/server/mod-eval.hpp
new file mode 100644
index 0000000000..a350538956
--- /dev/null
+++ b/sca-cpp/trunk/modules/server/mod-eval.hpp
@@ -0,0 +1,50 @@
+/*
+ * 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
new file mode 100644
index 0000000000..386d032695
--- /dev/null
+++ b/sca-cpp/trunk/modules/server/mod-scm.hpp
@@ -0,0 +1,92 @@
+/*
+ * 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_modscm_hpp
+#define tuscany_modscm_hpp
+
+/**
+ * Evaluation functions used by mod-eval to evaluate implementation.scheme
+ * component implementations.
+ */
+
+#include <string>
+#include <iostream>
+#include <fstream>
+
+#include "function.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "cache.hpp"
+#include "../eval/driver.hpp"
+#include "../http/httpd.hpp"
+#include "mod-eval.hpp"
+
+namespace tuscany {
+namespace server {
+namespace modeval {
+namespace scm {
+
+/**
+ * Evaluate a script component implementation function.
+ */
+struct evalImplementation {
+ const value impl;
+ evalImplementation(const value& impl) : impl(impl) {
+ }
+ const failable<value, std::string> operator()(const value& func, const list<value>& params) const {
+ const value expr = cons<value>(func, eval::quotedParameters(params));
+ httpd::logValue(expr, "expr");
+ gc_pool pool;
+ eval::Env globalEnv = eval::setupEnvironment(pool);
+ const value val = eval::evalScript(expr, impl, globalEnv, pool);
+ httpd::logValue(val, "val");
+ if (isNil(val))
+ return mkfailure<value, std::string>("Could not evaluate expression");
+ return val;
+ }
+};
+
+/**
+ * Read a script component implementation.
+ */
+const failable<ilambda, std::string> readLatestImplementation(const std::string path) {
+ 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);
+ const value impl = eval::readScript(is);
+ if (isNil(impl))
+ return mkfailure<ilambda, std::string>("Could not read implementation: " + path);
+ return ilambda(evalImplementation(impl));
+}
+
+const cached<failable<ilambda, std::string> > readImplementation(const std::string& path) {
+ const lambda<failable<ilambda, std::string>(std::string)> ri(readLatestImplementation);
+ const lambda<unsigned long(std::string)> ft(latestFileTime);
+ return cached<failable<ilambda, std::string> >(curry(ri, path), curry(ft, path));
+}
+
+}
+}
+}
+}
+
+#endif /* tuscany_modscm_hpp */
diff --git a/sca-cpp/trunk/modules/http/mod-wiring.cpp b/sca-cpp/trunk/modules/server/mod-wiring.cpp
index 965d5a87fb..2d3c8ce045 100644
--- a/sca-cpp/trunk/modules/http/mod-wiring.cpp
+++ b/sca-cpp/trunk/modules/server/mod-wiring.cpp
@@ -20,7 +20,7 @@
/* $Rev$ $Date$ */
/**
- * HTTPD module used to wire components.
+ * HTTPD module used to wire component references.
*/
#include <sys/stat.h>
@@ -34,16 +34,16 @@
#include "slist.hpp"
#include "value.hpp"
#include "monad.hpp"
+#include "cache.hpp"
#include "../scdl/scdl.hpp"
-#include "../cache/cache.hpp"
-#include "httpd.hpp"
+#include "../http/httpd.hpp"
extern "C" {
extern module AP_MODULE_DECLARE_DATA mod_tuscany_wiring;
}
namespace tuscany {
-namespace httpd {
+namespace server {
namespace modwiring {
/**
@@ -51,15 +51,12 @@ namespace modwiring {
*/
class ServerConf {
public:
- std::string home;
- ServerConf() : home("") {
+ ServerConf(server_rec* s) : home("") {
}
+ server_rec* s;
+ std::string home;
};
-const ServerConf& serverConf(const request_rec* r) {
- return *(ServerConf*)ap_get_module_config(r->server->module_config, &mod_tuscany_wiring);
-}
-
/**
* Set to true to wire using mod_proxy, false to wire using HTTP client redirects.
*/
@@ -70,17 +67,14 @@ const bool useModProxy = true;
*/
class DirConf {
public:
- DirConf() : contributionPath(""), compositeName("") {
+ DirConf(char* dirspec) : contributionPath(""), compositeName("") {
}
+ char* dirspec;
std::string contributionPath;
std::string compositeName;
- cache::cached<failable<list<value>, std::string> > components;
+ cached<failable<list<value>, std::string> > components;
};
-DirConf& dirConf(const request_rec* r) {
- return *(DirConf*)ap_get_module_config(r->per_dir_config, &mod_tuscany_wiring);
-}
-
/**
* Read the SCDL configuration of the deployed components.
*/
@@ -91,11 +85,11 @@ const failable<list<value>, std::string> readComponents(const std::string& path)
return scdl::components(readXML(streamList(is)));
}
-const cache::cached<failable<list<value>, std::string> > components(DirConf* conf) {
+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(cache::latestFileTime);
- return cache::cached<failable<list<value>, std::string> >(curry(rc, path), curry(ft, path));
+ const lambda<unsigned long(std::string)> ft(latestFileTime);
+ return cached<failable<list<value>, std::string> >(curry(rc, path), curry(ft, path));
}
/**
@@ -112,19 +106,16 @@ const bool isAbsolute(const std::string& uri) {
int translate(request_rec *r) {
if (strncmp(r->uri, "/references/", 12) != 0)
return DECLINED;
- const list<value> rpath(path(r->uri));
-
- // Log the request
- if(logRequests)
- logRequest(r, "mod_tuscany_wiring::translate");
+ httpd::logRequest(r, "mod_tuscany_wiring::translate");
// Find the requested component, reference and its target configuration
- DirConf& conf = dirConf(r);
- conf.components = cache::latest(conf.components);
- const failable<list<value>, std::string> comps(conf.components);
- if (!hasValue(comps))
+ 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;
- const value comp(scdl::named(cadr(rpath), list<value>(comps)));
+ const list<value> rpath(httpd::path(r->uri));
+ const value comp(scdl::named(cadr(rpath), list<value>(content(comps))));
if (isNil(comp))
return HTTP_NOT_FOUND;
const value ref(scdl::named(caddr(rpath), scdl::references(comp)));
@@ -174,10 +165,7 @@ const std::string redirect(const std::string& file, const std::string& pi, const
int handler(request_rec *r) {
if(strcmp(r->handler, "mod_tuscany_wiring"))
return DECLINED;
-
- // Log the request
- if(logRequests)
- logRequest(r, "mod_tuscany_wiring::handler");
+ httpd::logRequest(r, "mod_tuscany_wiring::handler");
// Do an internal redirect
if (r->filename == NULL || strncmp(r->filename, "/redirect:", 10) != 0)
@@ -211,17 +199,6 @@ const char *confComposite(cmd_parms *cmd, void *c, const char *arg) {
return NULL;
}
-void *makeDirConf(apr_pool_t *p, char *dirspec) {
- DirConf* c = new (apr_palloc(p, sizeof(DirConf))) DirConf();
- apr_pool_cleanup_register(p, c, gc_pool_cleanupCallback<DirConf>, apr_pool_cleanup_null) ;
- return c;
-}
-void* makeServerConf(apr_pool_t *p, server_rec *s) {
- ServerConf* c = new (apr_palloc(p, sizeof(ServerConf))) ServerConf();
- apr_pool_cleanup_register(p, c, gc_pool_cleanupCallback<ServerConf>, apr_pool_cleanup_null) ;
- return c;
-}
-
/**
* HTTP server module declaration.
*/
@@ -259,18 +236,12 @@ extern "C" {
module AP_MODULE_DECLARE_DATA mod_tuscany_wiring = {
STANDARD20_MODULE_STUFF,
- // dir config
- tuscany::httpd::modwiring::makeDirConf,
- // dir merger, default is to override
- NULL,
- // server config
- tuscany::httpd::modwiring::makeServerConf,
- // merge server config
- NULL,
- // command table
- tuscany::httpd::modwiring::commands,
- // register hooks
- tuscany::httpd::modwiring::registerHooks
+ // dir config and merger
+ tuscany::httpd::makeDirConf<tuscany::server::modwiring::DirConf>, NULL,
+ // server config and merger
+ tuscany::httpd::makeServerConf<tuscany::server::modwiring::ServerConf>, NULL,
+ // commands and hooks
+ tuscany::server::modwiring::commands, tuscany::server::modwiring::registerHooks
};
}
diff --git a/sca-cpp/trunk/modules/server/server-conf b/sca-cpp/trunk/modules/server/server-conf
new file mode 100755
index 0000000000..dfe4265bae
--- /dev/null
+++ b/sca-cpp/trunk/modules/server/server-conf
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+# 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.
+
+# Generate a server conf
+here=`readlink -f $0`; here=`dirname $here`
+root=`readlink -f $1`
+
+mkdir -p $root
+mkdir -p $root/logs
+mkdir -p $root/conf
+cat >>$root/conf/httpd.conf <<EOF
+LoadModule mod_tuscany_eval $here/.libs/libmod_tuscany_eval.so
+LoadModule mod_tuscany_wiring $here/.libs/libmod_tuscany_wiring.so
+LoadModule mod_tuscany_cache $here/.libs/libmod_tuscany_cache.so
+EOF
+
diff --git a/sca-cpp/trunk/modules/http/wiring-test b/sca-cpp/trunk/modules/server/wiring-test
index 0c3f36b513..c50732ddb2 100755
--- a/sca-cpp/trunk/modules/http/wiring-test
+++ b/sca-cpp/trunk/modules/server/wiring-test
@@ -20,7 +20,8 @@
echo "Testing..."
# Setup
-./httpd-conf tmp 8092 htdocs
+../http/httpd-conf tmp 8090 htdocs
+./server-conf tmp
cat >>tmp/conf/httpd.conf <<EOF
<Location /test>
@@ -48,37 +49,37 @@ apachectl -k start -d `pwd`/tmp
sleep 1
# Test HTTP GET
-curl http://localhost:8092/index.html 2>/dev/null >tmp/index.html
+curl http://localhost:8090/index.html 2>/dev/null >tmp/index.html
diff tmp/index.html htdocs/index.html
rc=$?
# Test ATOMPub
if [ "$rc" = "0" ]; then
- curl http://localhost:8092/client/ >tmp/feed.xml 2>/dev/null
+ curl http://localhost:8090/client/ >tmp/feed.xml 2>/dev/null
diff tmp/feed.xml htdocs/feed.xml
rc=$?
fi
if [ "$rc" = "0" ]; then
- curl http://localhost:8092/client/111 >tmp/entry.xml 2>/dev/null
+ curl http://localhost:8090/client/111 >tmp/entry.xml 2>/dev/null
diff tmp/entry.xml htdocs/entry.xml
rc=$?
fi
if [ "$rc" = "0" ]; then
- curl http://localhost:8092/client/ -X POST -H "Content-type: application/atom+xml" --data @htdocs/entry.xml 2>/dev/null
+ curl http://localhost:8090/client/ -X POST -H "Content-type: application/atom+xml" --data @htdocs/entry.xml 2>/dev/null
rc=$?
fi
if [ "$rc" = "0" ]; then
- curl http://localhost:8092/client/111 -X PUT -H "Content-type: application/atom+xml" --data @htdocs/entry.xml 2>/dev/null
+ curl http://localhost:8090/client/111 -X PUT -H "Content-type: application/atom+xml" --data @htdocs/entry.xml 2>/dev/null
rc=$?
fi
if [ "$rc" = "0" ]; then
- curl http://localhost:8092/client/111 -X DELETE 2>/dev/null
+ curl http://localhost:8090/client/111 -X DELETE 2>/dev/null
rc=$?
fi
# Test JSON-RPC
if [ "$rc" = "0" ]; then
- curl http://localhost:8092/client/ -X POST -H "Content-type: application/json-rpc" --data @htdocs/json-request.txt >tmp/json-result.txt 2>/dev/null
+ curl http://localhost:8090/client/ -X POST -H "Content-type: application/json-rpc" --data @htdocs/json-request.txt >tmp/json-result.txt 2>/dev/null
diff tmp/json-result.txt htdocs/json-result.txt
rc=$?
fi