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
This commit is contained in:
parent
cd7dae28b0
commit
ff12404062
31 changed files with 723 additions and 281 deletions
138
sca-cpp/trunk/components/cache/mcache-client-test.cpp
vendored
Normal file
138
sca-cpp/trunk/components/cache/mcache-client-test.cpp
vendored
Normal file
|
|
@ -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;
|
||||
}
|
||||
10
sca-cpp/trunk/components/cache/mcache-test.cpp
vendored
10
sca-cpp/trunk/components/cache/mcache-test.cpp
vendored
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
10
sca-cpp/trunk/components/cache/mcache.cpp
vendored
10
sca-cpp/trunk/components/cache/mcache.cpp
vendored
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
47
sca-cpp/trunk/components/cache/mcache.hpp
vendored
47
sca-cpp/trunk/components/cache/mcache.hpp
vendored
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
47
sca-cpp/trunk/components/cache/memcached-server-test
vendored
Executable file
47
sca-cpp/trunk/components/cache/memcached-server-test
vendored
Executable file
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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))));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
@ -40,11 +41,6 @@
|
|||
namespace tuscany {
|
||||
namespace http {
|
||||
|
||||
/**
|
||||
* Set to true to log HTTP content.
|
||||
*/
|
||||
bool logContent = false;
|
||||
|
||||
/**
|
||||
* CURL library context, one per process.
|
||||
*/
|
||||
|
|
@ -63,21 +59,44 @@ CURLContext curlContext;
|
|||
/**
|
||||
* Represents a CURL session handle.
|
||||
*/
|
||||
class CURLHandle {
|
||||
class CURLSession {
|
||||
public:
|
||||
CURLHandle() : h(curl_easy_init()) {
|
||||
}
|
||||
~CURLHandle() {
|
||||
curl_easy_cleanup(h);
|
||||
CURLSession() : ch(new CURLHandle()) {
|
||||
}
|
||||
|
||||
operator CURL*() const {
|
||||
return h;
|
||||
~CURLSession() {
|
||||
}
|
||||
|
||||
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.
|
||||
*/
|
||||
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,5 +28,5 @@ rc=$?
|
|||
|
||||
# Cleanup
|
||||
apachectl -k stop -d `pwd`/tmp
|
||||
sleep 2
|
||||
sleep 1
|
||||
return $rc
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ rc=$?
|
|||
|
||||
# Cleanup
|
||||
apachectl -k stop -d `pwd`/tmp
|
||||
sleep 2
|
||||
sleep 1
|
||||
if [ "$rc" = "0" ]; then
|
||||
echo "OK"
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -50,17 +50,12 @@
|
|||
|
||||
#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.
|
||||
*/
|
||||
|
|
@ -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.
|
||||
|
|
@ -255,14 +231,6 @@ const char* url(const value& v, request_rec* r) {
|
|||
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.
|
||||
*/
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -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
|
||||
|
|
|
|||
76
sca-cpp/trunk/modules/server/impl-test.cpp
Normal file
76
sca-cpp/trunk/modules/server/impl-test.cpp
Normal file
|
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
@ -45,20 +47,30 @@ namespace server {
|
|||
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));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -7,3 +7,4 @@
|
|||
(define (symbol currency)
|
||||
(if (equal? currency "EUR") "E" "$")
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
)
|
||||
|
||||
(define (getall)
|
||||
(cons "Sample Feed" (cons (uuid) '()))
|
||||
; 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 (get id)
|
||||
; Return the content of the cart
|
||||
(define (getall cache)
|
||||
(define cart (getcart cartId cache))
|
||||
(cons "Your Cart" (cons cartId cart))
|
||||
)
|
||||
|
||||
; 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)
|
||||
)
|
||||
|
||||
(define (gettotal)
|
||||
11.0
|
||||
; 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))))
|
||||
)
|
||||
|
||||
; 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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue