summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68>2009-11-30 08:36:32 +0000
committerjsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68>2009-11-30 08:36:32 +0000
commitff124040623879bc48a0ba5cf06a841642adef53 (patch)
treee0bee552780b0852c10744017b7826b08f57d377
parentcd7dae28b034deebc9c2c2469ed9d8f1f3dab1ed (diff)
Fixes to the http client, httpd modules and memcached component to get the store and shopping cart test case working end to end.
git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@885349 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--sca-cpp/trunk/components/cache/mcache-client-test.cpp138
-rw-r--r--sca-cpp/trunk/components/cache/mcache-test.cpp10
-rw-r--r--sca-cpp/trunk/components/cache/mcache.composite2
-rw-r--r--sca-cpp/trunk/components/cache/mcache.cpp10
-rw-r--r--sca-cpp/trunk/components/cache/mcache.hpp47
-rwxr-xr-xsca-cpp/trunk/components/cache/memcached-server-test47
-rwxr-xr-xsca-cpp/trunk/components/cache/memcached-test6
-rw-r--r--sca-cpp/trunk/modules/atom/atom.hpp14
-rw-r--r--sca-cpp/trunk/modules/http/curl-test.cpp6
-rw-r--r--sca-cpp/trunk/modules/http/curl.hpp166
-rwxr-xr-xsca-cpp/trunk/modules/http/http-test2
-rwxr-xr-xsca-cpp/trunk/modules/http/httpd-test2
-rw-r--r--sca-cpp/trunk/modules/http/httpd.hpp91
-rw-r--r--sca-cpp/trunk/modules/server/client-test.cpp79
-rw-r--r--sca-cpp/trunk/modules/server/client-test.scm (renamed from sca-cpp/trunk/modules/server/httpd-client.scm)0
-rw-r--r--sca-cpp/trunk/modules/server/domain-test.composite (renamed from sca-cpp/trunk/modules/server/httpd-test.composite)19
-rwxr-xr-xsca-cpp/trunk/modules/server/httpd-test6
-rw-r--r--sca-cpp/trunk/modules/server/impl-test.cpp76
-rw-r--r--sca-cpp/trunk/modules/server/mod-cpp.hpp20
-rw-r--r--sca-cpp/trunk/modules/server/mod-eval.cpp104
-rw-r--r--sca-cpp/trunk/modules/server/mod-scm.hpp30
-rwxr-xr-xsca-cpp/trunk/modules/server/server-test (renamed from sca-cpp/trunk/modules/server/http-test)15
-rw-r--r--sca-cpp/trunk/modules/server/server-test.scm (renamed from sca-cpp/trunk/modules/server/httpd-test.scm)0
-rwxr-xr-xsca-cpp/trunk/modules/server/wiring-test14
-rw-r--r--sca-cpp/trunk/test/store-script/currency-converter.scm1
-rw-r--r--sca-cpp/trunk/test/store-script/fruits-catalog.scm4
-rw-r--r--sca-cpp/trunk/test/store-script/htdocs/store.html14
-rw-r--r--sca-cpp/trunk/test/store-script/shopping-cart.scm52
-rwxr-xr-xsca-cpp/trunk/test/store-script/store-composite-test (renamed from sca-cpp/trunk/test/store-script/store-http-test)13
-rw-r--r--sca-cpp/trunk/test/store-script/store.composite10
-rw-r--r--sca-cpp/trunk/test/store-script/store.scm6
31 files changed, 723 insertions, 281 deletions
diff --git a/sca-cpp/trunk/components/cache/mcache-client-test.cpp b/sca-cpp/trunk/components/cache/mcache-client-test.cpp
new file mode 100644
index 0000000000..0a560bc05f
--- /dev/null
+++ b/sca-cpp/trunk/components/cache/mcache-client-test.cpp
@@ -0,0 +1,138 @@
+/*
+ * 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 Memcached access functions.
+ */
+
+#include <assert.h>
+#include <sys/time.h>
+#include <time.h>
+#include <iostream>
+#include <string>
+
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "../../modules/http/curl.hpp"
+
+namespace tuscany {
+namespace cache {
+
+const std::string url("http://localhost:8090/mcache");
+
+bool testCache() {
+ http::CURLSession cs;
+
+ 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);
+
+ const failable<value, std::string> id = http::post(a, url, cs);
+ assert(hasContent(id));
+ {
+ const failable<value, std::string> val = http::get(url + "/" + std::string(content(id)), cs);
+ assert(hasContent(val));
+ assert(content(val) == a);
+ }
+
+ const list<value> j = list<value>()
+ << (list<value>() << "name" << std::string("Apple"))
+ << (list<value>() << "price" << std::string("$3.55"));
+ const list<value> b = mklist<value>(std::string("item"), std::string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), j);
+
+ {
+ const failable<value, std::string> r = http::put(b, url + "/" + std::string(content(id)), cs);
+ assert(hasContent(r));
+ assert(content(r) == value(true));
+ }
+ {
+ const failable<value, std::string> val = http::get(url + "/" + std::string(content(id)), cs);
+ assert(hasContent(val));
+ assert(content(val) == b);
+ }
+ {
+ const failable<value, std::string> r = http::del(url + "/" + std::string(content(id)), cs);
+ assert(hasContent(r));
+ assert(content(r) == value(true));
+ }
+ {
+ const failable<value, std::string> val = http::get(url + "/" + std::string(content(id)), cs);
+ assert(!hasContent(val));
+ }
+
+ return true;
+}
+
+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;
+}
+
+bool testGetLoop(const int count, const value& id, const value& entry, http::CURLSession& cs) {
+ if (count == 0)
+ return true;
+ const failable<value, std::string> val = http::get(url + "/" + std::string(id), cs);
+ assert(hasContent(val));
+ assert(content(val) == entry);
+ return testGetLoop(count - 1, id, entry, cs);
+}
+
+bool testGetPerf() {
+ const int count = 50;
+ struct timeval start;
+ struct timeval end;
+ {
+ const list<value> i = list<value>()
+ << (list<value>() << "name" << std::string("Apple"))
+ << (list<value>() << "price" << std::string("$4.55"));
+ const list<value> a = mklist<value>(std::string("item"), std::string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
+
+ http::CURLSession cs;
+ const failable<value, std::string> id = http::post(a, url, cs);
+ assert(hasContent(id));
+
+ testGetLoop(5, content(id), a, cs);
+
+ gettimeofday(&start, NULL);
+
+ testGetLoop(count, content(id), a, cs);
+
+ gettimeofday(&end, NULL);
+ std::cout << "Cache get test " << duration(start, end, count) << " ms" << std::endl;
+ }
+ return true;
+}
+
+}
+}
+
+int main() {
+ std::cout << "Testing..." << std::endl;
+
+ tuscany::cache::testCache();
+ tuscany::cache::testGetPerf();
+
+ std::cout << "OK" << std::endl;
+
+ return 0;
+}
diff --git a/sca-cpp/trunk/components/cache/mcache-test.cpp b/sca-cpp/trunk/components/cache/mcache-test.cpp
index 3f02b649d6..78f0da0465 100644
--- a/sca-cpp/trunk/components/cache/mcache-test.cpp
+++ b/sca-cpp/trunk/components/cache/mcache-test.cpp
@@ -35,11 +35,11 @@ namespace tuscany {
namespace cache {
bool testMemCached() {
- MemCached ch("localhost", 11311);
+ MemCached ch;
- assert(hasContent(post("a", "AAA", ch)));
+ assert(hasContent(post("a", std::string("AAA"), ch)));
assert(get("a", ch) == value(std::string("AAA")));
- assert(hasContent(put("a", "aaa", ch)));
+ assert(hasContent(put("a", std::string("aaa"), ch)));
assert(get("a", ch) == value(std::string("aaa")));
assert(hasContent(del("a", ch)));
assert(!hasContent(get("a", ch)));
@@ -64,8 +64,8 @@ bool testGetPerf() {
struct timeval start;
struct timeval end;
{
- MemCached ch("localhost", 11311);
- assert(hasContent(post("c", "CCC", ch)));
+ MemCached ch;
+ assert(hasContent(post("c", std::string("CCC"), ch)));
testGetLoop(5, ch);
diff --git a/sca-cpp/trunk/components/cache/mcache.composite b/sca-cpp/trunk/components/cache/mcache.composite
index ccbced6fb4..99364104fb 100644
--- a/sca-cpp/trunk/components/cache/mcache.composite
+++ b/sca-cpp/trunk/components/cache/mcache.composite
@@ -23,7 +23,7 @@
name="mcache">
<component name="mcache">
- <t:implementation.cpp uri="libmcache"/>
+ <t:implementation.cpp uri=".libs/libmcache"/>
<service name="mcache">
<t:binding.http uri="mcache"/>
</service>
diff --git a/sca-cpp/trunk/components/cache/mcache.cpp b/sca-cpp/trunk/components/cache/mcache.cpp
index af51f508e2..b60301bbf2 100644
--- a/sca-cpp/trunk/components/cache/mcache.cpp
+++ b/sca-cpp/trunk/components/cache/mcache.cpp
@@ -20,7 +20,7 @@
/* $Rev$ $Date$ */
/**
- * memcached-based cache component implementation.
+ * Memcached-based cache component implementation.
*/
#include <apr_uuid.h>
@@ -45,6 +45,9 @@ const failable<value, std::string> get(const list<value>& params) {
return cache::get(car(params), ch);
}
+/**
+ * Post an item to the cache.
+ */
const value uuidValue() {
apr_uuid_t uuid;
apr_uuid_get(&uuid);
@@ -53,9 +56,6 @@ const value uuidValue() {
return value(std::string(buf, APR_UUID_FORMATTED_LENGTH));
}
-/**
- * Post an item to the cache.
- */
const failable<value, std::string> post(const list<value>& params) {
const value id = uuidValue();
const failable<bool, std::string> val = cache::post(id, car(params), ch);
@@ -96,7 +96,7 @@ const tuscany::failable<tuscany::value, std::string> eval(const tuscany::value&
return tuscany::cache::post(params);
if (func == "put")
return tuscany::cache::put(params);
- if (func == "del")
+ if (func == "delete")
return tuscany::cache::del(params);
return tuscany::mkfailure<tuscany::value, std::string>(std::string("Function not supported: ") + std::string(func));
}
diff --git a/sca-cpp/trunk/components/cache/mcache.hpp b/sca-cpp/trunk/components/cache/mcache.hpp
index aae298d80d..d1fe182946 100644
--- a/sca-cpp/trunk/components/cache/mcache.hpp
+++ b/sca-cpp/trunk/components/cache/mcache.hpp
@@ -35,9 +35,12 @@
#include "apr_network_io.h"
#include <string>
+#include <sstream>
#include "list.hpp"
#include "value.hpp"
#include "monad.hpp"
+#include "debug.hpp"
+#include "../../modules/eval/eval.hpp"
namespace tuscany {
namespace cache {
@@ -77,7 +80,7 @@ private:
*/
const failable<bool, std::string> init(const std::string& host, const int port) {
apr_memcache_server_t *server;
- const apr_status_t sc = apr_memcache_server_create(pool, host.c_str(), port, 0, 1, 1, 60, &server);
+ const apr_status_t sc = apr_memcache_server_create(pool, host.c_str(), (apr_port_t)port, 0, 1, 1, 60, &server);
if (sc != APR_SUCCESS)
return mkfailure<bool, std::string>("Could not create server");
const apr_status_t as = apr_memcache_add_server(mc, server);
@@ -92,21 +95,33 @@ private:
* Post a new item to the cache.
*/
const failable<bool, std::string> post(const value& key, const value& val, const MemCached& cache) {
- const std::string v(val);
- const apr_status_t rc = apr_memcache_add(cache.mc, std::string(key).c_str(), const_cast<char*>(v.c_str()), v.size(), 0, 27);
+ debug(key, "cache::post::key");
+ debug(val, "cache::post::value");
+
+ const std::string ks(eval::writeValue(key));
+ const std::string vs(eval::writeValue(val));
+ const apr_status_t rc = apr_memcache_add(cache.mc, ks.c_str(), const_cast<char*>(vs.c_str()), vs.size(), 0, 27);
if (rc != APR_SUCCESS)
return mkfailure<bool, std::string>("Could not add entry");
+
+ debug(true, "cache::post::result");
return true;
}
/**
- * Update an item in the cache.
+ * Update an item in the cache. If the item doesn't exist it is added.
*/
const failable<bool, std::string> put(const value& key, const value& val, const MemCached& cache) {
- const std::string v(val);
- const apr_status_t rc = apr_memcache_replace(cache.mc, std::string(key).c_str(), const_cast<char*>(v.c_str()), v.size(), 0, 27);
+ debug(key, "cache::put::key");
+ debug(val, "cache::put::value");
+
+ const std::string ks(eval::writeValue(key));
+ const std::string vs(eval::writeValue(val));
+ const apr_status_t rc = apr_memcache_set(cache.mc, ks.c_str(), const_cast<char*>(vs.c_str()), vs.size(), 0, 27);
if (rc != APR_SUCCESS)
return mkfailure<bool, std::string>("Could not add entry");
+
+ debug(true, "cache::put::result");
return true;
}
@@ -114,6 +129,10 @@ const failable<bool, std::string> put(const value& key, const value& val, const
* Get an item from the cache.
*/
const failable<value, std::string> get(const value& key, const MemCached& cache) {
+ debug(key, "cache::get::key");
+
+ const std::string ks(eval::writeValue(key));
+
apr_pool_t* vpool;
const apr_status_t pc = apr_pool_create(&vpool, cache.pool);
if (pc != APR_SUCCESS)
@@ -121,14 +140,16 @@ const failable<value, std::string> get(const value& key, const MemCached& cache)
char *data;
apr_size_t size;
- const apr_status_t rc = apr_memcache_getp(cache.mc, cache.pool, std::string(key).c_str(), &data, &size, NULL);
+ const apr_status_t rc = apr_memcache_getp(cache.mc, cache.pool, ks.c_str(), &data, &size, NULL);
if (rc != APR_SUCCESS) {
apr_pool_destroy(vpool);
return mkfailure<value, std::string>("Could not get entry");
}
- const value val(std::string(data, size));
+ const value val(eval::readValue(std::string(data, size)));
apr_pool_destroy(vpool);
+
+ debug(val, "cache::get::result");
return val;
}
@@ -136,9 +157,15 @@ const failable<value, std::string> get(const value& key, const MemCached& cache)
* Delete an item from the cache
*/
const failable<bool, std::string> del(const value& key, const MemCached& cache) {
- const apr_status_t rc = apr_memcache_delete(cache.mc, std::string(key).c_str(), 0);
+ debug(key, "cache::delete::key");
+
+ std::ostringstream kos;
+ kos << key;
+ const apr_status_t rc = apr_memcache_delete(cache.mc, kos.str().c_str(), 0);
if (rc != APR_SUCCESS)
- return mkfailure<bool, std::string>("Could not add entry");
+ return mkfailure<bool, std::string>("Could not delete entry");
+
+ debug(true, "cache::delete::result");
return true;
}
diff --git a/sca-cpp/trunk/components/cache/memcached-server-test b/sca-cpp/trunk/components/cache/memcached-server-test
new file mode 100755
index 0000000000..2da53fbdb4
--- /dev/null
+++ b/sca-cpp/trunk/components/cache/memcached-server-test
@@ -0,0 +1,47 @@
+#!/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
+../../modules/http/httpd-conf tmp 8090 ../../modules/http/htdocs
+../../modules/server/server-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+
+<Location /mcache>
+SetHandler mod_tuscany_eval
+SCAContribution `pwd`/
+SCAComposite mcache.composite
+SCAComponent mcache
+</Location>
+EOF
+
+apachectl -k start -d `pwd`/tmp
+
+mc="memcached -l 127.0.0.1 -m 4 -p 11211"
+$mc &
+sleep 1
+
+# Test
+./mcache-client-test
+rc=$?
+
+# Cleanup
+kill `ps -f | grep -v grep | grep "$mc" | awk '{ print $2 }'`
+apachectl -k stop -d `pwd`/tmp
+sleep 1
+return $rc
diff --git a/sca-cpp/trunk/components/cache/memcached-test b/sca-cpp/trunk/components/cache/memcached-test
index 6ca779cce5..df21d32a57 100755
--- a/sca-cpp/trunk/components/cache/memcached-test
+++ b/sca-cpp/trunk/components/cache/memcached-test
@@ -18,8 +18,8 @@
# under the License.
# Setup
-cmd="memcached -l 127.0.0.1 -m 4 -p 11311"
-$cmd &
+mc="memcached -l 127.0.0.1 -m 4 -p 11211"
+$mc &
sleep 1
# Test
@@ -27,5 +27,5 @@ sleep 1
rc=$?
# Cleanup
-ps -f | grep -v grep | grep "$cmd" | awk '{ print $2 }' | xargs kill
+kill `ps -f | grep -v grep | grep "$mc" | awk '{ print $2 }'`
return $rc
diff --git a/sca-cpp/trunk/modules/atom/atom.hpp b/sca-cpp/trunk/modules/atom/atom.hpp
index ac19b93e38..22489fd1d1 100644
--- a/sca-cpp/trunk/modules/atom/atom.hpp
+++ b/sca-cpp/trunk/modules/atom/atom.hpp
@@ -38,7 +38,7 @@ namespace atom {
/**
* Convert a list of elements to a list of values representing an ATOM entry.
*/
-const list<value> entryValue(const list<value>& e) {
+const list<value> entryValues(const list<value>& e) {
const list<value> lt = filter<value>(selector(mklist<value>(element, "title")), e);
const value t = isNil(lt)? value(std::string("")) : elementValue(car(lt));
const list<value> li = filter<value>(selector(mklist<value>(element, "id")), e);
@@ -53,7 +53,7 @@ const list<value> entryValue(const list<value>& e) {
const list<value> entriesValues(const list<value>& e) {
if (isNil(e))
return e;
- return cons<value>(entryValue(car(e)), entriesValues(cdr(e)));
+ return cons<value>(entryValues(car(e)), entriesValues(cdr(e)));
}
/**
@@ -63,7 +63,15 @@ const failable<list<value>, std::string> readEntry(const list<std::string>& ilis
const list<value> e = readXML(ilist);
if (isNil(e))
return mkfailure<list<value>, std::string>("Empty entry");
- return entryValue(car(e));
+ return entryValues(car(e));
+}
+
+/**
+ * Convert a list of values representing an ATOM entry to a value.
+ */
+const value entryValue(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))));
}
/**
diff --git a/sca-cpp/trunk/modules/http/curl-test.cpp b/sca-cpp/trunk/modules/http/curl-test.cpp
index 0a6fbcd8a6..59944546a1 100644
--- a/sca-cpp/trunk/modules/http/curl-test.cpp
+++ b/sca-cpp/trunk/modules/http/curl-test.cpp
@@ -50,7 +50,7 @@ std::ostringstream* curlWriter(const std::string& s, std::ostringstream* os) {
}
const bool testGet() {
- CURLHandle ch;
+ CURLSession ch;
{
std::ostringstream os;
const failable<list<std::ostringstream*>, std::string> r = get<std::ostringstream*>(curlWriter, &os, "http://localhost:8090", ch);
@@ -66,7 +66,7 @@ const bool testGet() {
return true;
}
-const bool testGetLoop(const int count, CURLHandle& ch) {
+const bool testGetLoop(const int count, CURLSession& ch) {
if (count == 0)
return true;
const failable<value, std::string> r = get("http://localhost:8090", ch);
@@ -77,7 +77,7 @@ const bool testGetLoop(const int count, CURLHandle& ch) {
const bool testGetPerf() {
const int count = 50;
- CURLHandle ch;
+ CURLSession ch;
struct timeval start;
struct timeval end;
{
diff --git a/sca-cpp/trunk/modules/http/curl.hpp b/sca-cpp/trunk/modules/http/curl.hpp
index 6c3a3a47dc..fd2e9857d1 100644
--- a/sca-cpp/trunk/modules/http/curl.hpp
+++ b/sca-cpp/trunk/modules/http/curl.hpp
@@ -30,6 +30,7 @@
#include <curl/types.h>
#include <curl/easy.h>
#include <string>
+#include "gc.hpp"
#include "list.hpp"
#include "value.hpp"
#include "element.hpp"
@@ -41,11 +42,6 @@ namespace tuscany {
namespace http {
/**
- * Set to true to log HTTP content.
- */
-bool logContent = false;
-
-/**
* CURL library context, one per process.
*/
class CURLContext {
@@ -63,22 +59,45 @@ CURLContext curlContext;
/**
* Represents a CURL session handle.
*/
-class CURLHandle {
+class CURLSession {
public:
- CURLHandle() : h(curl_easy_init()) {
+ CURLSession() : ch(new CURLHandle()) {
}
- ~CURLHandle() {
- curl_easy_cleanup(h);
+
+ ~CURLSession() {
}
- operator CURL*() const {
- return h;
+ CURLSession(const CURLSession& c) : ch(c.ch) {
}
+
private:
- CURL* h;
+ class CURLHandle {
+ public:
+ CURLHandle() : h(curl_easy_init()) {
+ }
+ ~CURLHandle() {
+ curl_easy_cleanup(h);
+ h = NULL;
+ }
+ private:
+ CURL* h;
+
+ friend CURL* handle(const CURLSession& c);
+ };
+
+ const gc_ptr<CURLHandle> ch;
+
+ friend CURL* handle(const CURLSession& c);
};
/**
+ * Returns the CURL handle used by a CURL session.
+ */
+CURL* handle(const CURLSession& c) {
+ return c.ch->h;
+}
+
+/**
* Context passed to the read callback function.
*/
class CURLReadContext {
@@ -143,9 +162,10 @@ curl_slist* headers(curl_slist* cl, const list<std::string>& h) {
return headers(curl_slist_append(cl, std::string(car(h)).c_str()), cdr(h));
}
-template<typename R> const failable<list<R>, std::string> apply(const list<list<std::string> >& req, const lambda<R(std::string, R)>& reduce, const R& initial, const std::string& url, const std::string& verb, const CURLHandle& ch) {
+template<typename R> const failable<list<R>, std::string> apply(const list<list<std::string> >& req, const lambda<R(std::string, R)>& reduce, const R& initial, const std::string& url, const std::string& verb, const CURLSession& cs) {
// Init the curl session
+ CURL* ch = handle(cs);
curl_easy_reset(ch);
curl_easy_setopt(ch, CURLOPT_USERAGENT, "libcurl/1.0");
@@ -204,7 +224,9 @@ template<typename R> const failable<list<R>, std::string> apply(const list<list<
/**
* Evaluate an expression remotely, at the given URL.
*/
-const failable<value, std::string> evalExpr(const value& expr, const std::string& url, const CURLHandle& ch) {
+const failable<value, std::string> evalExpr(const value& expr, const std::string& url, const CURLSession& ch) {
+ debug(url, "http::evalExpr::url");
+ debug(expr, "http::evalExpr::input");
// Convert expression to a JSON-RPC request
json::JSONContext cx;
@@ -212,13 +234,6 @@ const failable<value, std::string> evalExpr(const value& expr, const std::string
if (!hasContent(jsreq))
return mkfailure<value, std::string>(reason(jsreq));
- if (logContent) {
- std::cout<< "content: " << std::endl;
- 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, content(jsreq)), rcons<std::string>, list<std::string>(), url, "POST", ch);
@@ -226,19 +241,58 @@ const failable<value, std::string> evalExpr(const value& expr, const std::string
return mkfailure<value, std::string>(reason(res));
// Return result
- if (logContent) {
- std::cout << "content:" << std::endl;
- write(cadr<list<std::string> >(content(res)), std::cout);
- std::cout << std::endl;
- }
- const list<value> val = elementsToValues(content(json::readJSON(cadr<list<std::string> >(content(res)), cx)));
- return cadr<value>(cadr<value>(val));
+ failable<list<value>, std::string> jsres = json::readJSON(cadr<list<std::string> >(content(res)), cx);
+ if (!hasContent(jsres))
+ return mkfailure<value, std::string>(reason(jsres));
+ const list<value> val = elementsToValues(content(jsres));
+
+ const value rval(cadr<value>(cadr<value>(val)));
+ debug(rval, "http::evalExpr::result");
+ return rval;
+}
+
+/**
+ * Find and return a header.
+ */
+const failable<std::string, std::string> header(const std::string& prefix, const list<std::string>& h) {
+ if (isNil(h))
+ return mkfailure<std::string, std::string>(std::string("Couldn't find header: ") + prefix);
+ const std::string s = car(h);
+ if (s.find(prefix) != 0)
+ return header(prefix, cdr(h));
+ const std::string l(s.substr(prefix.length()));
+ return l.substr(0, l.find_first_of("\r\n"));
+}
+
+/**
+ * Find and return a location header.
+ */
+const failable<std::string, std::string> location(const list<std::string>& h) {
+ return header("Location: ", h);
+}
+
+/**
+ * Convert a location to an entry id.
+ */
+const failable<value, std::string> entryId(const failable<std::string, std::string> l) {
+ if (!hasContent(l))
+ return mkfailure<value, std::string>(reason(l));
+ const std::string ls(content(l));
+ return value(ls.substr(ls.find_last_of("/") + 1));
+}
+
+/**
+ * Find and return a content-type header.
+ */
+const failable<std::string, std::string> contentType(const list<std::string>& h) {
+ return header("Content-Type: ", h);
}
/**
* HTTP GET, return the resource at the given URL.
*/
-template<typename R> const failable<list<R>, std::string> get(const lambda<R(std::string, R)>& reduce, const R& initial, const std::string& url, const CURLHandle& ch) {
+template<typename R> const failable<list<R>, std::string> get(const lambda<R(std::string, R)>& reduce, const R& initial, const std::string& url, const CURLSession& ch) {
+ debug(url, "http::get::url");
const list<list<std::string> > req = mklist(list<std::string>(), list<std::string>());
return apply(req, reduce, initial, url, "GET", ch);
}
@@ -246,38 +300,41 @@ template<typename R> const failable<list<R>, std::string> get(const lambda<R(std
/**
* HTTP GET, return a list of values representing the resource at the given URL.
*/
-const failable<value, std::string> get(const std::string& url, const CURLHandle& ch) {
+const failable<value, std::string> get(const std::string& url, const CURLSession& ch) {
+ debug(url, "http::get::url");
// 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 (!hasContent(res))
return mkfailure<value, std::string>(reason(res));
+ const list<std::string> ls(reverse(cadr(content(res))));
- const std::string ct;
- if (ct.find("application/atom+xml") != std::string::npos) {
- // TODO Return an ATOM feed
+ const std::string ct(content(contentType(car(content(res)))));
+ if (ct == "application/atom+xml;type=entry") {
+ const value val(atom::entryValue(content(atom::readEntry(ls))));
+ debug(val, "http::get::result");
+ return val;
}
// Return the content as a string value
std::ostringstream os;
- write(reverse(cadr(content(res))), os);
- return value(os.str());
+ write(ls, os);
+ const value val(os.str());
+ debug(val, "http::get::result");
+ return val;
}
/**
* HTTP POST.
*/
-const failable<value, std::string> post(const value& val, const std::string& url, const CURLHandle& ch) {
+const failable<value, std::string> post(const value& val, const std::string& url, const CURLSession& ch) {
// Convert value to an ATOM entry
const failable<list<std::string>, std::string> entry = atom::writeATOMEntry(atom::entryValuesToElements(val));
if (!hasContent(entry))
return mkfailure<value, std::string>(reason(entry));
- if (logContent) {
- std::cout << "content:" << std::endl;
- write(list<std::string>(content(entry)), std::cout);
- std::cout << std::endl;
- }
+ debug(url, "http::post::url");
+ debug(content(entry), "http::post::input");
// POST it to the URL
const list<std::string> h = mklist<std::string>("Content-Type: application/atom+xml");
@@ -285,23 +342,24 @@ const failable<value, std::string> post(const value& val, const std::string& url
const failable<list<list<std::string> >, std::string> res = apply<list<std::string> >(req, rcons<std::string>, list<std::string>(), url, "POST", ch);
if (!hasContent(res))
return mkfailure<value, std::string>(reason(res));
- return value(true);
+
+ // Return the new entry id from the HTTP location header
+ const failable<value, std::string> eid(entryId(location(car(content(res)))));
+ debug(eid, "http::post::result");
+ return eid;
}
/**
* HTTP PUT.
*/
-const failable<value, std::string> put(const value& val, const std::string& url, const CURLHandle& ch) {
+const failable<value, std::string> put(const value& val, const std::string& url, const CURLSession& ch) {
// Convert value to an ATOM entry
const failable<list<std::string>, std::string> entry = atom::writeATOMEntry(atom::entryValuesToElements(val));
if (!hasContent(entry))
return mkfailure<value, std::string>(reason(entry));
- if (logContent) {
- std::cout << "content:" << std::endl;
- write(list<std::string>(content(entry)), std::cout);
- std::cout << std::endl;
- }
+ debug(url, "http::put::url");
+ debug(content(entry), "http::put::input");
// PUT it to the URL
const list<std::string> h = mklist<std::string>("Content-Type: application/atom+xml");
@@ -309,17 +367,23 @@ const failable<value, std::string> put(const value& val, const std::string& url,
const failable<list<list<std::string> >, std::string> res = apply<list<std::string> >(req, rcons<std::string>, list<std::string>(), url, "PUT", ch);
if (!hasContent(res))
return mkfailure<value, std::string>(reason(res));
+
+ debug(true, "http::put::result");
return value(true);
}
/**
* HTTP DELETE.
*/
-const failable<value, std::string> del(const std::string& url, const CURLHandle& ch) {
+const failable<value, std::string> del(const std::string& url, const CURLSession& ch) {
+ debug(url, "http::delete::url");
+
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 (!hasContent(res))
return mkfailure<value, std::string>(reason(res));
+
+ debug(true, "http::delete::result");
return value(true);
}
@@ -327,7 +391,7 @@ const failable<value, std::string> del(const std::string& url, const CURLHandle&
* HTTP client proxy function.
*/
struct proxy {
- proxy(const std::string& url, const CURLHandle& ch) : url(url), ch(ch) {
+ proxy(const std::string& url, const CURLSession& ch) : url(url), ch(ch) {
}
const value operator()(const list<value>& args) const {
@@ -338,7 +402,7 @@ struct proxy {
}
const std::string url;
- const CURLHandle& ch;
+ const CURLSession ch;
};
}
diff --git a/sca-cpp/trunk/modules/http/http-test b/sca-cpp/trunk/modules/http/http-test
index 1ab0da64b9..0aaaec48df 100755
--- a/sca-cpp/trunk/modules/http/http-test
+++ b/sca-cpp/trunk/modules/http/http-test
@@ -28,5 +28,5 @@ rc=$?
# Cleanup
apachectl -k stop -d `pwd`/tmp
-sleep 2
+sleep 1
return $rc
diff --git a/sca-cpp/trunk/modules/http/httpd-test b/sca-cpp/trunk/modules/http/httpd-test
index 57c35c5cc9..8e1d681d84 100755
--- a/sca-cpp/trunk/modules/http/httpd-test
+++ b/sca-cpp/trunk/modules/http/httpd-test
@@ -31,7 +31,7 @@ rc=$?
# Cleanup
apachectl -k stop -d `pwd`/tmp
-sleep 2
+sleep 1
if [ "$rc" = "0" ]; then
echo "OK"
fi
diff --git a/sca-cpp/trunk/modules/http/httpd.hpp b/sca-cpp/trunk/modules/http/httpd.hpp
index a9ced05208..05b959f1d2 100644
--- a/sca-cpp/trunk/modules/http/httpd.hpp
+++ b/sca-cpp/trunk/modules/http/httpd.hpp
@@ -50,18 +50,13 @@
#include "list.hpp"
#include "value.hpp"
+#include "debug.hpp"
namespace tuscany {
namespace httpd {
/**
- * Set to true to log requests and content.
- */
-bool logRequests = false;
-bool logContent = false;
-
-/**
* Returns a server-scoped module configuration.
*/
template<typename C> void* makeServerConf(apr_pool_t *p, server_rec *s) {
@@ -120,7 +115,7 @@ const std::string path(const list<value>& p) {
*/
const char* optional(const char* s) {
if (s == NULL)
- return "(null)";
+ return "";
return s;
}
@@ -128,59 +123,40 @@ const std::string contentType(const request_rec* r) {
return optional(apr_table_get(r->headers_in, "Content-Type"));
}
+#ifdef _DEBUG
+
/**
- * Log HTTP request info.
+ * Debug log.
*/
-int logHeader(void* r, const char* key, const char* value) {
- std::cout << "header key: " << key << ", value: " << value << std::endl;
+int debugHeader(unused void* r, const char* key, const char* value) {
+ std::cerr << " header key: " << key << ", value: " << value << std::endl;
return 1;
}
-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;
- std::cout << "method number: " << r->method_number << std::endl;
- std::cout << "content type: " << contentType(r) << std::endl;
- std::cout << "content encoding: " << optional(r->content_encoding) << std::endl;
- apr_table_do(logHeader, r, r->headers_in, NULL);
- std::cout << "uri: " << optional(r->unparsed_uri) << std::endl;
- std::cout << "path: " << optional(r->uri) << std::endl;
- std::cout << "path info: " << optional(r->path_info) << std::endl;
- std::cout << "filename: " << optional(r->filename) << std::endl;
- std::cout << "path tokens: " << pathTokens(r->uri) << std::endl;
- std::cout << "args: " << optional(r->args) << std::endl;
- std::cout.flush();
+const bool debugRequest(request_rec* r, const std::string& msg) {
+ std::cerr << msg << ":" << std::endl;
+ std::cerr << " protocol: " << optional(r->protocol) << std::endl;
+ std::cerr << " method: " << optional(r->method) << std::endl;
+ std::cerr << " method number: " << r->method_number << std::endl;
+ std::cerr << " content type: " << contentType(r) << std::endl;
+ std::cerr << " content encoding: " << optional(r->content_encoding) << std::endl;
+ apr_table_do(debugHeader, r, r->headers_in, NULL);
+ std::cerr << " uri: " << optional(r->unparsed_uri) << std::endl;
+ std::cerr << " path: " << optional(r->uri) << std::endl;
+ std::cerr << " path info: " << optional(r->path_info) << std::endl;
+ std::cerr << " filename: " << optional(r->filename) << std::endl;
+ std::cerr << " path tokens: " << pathTokens(r->uri) << std::endl;
+ std::cerr << " args: " << optional(r->args) << std::endl;
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;
-}
+#define httpdDebugRequest(r, msg) httpd::debugRequest(r, msg)
-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;
-}
+#else
-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;
-}
+#define httpdDebugRequest(r, msg)
+
+#endif
/**
* Returns a list of key value pairs from the args in a query string.
@@ -256,14 +232,6 @@ const char* url(const value& v, request_rec* 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) {
@@ -271,10 +239,7 @@ const failable<int, std::string> writeResult(const failable<list<std::string>, s
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();
- }
+ debug(os.str(), "httpd::result");
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");
@@ -283,7 +248,7 @@ const failable<int, std::string> writeResult(const failable<list<std::string>, s
r->status = HTTP_NOT_MODIFIED;
return OK;
}
- ap_set_content_type(r, ct.c_str());
+ ap_set_content_type(r, apr_pstrdup(r->pool, ct.c_str()));
ap_rputs(std::string(os.str()).c_str(), r);
return OK;
}
diff --git a/sca-cpp/trunk/modules/server/client-test.cpp b/sca-cpp/trunk/modules/server/client-test.cpp
index b43cb92c52..5888c481e3 100644
--- a/sca-cpp/trunk/modules/server/client-test.cpp
+++ b/sca-cpp/trunk/modules/server/client-test.cpp
@@ -50,7 +50,7 @@ std::ostringstream* curlWriter(const std::string& s, std::ostringstream* os) {
}
const bool testGet() {
- http::CURLHandle ch;
+ http::CURLSession ch;
{
std::ostringstream os;
const failable<list<std::ostringstream*>, std::string> r = http::get<std::ostringstream*>(curlWriter, &os, "http://localhost:8090", ch);
@@ -66,7 +66,7 @@ const bool testGet() {
return true;
}
-const bool testGetLoop(const int count, http::CURLHandle& ch) {
+const bool testGetLoop(const int count, http::CURLSession& ch) {
if (count == 0)
return true;
const failable<value, std::string> r = get("http://localhost:8090", ch);
@@ -77,16 +77,13 @@ const bool testGetLoop(const int count, http::CURLHandle& ch) {
const bool testGetPerf() {
const int count = 50;
- http::CURLHandle ch;
+ http::CURLSession 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;
}
@@ -94,13 +91,13 @@ const bool testGetPerf() {
}
const bool testEval() {
- http::CURLHandle ch;
+ http::CURLSession 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) {
+const bool testEvalLoop(const int count, http::CURLSession& 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));
@@ -111,7 +108,7 @@ const bool testEvalLoop(const int count, http::CURLHandle& 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) {
+const bool testBlobEvalLoop(const int count, http::CURLSession& ch) {
if (count == 0)
return true;
const value val = content(http::evalExpr(mklist<value>(std::string("echo"), blobs), "http://localhost:8090/test", ch));
@@ -121,26 +118,20 @@ const bool testBlobEvalLoop(const int count, http::CURLHandle& ch) {
const bool testEvalPerf() {
const int count = 50;
- http::CURLHandle ch;
+ http::CURLSession 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;
}
@@ -156,23 +147,23 @@ bool testPost() {
<< (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));
+ http::CURLSession ch;
+ const failable<value, std::string> id = http::post(a, "http://localhost:8090/test", ch);
+ assert(hasContent(id));
return true;
}
-const bool testPostLoop(const int count, const value& val, http::CURLHandle& ch) {
+const bool testPostLoop(const int count, const value& val, http::CURLSession& ch) {
if (count == 0)
return true;
- const value rc = content(http::post(val, "http://localhost:8090/test", ch));
- assert(rc == value(true));
+ const failable<value, std::string> id = http::post(val, "http://localhost:8090/test", ch);
+ assert(hasContent(id));
return testPostLoop(count - 1, val, ch);
}
const bool testPostPerf() {
const int count = 50;
- http::CURLHandle ch;
+ http::CURLSession ch;
struct timeval start;
struct timeval end;
{
@@ -181,11 +172,8 @@ const bool testPostPerf() {
<< (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;
}
@@ -200,11 +188,8 @@ const bool testPostPerf() {
<< (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;
}
@@ -216,19 +201,49 @@ const bool testPut() {
<< (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;
+ http::CURLSession 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;
+ http::CURLSession ch;
value rc = content(http::del("http://localhost:8090/test/123456789", ch));
assert(rc == value(true));
return true;
}
+const bool testEvalCpp() {
+ http::CURLSession ch;
+ const value val = content(http::evalExpr(mklist<value>(std::string("hello"), std::string("world")), "http://localhost:8090/cpp", ch));
+ assert(val == std::string("hello world"));
+ return true;
+}
+
+const bool testEvalCppLoop(const int count, http::CURLSession& ch) {
+ if (count == 0)
+ return true;
+ const value val = content(http::evalExpr(mklist<value>(std::string("hello"), std::string("world")), "http://localhost:8090/cpp", ch));
+ assert(val == std::string("hello world"));
+ return testEvalCppLoop(count - 1, ch);
+}
+
+const bool testEvalCppPerf() {
+ const int count = 50;
+ http::CURLSession ch;
+ struct timeval start;
+ struct timeval end;
+ {
+ testEvalCppLoop(5, ch);
+ gettimeofday(&start, NULL);
+ testEvalCppLoop(count, ch);
+ gettimeofday(&end, NULL);
+ std::cout << "JSON-RPC C++ eval test " << duration(start, end, count) << " ms" << std::endl;
+ }
+ return true;
+}
+
}
}
@@ -244,6 +259,8 @@ int main() {
tuscany::server::testFeed();
tuscany::server::testPut();
tuscany::server::testDel();
+ tuscany::server::testEvalCpp();
+ tuscany::server::testEvalCppPerf();
std::cout << "OK" << std::endl;
diff --git a/sca-cpp/trunk/modules/server/httpd-client.scm b/sca-cpp/trunk/modules/server/client-test.scm
index 12275693f4..12275693f4 100644
--- a/sca-cpp/trunk/modules/server/httpd-client.scm
+++ b/sca-cpp/trunk/modules/server/client-test.scm
diff --git a/sca-cpp/trunk/modules/server/httpd-test.composite b/sca-cpp/trunk/modules/server/domain-test.composite
index 875d26ae1b..48570e64d3 100644
--- a/sca-cpp/trunk/modules/server/httpd-test.composite
+++ b/sca-cpp/trunk/modules/server/domain-test.composite
@@ -19,18 +19,25 @@
-->
<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200903"
xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
- targetNamespace="http://test"
- name="httpd-test">
+ targetNamespace="http://domain/test"
+ name="domain-test">
- <component name="httpd-test">
- <t:implementation.scheme uri="httpd-test.scm"/>
+ <component name="server-test">
+ <t:implementation.scheme uri="server-test.scm"/>
<service name="test">
<t:binding.http uri="test"/>
</service>
</component>
- <component name="httpd-client">
- <t:implementation.scheme uri="httpd-client.scm"/>
+ <component name="cpp-test">
+ <t:implementation.cpp uri=".libs/libimpl-test"/>
+ <service name="cpp">
+ <t:binding.http uri="cpp"/>
+ </service>
+ </component>
+
+ <component name="client-test">
+ <t:implementation.scheme uri="client-test.scm"/>
<service name="client">
<t:binding.http uri="client"/>
</service>
diff --git a/sca-cpp/trunk/modules/server/httpd-test b/sca-cpp/trunk/modules/server/httpd-test
index 7fa2112f75..2f50c9f3c3 100755
--- a/sca-cpp/trunk/modules/server/httpd-test
+++ b/sca-cpp/trunk/modules/server/httpd-test
@@ -27,8 +27,8 @@ cat >>tmp/conf/httpd.conf <<EOF
<Location /test>
SetHandler mod_tuscany_eval
SCAContribution `pwd`/
-SCAComposite httpd-test.composite
-SCAComponent httpd-test
+SCAComposite domain-test.composite
+SCAComponent server-test
</Location>
EOF
@@ -73,7 +73,7 @@ fi
# Cleanup
apachectl -k stop -d `pwd`/tmp
-sleep 2
+sleep 1
if [ "$rc" = "0" ]; then
echo "OK"
fi
diff --git a/sca-cpp/trunk/modules/server/impl-test.cpp b/sca-cpp/trunk/modules/server/impl-test.cpp
new file mode 100644
index 0000000000..217c6f5171
--- /dev/null
+++ b/sca-cpp/trunk/modules/server/impl-test.cpp
@@ -0,0 +1,76 @@
+/*
+ * 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 component implementation.
+ */
+
+#include <string>
+
+#include "function.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "debug.hpp"
+
+namespace tuscany {
+namespace server {
+
+const failable<value, std::string> get(unused const list<value>& params) {
+ return value(std::string("Hey"));
+}
+
+const failable<value, std::string> post(unused const list<value>& params) {
+ return value(std::string("1234"));
+}
+
+const failable<value, std::string> put(unused const list<value>& params) {
+ return value(true);
+}
+
+const failable<value, std::string> del(unused const list<value>& params) {
+ return value(true);
+}
+
+const failable<value, std::string> hello(const list<value>& params) {
+ return value("hello " + std::string(car(params)));
+}
+
+}
+}
+
+extern "C" {
+
+const tuscany::failable<tuscany::value, std::string> eval(const tuscany::value& func, const tuscany::list<tuscany::value>& params) {
+ if (func == "get")
+ return tuscany::server::get(params);
+ if (func == "post")
+ return tuscany::server::post(params);
+ if (func == "put")
+ return tuscany::server::put(params);
+ if (func == "del")
+ return tuscany::server::del(params);
+ if (func == "hello")
+ return tuscany::server::hello(params);
+ return tuscany::mkfailure<tuscany::value, std::string>(std::string("Function not supported: ") + std::string(func));
+}
+
+}
diff --git a/sca-cpp/trunk/modules/server/mod-cpp.hpp b/sca-cpp/trunk/modules/server/mod-cpp.hpp
index cb24b76f6c..99b69a0d9f 100644
--- a/sca-cpp/trunk/modules/server/mod-cpp.hpp
+++ b/sca-cpp/trunk/modules/server/mod-cpp.hpp
@@ -34,6 +34,7 @@
#include "function.hpp"
#include "list.hpp"
#include "value.hpp"
+#include "debug.hpp"
#include "monad.hpp"
#include "dynlib.hpp"
#include "cache.hpp"
@@ -52,12 +53,13 @@ namespace cpp {
struct evalImplementation {
const lib ilib;
const ilambda impl;
- evalImplementation(const lib& ilib, const ilambda& impl) : ilib(ilib), impl(impl) {
+ const list<value> px;
+ evalImplementation(const lib& ilib, const ilambda& impl, const list<value>& px) : ilib(ilib), impl(impl), px(px) {
}
const failable<value, std::string> operator()(const value& func, const list<value>& params) const {
- httpd::logValue(cons<value>(func, params), "expr");
- const failable<value, std::string> val = impl(func, params);
- httpd::logValue(content(val), "val");
+ debug(cons<value>(func, params), "modeval::cpp::evalImplementation::input");
+ const failable<value, std::string> val = impl(func, append(params, px));
+ debug(content(val), "modeval::cpp::evalImplementation::result");
return val;
}
};
@@ -65,7 +67,7 @@ struct evalImplementation {
/**
* Read a C++ component implementation.
*/
-const failable<ilambda, std::string> readLatestImplementation(const std::string path) {
+const failable<ilambda, std::string> readLatestImplementation(const std::string path, const list<value>& px) {
const failable<lib, std::string> ilib(dynlib(path));
if (!hasContent(ilib))
return mkfailure<ilambda, std::string>(reason(ilib));
@@ -73,14 +75,14 @@ const failable<ilambda, std::string> readLatestImplementation(const std::string
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)));
+ return ilambda(evalImplementation(content(ilib), content(impl), px));
}
-const cached<failable<ilambda, std::string> > readImplementation(const std::string& path) {
- const lambda<failable<ilambda, std::string>(std::string)> ri(readLatestImplementation);
+const cached<failable<ilambda, std::string> > readImplementation(const std::string& path, const list<value>& px) {
+ const lambda<failable<ilambda, std::string>(std::string, list<value>)> ri(readLatestImplementation);
const lambda<unsigned long(std::string)> ft(latestFileTime);
const std::string p(path + dynlibExt);
- return cached<failable<ilambda, std::string> >(curry(ri, p), curry(ft, p));
+ return cached<failable<ilambda, std::string> >(curry(ri, p, px), curry(ft, p));
}
}
diff --git a/sca-cpp/trunk/modules/server/mod-eval.cpp b/sca-cpp/trunk/modules/server/mod-eval.cpp
index f843b9bdc5..aa0a6067a1 100644
--- a/sca-cpp/trunk/modules/server/mod-eval.cpp
+++ b/sca-cpp/trunk/modules/server/mod-eval.cpp
@@ -57,10 +57,11 @@ namespace modeval {
*/
class ServerConf {
public:
- ServerConf(server_rec* s) : s(s), home("") {
+ ServerConf(server_rec* s) : s(s), home(""), wiringHost("") {
}
- server_rec* s;
+ const server_rec* s;
std::string home;
+ std::string wiringHost;
};
/**
@@ -77,7 +78,7 @@ class DirConf {
public:
DirConf(char* dirspec) : dirspec(dirspec), contributionPath(""), compositeName(""), componentName(""), implementationPath("") {
}
- char* dirspec;
+ const char* dirspec;
std::string contributionPath;
std::string compositeName;
std::string componentName;
@@ -89,7 +90,8 @@ public:
/**
* Handle an HTTP GET.
*/
-const failable<int, std::string> get(request_rec* r, const ilambda& impl, const list<value>& px) {
+const failable<int, std::string> get(request_rec* r, const ilambda& impl) {
+ debug(r->uri, "modeval::get::url");
// Inspect the query string
const list<list<value> > args = httpd::queryArgs(r);
@@ -105,7 +107,7 @@ const failable<int, std::string> get(request_rec* r, const ilambda& impl, const
const list<value> params = httpd::queryParams(args);
// Apply the requested function
- const failable<value, std::string> val = impl(func, append(params, px));
+ const failable<value, std::string> val = impl(func, params);
if (!hasContent(val))
return mkfailure<int, std::string>(reason(val));
@@ -117,14 +119,14 @@ const failable<int, std::string> get(request_rec* r, const ilambda& impl, const
// 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);
+ const failable<value, std::string> val = impl("getall", list<value>());
if (!hasContent(val))
return mkfailure<int, std::string>(reason(val));
return httpd::writeResult(atom::writeATOMFeed(atom::feedValuesToElements(content(val))), "application/atom+xml;type=feed", r);
}
// Evaluate an ATOM GET and return an ATOM entry
- const failable<value, std::string> val = impl("get", cons<value>(car(id), px));
+ const failable<value, std::string> val = impl("get", mklist<value>(car(id)));
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);
@@ -133,9 +135,10 @@ const failable<int, std::string> get(request_rec* r, const ilambda& impl, const
/**
* Handle an HTTP POST.
*/
-const failable<int, std::string> post(request_rec* r, const ilambda& impl, const list<value>& px) {
+const failable<int, std::string> post(request_rec* r, const ilambda& impl) {
const list<std::string> ls = httpd::read(r);
- httpd::logStrings(ls, "content");
+ debug(r->uri, "modeval::post::url");
+ debug(ls, "modeval::post::input");
// Evaluate a JSON-RPC request and return a JSON result
const std::string ct = httpd::contentType(r);
@@ -150,7 +153,7 @@ const failable<int, std::string> post(request_rec* r, const ilambda& impl, const
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));
+ const failable<value, std::string> val = impl(func, params);
if (!hasContent(val))
return mkfailure<int, std::string>(reason(val));
@@ -162,8 +165,8 @@ const failable<int, std::string> post(request_rec* r, const ilambda& impl, const
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));
+ const value entry = atom::entryValue(content(atom::readEntry(ls)));
+ const failable<value, std::string> val = impl("post", mklist<value>(entry));
if (!hasContent(val))
return mkfailure<int, std::string>(reason(val));
@@ -179,14 +182,15 @@ const failable<int, std::string> post(request_rec* r, const ilambda& impl, const
/**
* Handle an HTTP PUT.
*/
-const failable<int, std::string> put(request_rec* r, const ilambda& impl, const list<value>& px) {
+const failable<int, std::string> put(request_rec* r, const ilambda& impl) {
const list<std::string> ls = httpd::read(r);
- httpd::logStrings(ls, "content");
+ debug(r->uri, "modeval::put::url");
+ debug(ls, "modeval::put::input");
// Evaluate an ATOM PUT request
const list<value> id(httpd::path(r->path_info));
- const value entry = httpd::feedEntry(content(atom::readEntry(ls)));
- const failable<value, std::string> val = impl("put", append(mklist<value>(entry, car(id)), px));
+ const value entry = atom::entryValue(content(atom::readEntry(ls)));
+ const failable<value, std::string> val = impl("put", mklist<value>(car(id), entry));
if (!hasContent(val))
return mkfailure<int, std::string>(reason(val));
if (val == value(false))
@@ -197,11 +201,12 @@ const failable<int, std::string> put(request_rec* r, const ilambda& impl, const
/**
* Handle an HTTP DELETE.
*/
-const failable<int, std::string> del(request_rec* r, const ilambda& impl, const list<value>& px) {
+const failable<int, std::string> del(request_rec* r, const ilambda& impl) {
+ debug(r->uri, "modeval::delete::url");
// Evaluate an ATOM delete request
const list<value> id(httpd::path(r->path_info));
- const failable<value, std::string> val = impl("delete", cons<value>(car(id), px));
+ const failable<value, std::string> val = impl("delete", mklist<value>(car(id)));
if (!hasContent(val))
return mkfailure<int, std::string>(reason(val));
if (val == value(false))
@@ -237,11 +242,11 @@ const cached<failable<value, std::string> > component(DirConf* conf) {
/**
* 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 value mkproxy(const value& ref, const std::string& base, const http::CURLSession& ch) {
+ return lambda<value(list<value>&)>(http::proxy(base + std::string(scdl::name(ref)), ch));
}
-const list<value> proxies(const list<value>& refs, const std::string& base, const http::CURLHandle& ch) {
+const list<value> proxies(const list<value>& refs, const std::string& base, const http::CURLSession& ch) {
if (isNil(refs))
return refs;
return cons(mkproxy(car(refs), base, ch), proxies(cdr(refs), base, ch));
@@ -251,11 +256,11 @@ const list<value> proxies(const list<value>& refs, const std::string& base, cons
* 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) {
+const cached<failable<ilambda, std::string> > implementation(const std::string& itype, const std::string& path, const list<value>& px) {
if (itype.find(".scheme") != std::string::npos)
- return latest(scm::readImplementation(path));
+ return latest(scm::readImplementation(path, px));
if (itype.find(".cpp") != std::string::npos)
- return latest(cpp::readImplementation(path));
+ return latest(cpp::readImplementation(path, px));
return cached<failable<ilambda, std::string> >();
}
@@ -265,7 +270,7 @@ const cached<failable<ilambda, std::string> > implementation(const std::string&
int handler(request_rec *r) {
if(strcmp(r->handler, "mod_tuscany_eval"))
return DECLINED;
- httpd::logRequest(r, "mod_tuscany_eval::handler");
+ httpdDebugRequest(r, "modeval::handler::input");
// Set up the read policy
const int rc = httpd::setupReadPolicy(r);
@@ -283,8 +288,19 @@ int handler(request_rec *r) {
const value ielement= scdl::implementation(content(comp));
const std::string path = conf.contributionPath + std::string(scdl::uri(ielement));
if (path != conf.implementationPath) {
+
+ // Convert component references to configured proxy lambdas
+ const ServerConf& sconf = httpd::serverConf<ServerConf>(r, &mod_tuscany_eval);
+ std::ostringstream base;
+ if (sconf.wiringHost == "")
+ base << "http://localhost:" << ap_get_server_port(r) << "/references/" << std::string(scdl::name(content(comp))) << "/";
+ else
+ base << "http://" << sconf.wiringHost << "/references/" << std::string(scdl::name(content(comp))) << "/";
+ http::CURLSession ch;
+ const list<value> px(proxies(scdl::references(content(comp)), base.str(), ch));
+
+ conf.implementation = implementation(elementName(ielement), path, px);
conf.implementationPath = path;
- conf.implementation = implementation(elementName(ielement), path);
}
else
conf.implementation = latest(conf.implementation);
@@ -292,47 +308,46 @@ int handler(request_rec *r) {
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));
+ return httpd::reportStatus(get(r, content(impl)));
if(r->method_number == M_POST)
- return httpd::reportStatus(post(r, content(impl), px));
+ return httpd::reportStatus(post(r, content(impl)));
if(r->method_number == M_PUT)
- return httpd::reportStatus(put(r, content(impl), px));
+ return httpd::reportStatus(put(r, content(impl)));
if(r->method_number == M_DELETE)
- return httpd::reportStatus(del(r, content(impl), px));
+ return httpd::reportStatus(del(r, content(impl)));
return HTTP_NOT_IMPLEMENTED;
}
/**
* Configuration commands.
*/
-const char *confHome(cmd_parms *cmd, void *dummy, const char *arg) {
+const char *confHome(cmd_parms *cmd, unused void *dummy, const char *arg) {
ServerConf *c = (ServerConf*)ap_get_module_config(cmd->server->module_config, &mod_tuscany_eval);
c->home = arg;
return NULL;
}
-const char *confContribution(cmd_parms *cmd, void *c, const char *arg) {
+const char *confWiringHost(cmd_parms *cmd, unused void *dummy, const char *arg) {
+ ServerConf *c = (ServerConf*)ap_get_module_config(cmd->server->module_config, &mod_tuscany_eval);
+ c->wiringHost = arg;
+ return NULL;
+}
+const char *confContribution(unused cmd_parms *cmd, void *c, const char *arg) {
DirConf* conf = (DirConf*)c;
conf->contributionPath = arg;
conf->component = component(conf);
return NULL;
}
-const char *confComposite(cmd_parms *cmd, void *c, const char *arg) {
+const char *confComposite(unused 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) {
+const char *confComponent(unused cmd_parms *cmd, void *c, const char *arg) {
DirConf* conf = (DirConf*)c;
conf->componentName = arg;
conf->component = component(conf);
@@ -344,17 +359,18 @@ const char *confComponent(cmd_parms *cmd, void *c, const char *arg) {
*/
const command_rec commands[] = {
AP_INIT_TAKE1("TuscanyHome", (const char*(*)())confHome, NULL, RSRC_CONF, "Tuscany home directory"),
+ AP_INIT_TAKE1("SCAWiringHost", (const char*(*)())confWiringHost, NULL, RSRC_CONF, "SCA wiring host"),
AP_INIT_TAKE1("SCAContribution", (const char*(*)())confContribution, NULL, ACCESS_CONF, "SCA contribution location"),
AP_INIT_TAKE1("SCAComposite", (const char*(*)())confComposite, NULL, ACCESS_CONF, "SCA composite location"),
AP_INIT_TAKE1("SCAComponent", (const char*(*)())confComponent, NULL, ACCESS_CONF, "SCA component name"),
- {NULL}
+ {NULL, NULL, NULL, 0, NO_ARGS, NULL}
};
-int postConfig(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) {
+int postConfig(unused apr_pool_t *p, unused apr_pool_t *plog, unused apr_pool_t *ptemp, unused server_rec *s) {
return OK;
}
-void childInit(apr_pool_t* p, server_rec* svr_rec) {
+void childInit(unused apr_pool_t* p, server_rec* svr_rec) {
ServerConf *c = (ServerConf*)ap_get_module_config(svr_rec->module_config, &mod_tuscany_eval);
if(c == NULL) {
std::cerr << "[Tuscany] Due to one or more errors mod_tuscany_eval loading failed. Causing apache to stop loading." << std::endl;
@@ -362,7 +378,7 @@ void childInit(apr_pool_t* p, server_rec* svr_rec) {
}
}
-void registerHooks(apr_pool_t *p) {
+void registerHooks(unused apr_pool_t *p) {
ap_hook_post_config(postConfig, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_child_init(childInit, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_handler(handler, NULL, NULL, APR_HOOK_MIDDLE);
diff --git a/sca-cpp/trunk/modules/server/mod-scm.hpp b/sca-cpp/trunk/modules/server/mod-scm.hpp
index 386d032695..586b90190f 100644
--- a/sca-cpp/trunk/modules/server/mod-scm.hpp
+++ b/sca-cpp/trunk/modules/server/mod-scm.hpp
@@ -34,8 +34,10 @@
#include "function.hpp"
#include "list.hpp"
#include "value.hpp"
+#include "debug.hpp"
#include "monad.hpp"
#include "cache.hpp"
+#include "../eval/primitive.hpp"
#include "../eval/driver.hpp"
#include "../http/httpd.hpp"
#include "mod-eval.hpp"
@@ -46,19 +48,29 @@ namespace modeval {
namespace scm {
/**
+ * Convert proxy lambdas to evaluator primitive procedures.
+ */
+const list<value> primitiveProcedures(const list<value>& l) {
+ if (isNil(l))
+ return l;
+ return cons<value>(mklist<value>(eval::primitiveSymbol, car(l)), primitiveProcedures(cdr(l)));
+}
+
+/**
* Evaluate a script component implementation function.
*/
struct evalImplementation {
const value impl;
- evalImplementation(const value& impl) : impl(impl) {
+ const list<value> px;
+ evalImplementation(const value& impl, const list<value>& px) : impl(impl), px(eval::quotedParameters(primitiveProcedures(px))) {
}
const failable<value, std::string> operator()(const value& func, const list<value>& params) const {
- const value expr = cons<value>(func, eval::quotedParameters(params));
- httpd::logValue(expr, "expr");
+ const value expr = cons<value>(func, append(eval::quotedParameters(params), px));
+ debug(expr, "modeval::scm::evalImplementation::input");
gc_pool pool;
eval::Env globalEnv = eval::setupEnvironment(pool);
const value val = eval::evalScript(expr, impl, globalEnv, pool);
- httpd::logValue(val, "val");
+ debug(val, "modeval::scm::evalImplementation::result");
if (isNil(val))
return mkfailure<value, std::string>("Could not evaluate expression");
return val;
@@ -68,20 +80,20 @@ struct evalImplementation {
/**
* Read a script component implementation.
*/
-const failable<ilambda, std::string> readLatestImplementation(const std::string path) {
+const failable<ilambda, std::string> readLatestImplementation(const std::string path, const list<value>& px) {
std::ifstream is(path.c_str(), std::ios_base::in);
if (is.fail() || is.bad())
return mkfailure<ilambda, std::string>("Could not read implementation: " + path);
const value impl = eval::readScript(is);
if (isNil(impl))
return mkfailure<ilambda, std::string>("Could not read implementation: " + path);
- return ilambda(evalImplementation(impl));
+ return ilambda(evalImplementation(impl, px));
}
-const cached<failable<ilambda, std::string> > readImplementation(const std::string& path) {
- const lambda<failable<ilambda, std::string>(std::string)> ri(readLatestImplementation);
+const cached<failable<ilambda, std::string> > readImplementation(const std::string& path, const list<value>& px) {
+ const lambda<failable<ilambda, std::string>(std::string, list<value>)> ri(readLatestImplementation);
const lambda<unsigned long(std::string)> ft(latestFileTime);
- return cached<failable<ilambda, std::string> >(curry(ri, path), curry(ft, path));
+ return cached<failable<ilambda, std::string> >(curry(ri, path, px), curry(ft, path));
}
}
diff --git a/sca-cpp/trunk/modules/server/http-test b/sca-cpp/trunk/modules/server/server-test
index 6d23911c31..9c517f38b6 100755
--- a/sca-cpp/trunk/modules/server/http-test
+++ b/sca-cpp/trunk/modules/server/server-test
@@ -25,8 +25,15 @@ cat >>tmp/conf/httpd.conf <<EOF
<Location /test>
SetHandler mod_tuscany_eval
SCAContribution `pwd`/
-SCAComposite httpd-test.composite
-SCAComponent httpd-test
+SCAComposite domain-test.composite
+SCAComponent server-test
+</Location>
+
+<Location /cpp>
+SetHandler mod_tuscany_eval
+SCAContribution `pwd`/
+SCAComposite domain-test.composite
+SCAComponent cpp-test
</Location>
EOF
@@ -34,10 +41,10 @@ apachectl -k start -d `pwd`/tmp
sleep 1
# Test
-./client-test
+./client-test 2>/dev/null
rc=$?
# Cleanup
apachectl -k stop -d `pwd`/tmp
-sleep 2
+sleep 1
return $rc
diff --git a/sca-cpp/trunk/modules/server/httpd-test.scm b/sca-cpp/trunk/modules/server/server-test.scm
index 0566eaf36f..0566eaf36f 100644
--- a/sca-cpp/trunk/modules/server/httpd-test.scm
+++ b/sca-cpp/trunk/modules/server/server-test.scm
diff --git a/sca-cpp/trunk/modules/server/wiring-test b/sca-cpp/trunk/modules/server/wiring-test
index c50732ddb2..5f77d4c6f8 100755
--- a/sca-cpp/trunk/modules/server/wiring-test
+++ b/sca-cpp/trunk/modules/server/wiring-test
@@ -27,21 +27,21 @@ cat >>tmp/conf/httpd.conf <<EOF
<Location /test>
SetHandler mod_tuscany_eval
SCAContribution `pwd`/
-SCAComposite httpd-test.composite
-SCAComponent httpd-test
+SCAComposite domain-test.composite
+SCAComponent server-test
</Location>
<Location /client>
SetHandler mod_tuscany_eval
-SCAContribution /home/delfinoj/SCAZone/Source/tuscany-cpp/sca/modules/http/
-SCAComposite httpd-test.composite
-SCAComponent httpd-client
+SCAContribution `pwd`/
+SCAComposite domain-test.composite
+SCAComponent client-test
</Location>
<Location /references>
SetHandler mod_tuscany_wiring
SCAContribution `pwd`/
-SCAComposite httpd-test.composite
+SCAComposite domain-test.composite
</Location>
EOF
@@ -86,7 +86,7 @@ fi
# Cleanup
apachectl -k stop -d `pwd`/tmp
-sleep 2
+sleep 1
if [ "$rc" = "0" ]; then
echo "OK"
fi
diff --git a/sca-cpp/trunk/test/store-script/currency-converter.scm b/sca-cpp/trunk/test/store-script/currency-converter.scm
index 7f58335951..498ac5da5b 100644
--- a/sca-cpp/trunk/test/store-script/currency-converter.scm
+++ b/sca-cpp/trunk/test/store-script/currency-converter.scm
@@ -7,3 +7,4 @@
(define (symbol currency)
(if (equal? currency "EUR") "E" "$")
)
+
diff --git a/sca-cpp/trunk/test/store-script/fruits-catalog.scm b/sca-cpp/trunk/test/store-script/fruits-catalog.scm
index 390068d71a..18128f0137 100644
--- a/sca-cpp/trunk/test/store-script/fruits-catalog.scm
+++ b/sca-cpp/trunk/test/store-script/fruits-catalog.scm
@@ -1,12 +1,9 @@
; Catalog implementation
(define (get converter)
- (display "catalog")
(define (convert price) (converter "convert" "USD" "USD" price))
-
(define code "USD")
(define symbol (converter "symbol" code))
-
(list
(list (list 'javaClass "services.Item") (list 'name "Apple") (list 'currencyCode code) (list 'currencySymbol symbol) (list 'price (convert 2.99)))
(list (list 'javaClass "services.Item") (list 'name "Orange") (list 'currencyCode code) (list 'currencySymbol symbol) (list 'price (convert 3.55)))
@@ -17,3 +14,4 @@
; TODO remove these JSON-RPC specific functions
(define (system.listMethods converter) (list "Service.get"))
(define Service.get get)
+
diff --git a/sca-cpp/trunk/test/store-script/htdocs/store.html b/sca-cpp/trunk/test/store-script/htdocs/store.html
index 4d300f1adb..0378b454cc 100644
--- a/sca-cpp/trunk/test/store-script/htdocs/store.html
+++ b/sca-cpp/trunk/test/store-script/htdocs/store.html
@@ -94,11 +94,15 @@
var j = 0;
for (var i=0; i<items.length; i++)
if (items[i].checked) {
-
- var entry = '<entry xmlns="http://www.w3.org/2005/Atom"><title>item</title><content type="text/xml">' +
- '<Item xmlns="http://services/">' +
- '<name xmlns="">' + catalogItems[i].name + '</name>' + '<price xmlns="">' + catalogItems[i].price + '</price>' +
- '</Item>' + '</content></entry>';
+ var entry = '<entry xmlns="http://www.w3.org/2005/Atom"><title type="text">Item</title><content type="application/xml">' +
+ '<item>' +
+ '<javaClass>' + catalogItems[i].javaClass + '</javaClass>' +
+ '<name>' + catalogItems[i].name + '</name>' +
+ '<currencyCode>' + catalogItems[i].currencyCode + '</currencyCode>' +
+ '<currencySymbol>' + catalogItems[i].currencySymbol + '</currencySymbol>' +
+ '<price>' + catalogItems[i].price + '</price>' +
+ '</item>' +
+ '</content></entry>';
shoppingCart.post(entry, shoppingCart_postResponse);
items[i].checked = false;
}
diff --git a/sca-cpp/trunk/test/store-script/shopping-cart.scm b/sca-cpp/trunk/test/store-script/shopping-cart.scm
index ebb3504e25..01ca62df40 100644
--- a/sca-cpp/trunk/test/store-script/shopping-cart.scm
+++ b/sca-cpp/trunk/test/store-script/shopping-cart.scm
@@ -1,26 +1,58 @@
; Shopping cart implementation
-(define (post item)
- (uuid)
+(define cartId "1234")
+
+; Get the shopping cart from the cache
+; Return an empty cart if not found
+(define (getcart id cache)
+ (define cart (cache "get" id))
+ (if (nul cart)
+ (list)
+ cart)
+)
+
+; Post a new item to the cart, create a new cart if necessary
+(define (post item cache)
+ (define id (uuid))
+ (define cart (cons item (getcart cartId cache)))
+ (cache "put" cartId cart)
+ id
)
-(define (getall)
- (cons "Sample Feed" (cons (uuid) '()))
+; Return the content of the cart
+(define (getall cache)
+ (define cart (getcart cartId cache))
+ (cons "Your Cart" (cons cartId cart))
)
-(define (get id)
+; Get an item from the cart
+(define (get id cache)
(define entry (list (list 'name "Apple") (list 'currencyCode "USD") (list 'currencySymbol "$") (list 'price 2.99)))
(cons "Item" (list id entry))
)
-(define (delete id)
- true
+; Delete the cart
+(define (delete id cache)
+ (cache "delete" cartId)
+)
+
+; Return the price of an item
+(define (price item)
+ (car (cdr (car (cdr (cdr (cdr (cdr (car (cdr (cdr item))))))))))
+)
+
+; Sum the prices of a list of items
+(define (sum items)
+ (if (nul items) 0 (+ (price (car items)) (sum (cdr items))))
)
-(define (gettotal)
- 11.0
+; Return the total price of the items in the cart
+(define (gettotal cache)
+ (define cart (getcart cartId cache))
+ (sum cart)
)
; TODO remove these JSON-RPC specific functions
-(define (system.listMethods) (list "Service.getTotal"))
+(define (system.listMethods cache) (list "Service.getTotal"))
(define Service.getTotal gettotal)
+
diff --git a/sca-cpp/trunk/test/store-script/store-http-test b/sca-cpp/trunk/test/store-script/store-composite-test
index d04eab8a6c..43923fca36 100755
--- a/sca-cpp/trunk/test/store-script/store-http-test
+++ b/sca-cpp/trunk/test/store-script/store-composite-test
@@ -52,6 +52,13 @@ SCAComposite store.composite
SCAComponent CurrencyConverter
</Location>
+<Location /Cache>
+SetHandler mod_tuscany_eval
+SCAContribution `pwd`/
+SCAComposite store.composite
+SCAComponent Cache
+</Location>
+
<Location /references>
SetHandler mod_tuscany_wiring
SCAContribution `pwd`/
@@ -60,6 +67,9 @@ SCAComposite store.composite
EOF
apachectl -k start -d `pwd`/tmp
+
+mc="memcached -l 127.0.0.1 -m 4 -p 11211"
+$mc &
sleep 1
# Test HTTP GET
@@ -69,7 +79,8 @@ rc=$?
# Cleanup
apachectl -k stop -d `pwd`/tmp
-sleep 2
+kill `ps -f | grep -v grep | grep "$mc" | awk '{ print $2 }'`
+sleep 1
if [ "$rc" = "0" ]; then
echo "OK"
fi
diff --git a/sca-cpp/trunk/test/store-script/store.composite b/sca-cpp/trunk/test/store-script/store.composite
index cd34f81840..2cfadf3f71 100644
--- a/sca-cpp/trunk/test/store-script/store.composite
+++ b/sca-cpp/trunk/test/store-script/store.composite
@@ -57,6 +57,9 @@
<service name="Total">
<t:binding.jsonrpc uri="Total"/>
</service>
+ <reference name="cache" target="Cache">
+ <t:binding.atom/>
+ </reference>
</component>
<component name="CurrencyConverter">
@@ -66,4 +69,11 @@
</service>
</component>
+ <component name="Cache">
+ <t:implementation.cpp uri="../../components/cache/.libs/libmcache"/>
+ <service name="Cache">
+ <t:binding.atom uri="Cache"/>
+ </service>
+ </component>
+
</composite>
diff --git a/sca-cpp/trunk/test/store-script/store.scm b/sca-cpp/trunk/test/store-script/store.scm
index 2434b18b51..01f72d0bea 100644
--- a/sca-cpp/trunk/test/store-script/store.scm
+++ b/sca-cpp/trunk/test/store-script/store.scm
@@ -24,8 +24,8 @@
(shoppingCart "delete" id)
)
-(define (system.listMethods) (list "Service.get" "Service.getTotal"))
-
+; TODO remove these JSON-RPC specific functions
+(define (system.listMethods catalog shoppingCart shoppingTotal) (list "Service.get" "Service.getTotal"))
(define Service.getCatalog getcatalog)
-
(define Service.getTotal gettotal)
+