summaryrefslogtreecommitdiffstats
path: root/sandbox/sebastien/cpp/apr-2/components
diff options
context:
space:
mode:
Diffstat (limited to 'sandbox/sebastien/cpp/apr-2/components')
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/Makefile.am19
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/cache/Makefile.am53
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/cache/adder-test.scm20
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/cache/cache.composite68
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/cache/client-test.cpp156
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/cache/datacache.componentType30
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/cache/datacache.cpp125
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/cache/memcache-test.cpp82
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/cache/memcache.componentType28
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/cache/memcache.cpp123
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/cache/memcache.hpp191
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/cache/memcached-ssl-test54
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/cache/memcached-start38
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/cache/memcached-stop39
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/cache/memcached-test34
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/cache/memocache.componentType28
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/cache/memocache.cpp77
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/cache/server-test51
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/chat/Makefile.am68
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/chat/chat-sender.componentType29
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/chat/chat-sender.cpp150
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/chat/chat-sendreceiver.componentType30
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/chat/chat-sendreceiver.cpp164
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/chat/chat.composite52
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/chat/client-test.cpp111
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/chat/echo-test31
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/chat/server-test39
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/chat/server-test.scm20
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/chat/test/TestVysperServer.java79
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/chat/vysper-classpath29
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/chat/vysper-start25
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/chat/vysper-stop25
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/chat/xmpp-test.cpp103
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/chat/xmpp.hpp320
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/filedb/Makefile.am44
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/filedb/client-test.cpp130
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/filedb/file-test.cpp94
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/filedb/filedb-test31
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/filedb/filedb.componentType28
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/filedb/filedb.composite34
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/filedb/filedb.cpp124
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/filedb/filedb.hpp225
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/filedb/server-test40
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/log/Makefile.am76
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/log/adder-test.scm20
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/log/client-test.cpp107
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/log/client-test.scm20
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/log/fb303.thrift112
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/log/log.componentType28
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/log/log.composite57
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/log/log.cpp94
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/log/logger.componentType29
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/log/logger.cpp92
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/log/scribe-cat.cpp77
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/log/scribe-tail-start44
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/log/scribe-tail-stop42
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/log/scribe-test43
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/log/scribe.hpp147
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/log/scribe.thrift39
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/log/scribed-central-conf73
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/log/scribed-central-start27
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/log/scribed-central-stop28
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/log/scribed-client-conf67
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/log/scribed-client-start27
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/log/scribed-client-stop28
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/log/server-test65
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/nosqldb/Makefile.am49
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/nosqldb/client-test.cpp130
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/nosqldb/nosqldb-test29
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/nosqldb/nosqldb.componentType28
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/nosqldb/nosqldb.composite33
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/nosqldb/nosqldb.cpp123
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/nosqldb/server-test40
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/nosqldb/tinycdb24
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/nosqldb/tinycdb-test.cpp82
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/nosqldb/tinycdb.hpp460
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/queue/Makefile.am57
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/queue/client-test.cpp99
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/queue/qpid-test.cpp97
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/queue/qpid.hpp260
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/queue/qpidd-start24
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/queue/qpidd-stop26
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/queue/queue-listener.componentType29
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/queue/queue-listener.cpp158
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/queue/queue-sender.componentType28
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/queue/queue-sender.cpp72
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/queue/queue.composite56
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/queue/send-test31
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/queue/server-test43
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/queue/server-test.scm20
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/sqldb/Makefile.am55
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/sqldb/client-test.cpp130
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/sqldb/pgsql35
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-backup41
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-conf105
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-standby-conf122
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-standby-test.cpp88
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-start29
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-stop27
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-test.cpp82
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql.hpp262
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/sqldb/server-test44
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/sqldb/sqldb-test32
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/sqldb/sqldb.componentType29
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/sqldb/sqldb.composite34
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/sqldb/sqldb.cpp124
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/sqldb/standby-test39
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/webservice/Makefile.am71
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/webservice/axiom-test.cpp85
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/webservice/axis2-conf64
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/webservice/axis2-dispatcher.cpp138
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/webservice/axis2-service.cpp151
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/webservice/axis2-test.cpp71
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/webservice/axis2.hpp194
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/webservice/axis2.xml148
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/webservice/client-test.cpp94
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/webservice/echo-test37
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/webservice/module.xml25
-rwxr-xr-xsandbox/sebastien/cpp/apr-2/components/webservice/server-test49
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/webservice/server-test.scm21
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/webservice/services.xml25
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/webservice/webservice-client.componentType28
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/webservice/webservice-client.cpp65
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/webservice/webservice-listener.componentType28
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/webservice/webservice-listener.cpp86
-rw-r--r--sandbox/sebastien/cpp/apr-2/components/webservice/webservice.composite48
126 files changed, 9287 insertions, 0 deletions
diff --git a/sandbox/sebastien/cpp/apr-2/components/Makefile.am b/sandbox/sebastien/cpp/apr-2/components/Makefile.am
new file mode 100644
index 0000000000..55f14a4ea8
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/Makefile.am
@@ -0,0 +1,19 @@
+# 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.
+
+SUBDIRS = cache chat log nosqldb filedb queue sqldb webservice
+
diff --git a/sandbox/sebastien/cpp/apr-2/components/cache/Makefile.am b/sandbox/sebastien/cpp/apr-2/components/cache/Makefile.am
new file mode 100644
index 0000000000..2f162bf8f5
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/cache/Makefile.am
@@ -0,0 +1,53 @@
+# 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.
+
+incl_HEADERS = *.hpp
+incldir = $(prefix)/include/components/cache
+
+dist_comp_SCRIPTS = memcached-start memcached-stop
+compdir=$(prefix)/components/cache
+
+comp_DATA = memcached.prefix
+memcached.prefix: $(top_builddir)/config.status
+ echo ${MEMCACHED_PREFIX} >memcached.prefix
+
+EXTRA_DIST = cache.composite memcache.componentType datacache.componentType memocache.componentType *.scm
+
+comp_LTLIBRARIES = libmemcache.la libdatacache.la libmemocache.la
+noinst_DATA = libmemcache.so libdatacache.so libmemocache.so
+
+libmemcache_la_SOURCES = memcache.cpp
+libmemcache.so:
+ ln -s .libs/libmemcache.so
+
+libdatacache_la_SOURCES = datacache.cpp
+libdatacache.so:
+ ln -s .libs/libdatacache.so
+
+libmemocache_la_SOURCES = memocache.cpp
+libmemocache.so:
+ ln -s .libs/libmemocache.so
+
+memcache_test_SOURCES = memcache-test.cpp
+memcache_test_LDFLAGS = -lxml2
+
+client_test_SOURCES = client-test.cpp
+client_test_LDFLAGS = -lxml2 -lcurl -lmozjs
+
+dist_noinst_SCRIPTS = memcached-test memcached-ssl-test server-test
+noinst_PROGRAMS = memcache-test client-test
+TESTS = memcached-test memcached-ssl-test server-test
diff --git a/sandbox/sebastien/cpp/apr-2/components/cache/adder-test.scm b/sandbox/sebastien/cpp/apr-2/components/cache/adder-test.scm
new file mode 100644
index 0000000000..ccd5bc555f
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/cache/adder-test.scm
@@ -0,0 +1,20 @@
+; 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.
+
+; Logger test case
+
+(define (add a b) (+ a b))
diff --git a/sandbox/sebastien/cpp/apr-2/components/cache/cache.composite b/sandbox/sebastien/cpp/apr-2/components/cache/cache.composite
new file mode 100644
index 0000000000..1f3302614d
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/cache/cache.composite
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/components"
+ name="memcache">
+
+ <component name="memcache">
+ <implementation.cpp path="." library="libmemcache"/>
+ <service name="memcache">
+ <t:binding.http uri="memcache"/>
+ </service>
+ <property name="servers">localhost,localhost:11212,localhost:11213</property>
+ </component>
+
+ <component name="l2cache">
+ <implementation.cpp path="." library="libmemcache"/>
+ <service name="l2cache">
+ <t:binding.http uri="l2cache"/>
+ </service>
+ <property name="servers">localhost:11411,localhost:11412,localhost:11413</property>
+ </component>
+
+ <component name="datacache">
+ <implementation.cpp path="." library="libdatacache"/>
+ <service name="datacache">
+ <t:binding.http uri="datacache"/>
+ </service>
+ <reference name="l1reader" target="memcache"/>
+ <reference name="l1writer" target="memcache"/>
+ <reference name="l2reader" target="l2cache"/>
+ <reference name="l2writer" target="l2cache"/>
+ </component>
+
+ <component name="memocache">
+ <implementation.cpp path="." library="libmemocache"/>
+ <service name="memocache">
+ <t:binding.http uri="memocache"/>
+ </service>
+ <reference name="relay" target="adder"/>
+ <reference name="cache" target="memcache"/>
+ </component>
+
+ <component name="adder">
+ <implementation.scheme script="adder-test.scm"/>
+ <service name="adder">
+ <t:binding.http uri="adder"/>
+ </service>
+ </component>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/components/cache/client-test.cpp b/sandbox/sebastien/cpp/apr-2/components/cache/client-test.cpp
new file mode 100644
index 0000000000..fce911a302
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/cache/client-test.cpp
@@ -0,0 +1,156 @@
+/*
+ * 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 cache component.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "perf.hpp"
+#include "../../modules/http/http.hpp"
+
+namespace tuscany {
+namespace cache {
+
+const string memcacheuri("http://localhost:8090/memcache");
+const string datacacheuri("http://localhost:8090/datacache");
+const string memocacheuri("http://localhost:8090/memocache");
+
+bool testCache(const string& uri) {
+ http::CURLSession cs("", "", "");
+
+ const list<value> i = list<value>()
+ + (list<value>() + "name" + string("Apple"))
+ + (list<value>() + "price" + string("$2.99"));
+ const list<value> a = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
+
+ const failable<value> id = http::post(a, uri, cs);
+ assert(hasContent(id));
+
+ const string p = path(content(id));
+ {
+ const failable<value> val = http::get(uri + p, cs);
+ assert(hasContent(val));
+ assert(content(val) == a);
+ }
+
+ const list<value> j = list<value>()
+ + (list<value>() + "name" + string("Apple"))
+ + (list<value>() + "price" + string("$3.55"));
+ const list<value> b = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), j);
+
+ {
+ const failable<value> r = http::put(b, uri + p, cs);
+ assert(hasContent(r));
+ assert(content(r) == value(true));
+ }
+ {
+ const failable<value> val = http::get(uri + p, cs);
+ assert(hasContent(val));
+ assert(content(val) == b);
+ }
+ {
+ const failable<value> r = http::del(uri + p, cs);
+ assert(hasContent(r));
+ assert(content(r) == value(true));
+ }
+ {
+ const failable<value> val = http::get(uri + p, cs);
+ assert(!hasContent(val));
+ }
+
+ return true;
+}
+
+bool testMemcache() {
+ return testCache(memcacheuri);
+}
+
+bool testDatacache() {
+ return testCache(datacacheuri);
+}
+
+bool testMemocache() {
+ http::CURLSession cs("", "", "");
+
+ const failable<value> res = http::evalExpr(mklist<value>(string("add"), 33, 22), memocacheuri, cs);
+ assert(hasContent(res));
+ assert((int)content(res) == 55);
+
+ const failable<value> res2 = http::evalExpr(mklist<value>(string("add"), 33, 22), memocacheuri, cs);
+ assert(hasContent(res2));
+ assert((int)content(res2) == 55);
+
+ return true;
+}
+
+struct getLoop {
+ const string path;
+ const value entry;
+ http::CURLSession cs;
+ getLoop(const string& path, const value& entry, http::CURLSession cs) : path(path), entry(entry), cs(cs) {
+ }
+ const bool operator()() const {
+ const failable<value> val = http::get(memcacheuri + path, cs);
+ assert(hasContent(val));
+ assert(content(val) == entry);
+ return true;
+ }
+};
+
+bool testGetPerf() {
+ const list<value> i = list<value>()
+ + (list<value>() + "name" + string("Apple"))
+ + (list<value>() + "price" + string("$4.55"));
+ const value a = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
+
+ http::CURLSession cs("", "", "");
+ const failable<value> id = http::post(a, memcacheuri, cs);
+ assert(hasContent(id));
+ const string p = path(content(id));
+
+ const lambda<bool()> gl = getLoop(p, a, cs);
+ cout << "Cache get test " << time(gl, 5, 200) << " ms" << endl;
+
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::cache::testMemcache();
+ tuscany::cache::testDatacache();
+ tuscany::cache::testMemocache();
+ tuscany::cache::testGetPerf();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/cache/datacache.componentType b/sandbox/sebastien/cpp/apr-2/components/cache/datacache.componentType
new file mode 100644
index 0000000000..ca6284c661
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/cache/datacache.componentType
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<componentType xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/components">
+
+ <service name="datacache"/>
+ <reference name="l1reader"/>
+ <reference name="l1writer"/>
+ <reference name="l2reader"/>
+ <reference name="l2writer"/>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/components/cache/datacache.cpp b/sandbox/sebastien/cpp/apr-2/components/cache/datacache.cpp
new file mode 100644
index 0000000000..e1cfdbfa57
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/cache/datacache.cpp
@@ -0,0 +1,125 @@
+/*
+ * 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$ */
+
+/**
+ * A data cache component implementation which coordinates access to two
+ * levels of backend read/write caches or stores. Each cache or store is
+ * accessed through two references: a writer reference and a reader reference.
+ *
+ * This is useful if your level2 store is made of a master and slave
+ * replicated databases, you can then wire the writer reference to the master
+ * database and the reader reference to one your slave databases (assuming
+ * that the updates eventually get replicated to the slave database, in the
+ * meantime the updates will be retrieved from the level1 cache).
+ */
+
+#include "string.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+
+namespace tuscany {
+namespace datacache {
+
+/**
+ * Get an item from the cache.
+ */
+const failable<value> get(const value& key, const lambda<value(const list<value>&)> rcache1, const lambda<value(const list<value>&)> wcache1, const lambda<value(const list<value>&)> rcache2, unused const lambda<value(const list<value>&)> wcache2) {
+
+ // Lookup level1 cache
+ const value val1 = rcache1(mklist<value>("get", key));
+ if (!isNil(val1))
+ return val1;
+
+ // Lookup level2 cache
+ const value val2 = rcache2(mklist<value>("get", key));
+ if (isNil(val2))
+ return mkfailure<value>("Couldn't get cache entry");
+
+ // Update level1 cache
+ wcache1(mklist<value>("put", key, val2));
+
+ return val2;
+}
+
+/**
+ * Post an item to the cache.
+ */
+const failable<value> post(const value& key, const value& val, unused const lambda<value(const list<value>&)> rcache1, const lambda<value(const list<value>&)> wcache1, unused const lambda<value(const list<value>&)> rcache2, const lambda<value(const list<value>&)> wcache2) {
+ const value id = append<value>(key, mklist(mkuuid()));
+
+ // Update level1 cache
+ wcache1(mklist<value>("put", id, val));
+
+ // Update level2 cache
+ wcache2(mklist<value>("put", id, val));
+
+ return id;
+}
+
+/**
+ * Put an item into the cache.
+ */
+const failable<value> put(const value& key, const value& val, unused const lambda<value(const list<value>&)> rcache1, const lambda<value(const list<value>&)> wcache1, unused const lambda<value(const list<value>&)> rcache2, const lambda<value(const list<value>&)> wcache2) {
+
+ // Update level1 cache
+ wcache1(mklist<value>("put", key, val));
+
+ // Update level2 cache
+ wcache2(mklist<value>("put", key, val));
+
+ return value(true);
+}
+
+/**
+ * Delete an item from the cache.
+ */
+const failable<value> del(const value& key, unused const lambda<value(const list<value>&)> rcache1, const lambda<value(const list<value>&)> wcache1, unused const lambda<value(const list<value>&)> rcache2, const lambda<value(const list<value>&)> wcache2) {
+
+ // Delete from level1 cache
+ wcache1(mklist<value>("delete", key));
+
+ // Delete from level2 cache
+ wcache2(mklist<value>("delete", key));
+
+ return value(true);
+}
+
+}
+}
+
+extern "C" {
+
+const tuscany::value apply(const tuscany::list<tuscany::value>& params) {
+ const tuscany::value func(car(params));
+ if (func == "get")
+ return tuscany::datacache::get(cadr(params), caddr(params), cadddr(params), caddddr(params), cadddddr(params));
+ if (func == "post")
+ return tuscany::datacache::post(cadr(params), caddr(params), cadddr(params), caddddr(params), cadddddr(params), caddddddr(params));
+ if (func == "put")
+ return tuscany::datacache::put(cadr(params), caddr(params), cadddr(params), caddddr(params), cadddddr(params), caddddddr(params));
+ if (func == "delete")
+ return tuscany::datacache::del(cadr(params), caddr(params), cadddr(params), caddddr(params), cadddddr(params));
+ return tuscany::mkfailure<tuscany::value>();
+}
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/cache/memcache-test.cpp b/sandbox/sebastien/cpp/apr-2/components/cache/memcache-test.cpp
new file mode 100644
index 0000000000..49848dd2a7
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/cache/memcache-test.cpp
@@ -0,0 +1,82 @@
+/*
+ * 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 "stream.hpp"
+#include "string.hpp"
+#include "perf.hpp"
+#include "memcache.hpp"
+
+namespace tuscany {
+namespace memcache {
+
+bool testMemCached() {
+ MemCached ch(mklist<string>("localhost:11211", "localhost:11212", "localhost:11213"));
+ const value k = mklist<value>("a");
+
+ assert(hasContent(post(k, string("AAA"), ch)));
+ assert(get(k, ch) == value(string("AAA")));
+ assert(hasContent(put(k, string("aaa"), ch)));
+ assert(get(k, ch) == value(string("aaa")));
+ assert(hasContent(del(k, ch)));
+ assert(!hasContent(get(k, ch)));
+
+ return true;
+}
+
+struct getLoop {
+ const value k;
+ MemCached& ch;
+ getLoop(const value& k, MemCached& ch) : k(k), ch(ch) {
+ }
+ const bool operator()() const {
+ assert(get(k, ch) == value(string("CCC")));
+ return true;
+ }
+};
+
+bool testGetPerf() {
+ const value k = mklist<value>("c");
+ MemCached ch(mklist<string>("localhost:11211", "localhost:11212", "localhost:11213"));
+ assert(hasContent(post(k, string("CCC"), ch)));
+
+ const lambda<bool()> gl = getLoop(k, ch);
+ cout << "Memcached get test " << time(gl, 5, 200) << " ms" << endl;
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::memcache::testMemCached();
+ tuscany::memcache::testGetPerf();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/cache/memcache.componentType b/sandbox/sebastien/cpp/apr-2/components/cache/memcache.componentType
new file mode 100644
index 0000000000..2ae66d1c43
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/cache/memcache.componentType
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<componentType xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/components">
+
+ <service name="memcache"/>
+ <property name="servers" type="xsd:string">localhost</property>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/components/cache/memcache.cpp b/sandbox/sebastien/cpp/apr-2/components/cache/memcache.cpp
new file mode 100644
index 0000000000..4b62ce2e4c
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/cache/memcache.cpp
@@ -0,0 +1,123 @@
+/*
+ * 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$ */
+
+/**
+ * Memcached-based cache component implementation.
+ */
+
+#include "string.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "memcache.hpp"
+
+namespace tuscany {
+namespace cache {
+
+/**
+ * Get an item from the cache.
+ */
+const failable<value> get(const list<value>& params, memcache::MemCached& ch) {
+ return memcache::get(car(params), ch);
+}
+
+/**
+ * Post an item to the cache.
+ */
+const failable<value> post(const list<value>& params, memcache::MemCached& ch) {
+ const value id = append<value>(car(params), mklist(mkuuid()));
+ const failable<bool> val = memcache::post(id, cadr(params), ch);
+ if (!hasContent(val))
+ return mkfailure<value>(reason(val));
+ return id;
+}
+
+/**
+ * Put an item into the cache.
+ */
+const failable<value> put(const list<value>& params, memcache::MemCached& ch) {
+ const failable<bool> val = memcache::put(car(params), cadr(params), ch);
+ if (!hasContent(val))
+ return mkfailure<value>(reason(val));
+ return value(content(val));
+}
+
+/**
+ * Delete an item from the cache.
+ */
+const failable<value> del(const list<value>& params, memcache::MemCached& ch) {
+ const failable<bool> val = memcache::del(car(params), ch);
+ if (!hasContent(val))
+ return mkfailure<value>(reason(val));
+ return value(content(val));
+}
+
+/**
+ * Component implementation lambda function.
+ */
+class applyCache {
+public:
+ applyCache(memcache::MemCached& ch) : ch(ch) {
+ }
+
+ const value operator()(const list<value>& params) const {
+ const value func(car(params));
+ if (func == "get")
+ return get(cdr(params), ch);
+ if (func == "post")
+ return post(cdr(params), ch);
+ if (func == "put")
+ return put(cdr(params), ch);
+ if (func == "delete")
+ return del(cdr(params), ch);
+ return tuscany::mkfailure<tuscany::value>();
+ }
+
+private:
+ memcache::MemCached& ch;
+};
+
+/**
+ * Start the component.
+ */
+const failable<value> start(unused const list<value>& params) {
+ // Connect to memcached
+ const value servers = ((lambda<value(list<value>)>)car(params))(list<value>());
+ memcache::MemCached& ch = *(new (gc_new<memcache::MemCached>()) memcache::MemCached(tokenize(",", servers)));
+
+ // Return the component implementation lambda function
+ return value(lambda<value(const list<value>&)>(applyCache(ch)));
+}
+
+}
+}
+
+extern "C" {
+
+const tuscany::value apply(const tuscany::list<tuscany::value>& params) {
+ const tuscany::value func(car(params));
+ if (func == "start")
+ return tuscany::cache::start(cdr(params));
+ return tuscany::mkfailure<tuscany::value>();
+}
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/cache/memcache.hpp b/sandbox/sebastien/cpp/apr-2/components/cache/memcache.hpp
new file mode 100644
index 0000000000..a76af6b662
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/cache/memcache.hpp
@@ -0,0 +1,191 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_memcache_hpp
+#define tuscany_memcache_hpp
+
+/**
+ * Memcached access functions.
+ */
+
+#include "apr.h"
+#include "apu.h"
+#include "apr_general.h"
+#include "apr_strings.h"
+#include "apr_hash.h"
+#include "apr_memcache.h"
+#include "apr_network_io.h"
+
+#include "string.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "../../modules/scheme/eval.hpp"
+
+namespace tuscany {
+namespace memcache {
+
+/**
+ * Represents a memcached context.
+ */
+class MemCached {
+public:
+ MemCached() : owner(false) {
+ }
+
+ MemCached(const string host, const int port) : owner(true) {
+ apr_pool_create(&pool, NULL);
+ apr_memcache_create(pool, 1, 0, &mc);
+ addServer(host, port);
+ }
+
+ MemCached(const list<string>& servers) : owner(true) {
+ apr_pool_create(&pool, NULL);
+ apr_memcache_create(pool, 1, 0, &mc);
+ addServers(servers);
+ }
+
+ MemCached(const MemCached& c) : owner(false), pool(c.pool), mc(c.mc) {
+ }
+
+ ~MemCached() {
+ if (!owner)
+ return;
+ apr_pool_destroy(pool);
+ }
+
+private:
+ bool owner;
+ apr_pool_t* pool;
+ apr_memcache_t* mc;
+
+ friend const failable<bool> post(const value& key, const value& val, const MemCached& cache);
+ friend const failable<bool> put(const value& key, const value& val, const MemCached& cache);
+ friend const failable<value> get(const value& key, const MemCached& cache);
+ friend const failable<bool> del(const value& key, const MemCached& cache);
+
+ /**
+ * Add servers to the memcached context.
+ */
+ const failable<bool> addServer(const string& host, const int port) {
+ apr_memcache_server_t *server;
+ const apr_status_t sc = apr_memcache_server_create(pool, c_str(host), (apr_port_t)port, 1, 1, 1, 600, &server);
+ if (sc != APR_SUCCESS)
+ return mkfailure<bool>("Could not create memcached server");
+ const apr_status_t as = apr_memcache_add_server(mc, server);
+ if (as != APR_SUCCESS)
+ return mkfailure<bool>("Could not add memcached server");
+ return true;
+ }
+
+ const failable<bool> addServers(const list<string>& servers) {
+ if (isNil(servers))
+ return true;
+ const list<string> toks = tokenize(":", car(servers));
+ const failable<bool> r = addServer(car(toks), isNil(cdr(toks))? 11211 : atoi(c_str(cadr(toks))));
+ if (!hasContent(r))
+ return r;
+ return addServers(cdr(servers));
+ }
+};
+
+/**
+ * Replace spaces by tabs (as spaces are not allowed in memcached keys).
+ */
+const char* nospaces(const char* s) {
+ char* c = const_cast<char*>(s);
+ for (; *c; c++)
+ if (*c == ' ')
+ *c = '\t';
+ return s;
+}
+
+/**
+ * Post a new item to the cache.
+ */
+const failable<bool> post(const value& key, const value& val, const MemCached& cache) {
+ debug(key, "memcache::post::key");
+ debug(val, "memcache::post::value");
+
+ const string ks(scheme::writeValue(key));
+ const string vs(scheme::writeValue(val));
+ const apr_status_t rc = apr_memcache_add(cache.mc, nospaces(c_str(ks)), const_cast<char*>(c_str(vs)), length(vs), 0, 27);
+ if (rc != APR_SUCCESS)
+ return mkfailure<bool>("Could not add memcached entry");
+
+ debug(true, "memcache::post::result");
+ return true;
+}
+
+/**
+ * Update an item in the cache. If the item doesn't exist it is added.
+ */
+const failable<bool> put(const value& key, const value& val, const MemCached& cache) {
+ debug(key, "memcache::put::key");
+ debug(val, "memcache::put::value");
+
+ const string ks(scheme::writeValue(key));
+ const string vs(scheme::writeValue(val));
+ const apr_status_t rc = apr_memcache_set(cache.mc, nospaces(c_str(ks)), const_cast<char*>(c_str(vs)), length(vs), 0, 27);
+ if (rc != APR_SUCCESS)
+ return mkfailure<bool>("Could not set memcached entry");
+
+ debug(true, "memcache::put::result");
+ return true;
+}
+
+/**
+ * Get an item from the cache.
+ */
+const failable<value> get(const value& key, const MemCached& cache) {
+ debug(key, "memcache::get::key");
+
+ const string ks(scheme::writeValue(key));
+ char *data;
+ apr_size_t size;
+ const apr_status_t rc = apr_memcache_getp(cache.mc, cache.pool, nospaces(c_str(ks)), &data, &size, NULL);
+ if (rc != APR_SUCCESS)
+ return mkfailure<value>("Could not get memcached entry");
+ const value val(scheme::readValue(string(data, size)));
+
+ debug(val, "memcache::get::result");
+ return val;
+}
+
+/**
+ * Delete an item from the cache
+ */
+const failable<bool> del(const value& key, const MemCached& cache) {
+ debug(key, "memcache::delete::key");
+
+ const string ks(scheme::writeValue(key));
+ const apr_status_t rc = apr_memcache_delete(cache.mc, nospaces(c_str(ks)), 0);
+ if (rc != APR_SUCCESS)
+ return mkfailure<bool>("Could not delete memcached entry");
+
+ debug(true, "memcache::delete::result");
+ return true;
+}
+
+}
+}
+
+#endif /* tuscany_memcache_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/components/cache/memcached-ssl-test b/sandbox/sebastien/cpp/apr-2/components/cache/memcached-ssl-test
new file mode 100755
index 0000000000..88143490f8
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/cache/memcached-ssl-test
@@ -0,0 +1,54 @@
+#!/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/ssl-ca-conf tmp/ssl localhost
+../../modules/http/ssl-cert-conf tmp/ssl localhost server
+../../modules/http/ssl-cert-conf tmp/ssl localhost tunnel
+
+./memcached-start 11411
+./memcached-start 11412
+./memcached-start 11413
+
+../../modules/http/httpd-conf tmp/tunnel localhost 8089 htdocs
+../../modules/http/httpd-event-conf tmp/tunnel
+tar -C tmp/ssl -c `../../modules/http/ssl-cert-find tmp/ssl` | tar -C tmp/tunnel -x
+../../modules/http/tunnel-ssl-conf tmp/tunnel 11211 localhost 8453 11411
+../../modules/http/tunnel-ssl-conf tmp/tunnel 11212 localhost 8453 11412
+../../modules/http/tunnel-ssl-conf tmp/tunnel 11213 localhost 8453 11413
+../../modules/http/httpd-start tmp/tunnel
+
+../../modules/http/httpd-conf tmp/server localhost 8090 htdocs
+tar -C tmp/ssl -c `../../modules/http/ssl-cert-find tmp/ssl` | tar -C tmp/server -x
+../../modules/http/httpd-ssl-conf tmp/server 8453
+../../modules/http/cert-auth-conf tmp/server
+../../modules/http/httpd-start tmp/server
+sleep 1
+
+# Test
+./memcache-test 2>/dev/null
+rc=$?
+
+# Cleanup
+../../modules/http/httpd-stop tmp/tunnel
+../../modules/http/httpd-stop tmp/server
+./memcached-stop 11411
+./memcached-stop 11412
+./memcached-stop 11413
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/components/cache/memcached-start b/sandbox/sebastien/cpp/apr-2/components/cache/memcached-start
new file mode 100755
index 0000000000..75524d0dec
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/cache/memcached-start
@@ -0,0 +1,38 @@
+#!/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.
+
+# Start memcached
+here=`readlink -f $0`; here=`dirname $here`
+
+addr=$1
+if [ "$addr" = "" ]; then
+ ip=""
+ port="11211"
+else
+ ip=`$here/../../modules/http/httpd-addr ip $addr`
+ port=`$here/../../modules/http/httpd-addr port $addr`
+fi
+
+memcached_prefix=`cat $here/memcached.prefix`
+if [ "$ip" = "" ]; then
+ $memcached_prefix/bin/memcached -d -m 4 -p $port
+else
+ $memcached_prefix/bin/memcached -d -l $ip -m 4 -p $port
+fi
+
diff --git a/sandbox/sebastien/cpp/apr-2/components/cache/memcached-stop b/sandbox/sebastien/cpp/apr-2/components/cache/memcached-stop
new file mode 100755
index 0000000000..c414616752
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/cache/memcached-stop
@@ -0,0 +1,39 @@
+#!/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.
+
+# Stop memcached
+here=`readlink -f $0`; here=`dirname $here`
+
+addr=$1
+if [ "$addr" = "" ]; then
+ ip=""
+ port="11211"
+else
+ ip=`$here/../../modules/http/httpd-addr ip $addr`
+ port=`$here/../../modules/http/httpd-addr port $addr`
+fi
+
+memcached_prefix=`cat $here/memcached.prefix`
+if [ "$ip" = "" ]; then
+ mc="$memcached_prefix/bin/memcached -d -m 4 -p $port"
+else
+ mc="$memcached_prefix/bin/memcached -d -l $ip -m 4 -p $port"
+fi
+
+kill `ps -ef | grep -v grep | grep "${mc}" | awk '{ print $2 }'`
diff --git a/sandbox/sebastien/cpp/apr-2/components/cache/memcached-test b/sandbox/sebastien/cpp/apr-2/components/cache/memcached-test
new file mode 100755
index 0000000000..993d63ba1b
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/cache/memcached-test
@@ -0,0 +1,34 @@
+#!/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
+./memcached-start 11211
+./memcached-start 11212
+./memcached-start 11213
+sleep 1
+
+# Test
+./memcache-test 2>/dev/null
+rc=$?
+
+# Cleanup
+./memcached-stop 11211
+./memcached-stop 11212
+./memcached-stop 11213
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/components/cache/memocache.componentType b/sandbox/sebastien/cpp/apr-2/components/cache/memocache.componentType
new file mode 100644
index 0000000000..f32677544f
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/cache/memocache.componentType
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<componentType xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/components">
+
+ <service name="memocache"/>
+ <reference name="relay"/>
+ <reference name="cache"/>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/components/cache/memocache.cpp b/sandbox/sebastien/cpp/apr-2/components/cache/memocache.cpp
new file mode 100644
index 0000000000..2482c2202b
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/cache/memocache.cpp
@@ -0,0 +1,77 @@
+/*
+ * 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$ */
+
+/**
+ * A cache component implementation which memoizes the value of function
+ * applications, keyed by the function arguments, in a key/value cache passed
+ * as a reference.
+ *
+ * This is useful if your functions are idempotent and applied many times to
+ * the same arguments. The results can then be retrieved quickly from the
+ * cache without actually applying the function.
+ */
+
+#include "string.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+
+namespace tuscany {
+namespace memocache {
+
+/**
+ * Memoize the value of a function application in a cache.
+ */
+const failable<value> memoize(const list<value>& params, const lambda<value(const list<value>&)> relay, const lambda<value(const list<value>&)> cache) {
+ debug(params, "memocache::memoize::params");
+
+ // Lookup memoized value from cache
+ const value val = cache(mklist<value>("get", params));
+ if (!isNil(val)) {
+ debug(val, "memocache::memoize::cached");
+ return val;
+ }
+
+ // Apply the given function
+ const value res = relay(params);
+ debug(res, "memocache::memoize::res");
+
+ // Store the result value in the cache
+ cache(mklist<value>("put", params, res));
+
+ return res;
+}
+
+}
+}
+
+extern "C" {
+
+const tuscany::value apply(const tuscany::list<tuscany::value>& params) {
+ const tuscany::value func(car(params));
+ if (func == "start" || func == "stop")
+ return tuscany::mkfailure<tuscany::value>();
+ const tuscany::list<tuscany::value> rev = tuscany::reverse(params);
+ return tuscany::memocache::memoize(tuscany::reverse(tuscany::cddr(rev)), tuscany::cadr(rev), tuscany::car(rev));
+}
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/cache/server-test b/sandbox/sebastien/cpp/apr-2/components/cache/server-test
new file mode 100755
index 0000000000..6d14f789f5
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/cache/server-test
@@ -0,0 +1,51 @@
+#!/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 localhost 8090 ../../modules/http/htdocs
+../../modules/server/server-conf tmp
+../../modules/server/scheme-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+SCAContribution `pwd`/
+SCAComposite cache.composite
+EOF
+
+./memcached-start 11211
+./memcached-start 11212
+./memcached-start 11213
+./memcached-start 11411
+./memcached-start 11412
+./memcached-start 11413
+../../modules/http/httpd-start tmp
+sleep 2
+
+# Test
+./client-test 2>/dev/null
+rc=$?
+
+# Cleanup
+../../modules/http/httpd-stop tmp
+./memcached-stop 11211
+./memcached-stop 11212
+./memcached-stop 11213
+./memcached-stop 11411
+./memcached-stop 11412
+./memcached-stop 11413
+sleep 2
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/components/chat/Makefile.am b/sandbox/sebastien/cpp/apr-2/components/chat/Makefile.am
new file mode 100644
index 0000000000..35fb57daf3
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/chat/Makefile.am
@@ -0,0 +1,68 @@
+# 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.
+
+JAVAROOT = $(top_builddir)/components/chat
+
+if WANT_CHAT
+
+INCLUDES = -I${LIBSTROPHE_INCLUDE}
+
+incl_HEADERS = *.hpp
+incldir = $(prefix)/include/components/chat
+
+dist_comp_SCRIPTS = vysper-start vysper-stop vysper-classpath
+compdir=$(prefix)/components/chat
+
+comp_DATA = vysper.prefix
+vysper.prefix: $(top_builddir)/config.status
+ echo ${VYSPER_PREFIX} >vysper.prefix
+
+EXTRA_DIST = chat.composite chat-sendreceiver.componentType chat-sender.componentType *.scm
+
+comp_LTLIBRARIES = libchat-sendreceiver.la libchat-sender.la
+noinst_DATA = libchat-sendreceiver.so libchat-sender.so
+
+libchat_sendreceiver_la_SOURCES = chat-sendreceiver.cpp
+libchat_sendreceiver_la_LDFLAGS = -L${LIBSTROPHE_LIB} -R${LIBSTROPHE_LIB} -lstrophe -lssl -lresolv
+libchat-sendreceiver.so:
+ ln -s .libs/libchat-sendreceiver.so
+
+libchat_sender_la_SOURCES = chat-sender.cpp
+libchat_sender_la_LDFLAGS = -L${LIBSTROPHE_LIB} -R${LIBSTROPHE_LIB} -lstrophe -lssl -lresolv
+libchat-sender.so:
+ ln -s .libs/libchat-sender.so
+
+xmpp_test_SOURCES = xmpp-test.cpp
+xmpp_test_LDFLAGS = -L${LIBSTROPHE_LIB} -R${LIBSTROPHE_LIB} -lstrophe -lssl -lresolv
+
+client_test_SOURCES = client-test.cpp
+client_test_LDFLAGS = -lxml2 -lcurl -lmozjs -L${LIBSTROPHE_LIB} -R${LIBSTROPHE_LIB} -lstrophe -lssl -lresolv
+
+noinst_PROGRAMS = xmpp-test client-test
+dist_noinst_SCRIPTS = server-test
+
+if WANT_VYSPER
+
+AM_JAVACFLAGS = -cp `${top_builddir}/components/chat/vysper-classpath ${VYSPER_PREFIX}`${JAVAROOT}
+dist_noinst_JAVA = test/*.java
+CLEANFILES = test/*.class
+
+dist_noinst_SCRIPTS += echo-test
+TESTS = echo-test
+endif
+
+endif
diff --git a/sandbox/sebastien/cpp/apr-2/components/chat/chat-sender.componentType b/sandbox/sebastien/cpp/apr-2/components/chat/chat-sender.componentType
new file mode 100644
index 0000000000..01838f0260
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/chat/chat-sender.componentType
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<componentType xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/components">
+
+ <service name="send"/>
+ <property name="jid" type="xsd:string"/>
+ <property name="password" type="xsd:string"/>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/components/chat/chat-sender.cpp b/sandbox/sebastien/cpp/apr-2/components/chat/chat-sender.cpp
new file mode 100644
index 0000000000..d3726a4e1c
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/chat/chat-sender.cpp
@@ -0,0 +1,150 @@
+/*
+ * 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$ */
+
+/**
+ * XMPP chat sender component implementation.
+ */
+
+#include "string.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "parallel.hpp"
+#include "xmpp.hpp"
+
+namespace tuscany {
+namespace chat {
+namespace sender {
+
+/**
+ * Post an item to an XMPP JID.
+ */
+const failable<value> post(const list<value>& params, XMPPClient& xc) {
+ const value to = car<value>(car(params));
+ const value val = cadr(params);
+ debug(to, "chat::post::jid");
+ debug(val, "chat::post::value");
+ const failable<bool> r = post(to, val, xc);
+ if (!hasContent(r))
+ return mkfailure<value>(reason(r));
+ return value(mklist<value>(to));
+}
+
+/**
+ * Subscribe and listen to an XMPP session.
+ */
+class noop {
+public:
+ noop() {
+ }
+
+ const failable<bool> operator()(unused const value& jid, unused const value& val, unused XMPPClient& xc) const {
+ return true;
+ }
+};
+
+class subscribe {
+public:
+ subscribe(XMPPClient& xc) : xc(xc) {
+ }
+
+ const failable<bool> operator()() const {
+ gc_pool pool;
+ debug("chat::subscribe::listen");
+ const failable<bool> r = listen(noop(), const_cast<XMPPClient&>(xc));
+ debug("chat::subscribe::stopped");
+ return r;
+ }
+
+private:
+ const lambda<failable<bool>(const value&, const value&, XMPPClient&)> l;
+ XMPPClient xc;
+};
+
+/**
+ * Chatter component lambda function
+ */
+class chatSender {
+public:
+ chatSender(XMPPClient& xc, worker& w) : xc(xc), w(w) {
+ }
+
+ const value operator()(const list<value>& params) const {
+ const tuscany::value func(car(params));
+ if (func == "post")
+ return post(cdr(params), const_cast<XMPPClient&>(xc));
+
+ // Stop the chat sender component
+ if (func != "stop")
+ return tuscany::mkfailure<tuscany::value>();
+ debug("chat::sender::stop");
+
+ // Disconnect and shutdown the worker thread
+ disconnect(const_cast<XMPPClient&>(xc));
+ cancel(const_cast<worker&>(w));
+ debug("chat::sender::stopped");
+
+ return failable<value>(value(lambda<value(const list<value>&)>()));
+ }
+
+private:
+ const XMPPClient xc;
+ worker w;
+};
+
+/**
+ * Start the component.
+ */
+const failable<value> start(const list<value>& params) {
+ // Extract the the XMPP JID and password
+ const list<value> props = params;
+ const value jid = ((lambda<value(list<value>)>)car(props))(list<value>());
+ const value pass = ((lambda<value(list<value>)>)cadr(props))(list<value>());
+
+ // Create an XMPP client session
+ XMPPClient xc(jid, pass, false);
+ const failable<bool> r = connect(xc);
+ if (!hasContent(r))
+ return mkfailure<value>(reason(r));
+
+ // Listen and relay messages in a worker thread
+ worker w(3);
+ submit<failable<bool> >(w, lambda<failable<bool>()>(subscribe(xc)));
+
+ // Return the chat sender component lambda function
+ return value(lambda<value(const list<value>&)>(chatSender(xc, w)));
+}
+
+}
+}
+}
+
+extern "C" {
+
+const tuscany::value apply(const tuscany::list<tuscany::value>& params) {
+ const tuscany::value func(car(params));
+ if (func == "start")
+ return tuscany::chat::sender::start(cdr(params));
+ return tuscany::mkfailure<tuscany::value>();
+}
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/chat/chat-sendreceiver.componentType b/sandbox/sebastien/cpp/apr-2/components/chat/chat-sendreceiver.componentType
new file mode 100644
index 0000000000..0367c38f55
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/chat/chat-sendreceiver.componentType
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<componentType xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/components">
+
+ <service name="send"/>
+ <reference name="relay"/>
+ <property name="jid" type="xsd:string"/>
+ <property name="password" type="xsd:string"/>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/components/chat/chat-sendreceiver.cpp b/sandbox/sebastien/cpp/apr-2/components/chat/chat-sendreceiver.cpp
new file mode 100644
index 0000000000..610f3cc9cc
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/chat/chat-sendreceiver.cpp
@@ -0,0 +1,164 @@
+/*
+ * 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$ */
+
+/**
+ * XMPP chat sender/receiver component implementation.
+ */
+
+#include "string.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "parallel.hpp"
+#include "xmpp.hpp"
+
+namespace tuscany {
+namespace chat {
+namespace sendreceiver {
+
+/**
+ * Post an item to an XMPP JID.
+ */
+const failable<value> post(const list<value>& params, XMPPClient& xc) {
+ const value to = car<value>(car(params));
+ const value val = cadr(params);
+ debug(to, "chat::post::jid");
+ debug(val, "chat::post::value");
+ const failable<bool> r = post(to, val, xc);
+ if (!hasContent(r))
+ return mkfailure<value>(reason(r));
+ return value(mklist<value>(to));
+}
+
+/**
+ * A relay function that posts the XMPP messages it receives to a relay component reference.
+ */
+class relay {
+public:
+ relay(const lambda<value(const list<value>&)>& rel) : rel(rel) {
+ }
+
+ const failable<bool> operator()(const value& jid, const value& val, unused XMPPClient& xc) const {
+ if (isNil(rel))
+ return true;
+ debug(jid, "chat::relay::jid");
+ debug(val, "chat::relay::value");
+ const value res = rel(mklist<value>("post", mklist<value>(jid), val));
+ return true;
+ }
+
+private:
+ const lambda<value(const list<value>&)> rel;
+};
+
+/**
+ * Subscribe and listen to an XMPP session.
+ */
+class subscribe {
+public:
+ subscribe(const lambda<failable<bool>(const value&, const value&, XMPPClient&)>& l, XMPPClient& xc) : l(l), xc(xc) {
+ }
+
+ const failable<bool> operator()() const {
+ gc_pool pool;
+ debug("chat::subscribe::listen");
+ const failable<bool> r = listen(l, const_cast<XMPPClient&>(xc));
+ debug("chat::subscribe::stopped");
+ return r;
+ }
+
+private:
+ const lambda<failable<bool>(const value&, const value&, XMPPClient&)> l;
+ XMPPClient xc;
+};
+
+/**
+ * Chat sender/receiver component lambda function
+ */
+class chatSenderReceiver {
+public:
+ chatSenderReceiver(XMPPClient& xc, worker& w) : xc(xc), w(w) {
+ }
+
+ const value operator()(const list<value>& params) const {
+ const tuscany::value func(car(params));
+ if (func == "post")
+ return post(cdr(params), const_cast<XMPPClient&>(xc));
+
+ // Stop the chat sender/receiver component
+ if (func != "stop")
+ return tuscany::mkfailure<tuscany::value>();
+ debug("chat::sendreceiver::stop");
+
+ // Disconnect and shutdown the worker thread
+ disconnect(const_cast<XMPPClient&>(xc));
+ cancel(const_cast<worker&>(w));
+ debug("chat::sendreceiver::stopped");
+
+ return failable<value>(value(lambda<value(const list<value>&)>()));
+ }
+
+private:
+ const XMPPClient xc;
+ worker w;
+};
+
+/**
+ * Start the component.
+ */
+const failable<value> start(const list<value>& params) {
+ // Extract the relay reference and the XMPP JID and password
+ const bool hasRelay = !isNil(cddr(params));
+ const value rel = hasRelay? car(params) : value(lambda<value(const list<value>&)>());
+ const list<value> props = hasRelay? cdr(params) : params;
+ const value jid = ((lambda<value(list<value>)>)car(props))(list<value>());
+ const value pass = ((lambda<value(list<value>)>)cadr(props))(list<value>());
+
+ // Create an XMPP client session
+ XMPPClient xc(jid, pass, false);
+ const failable<bool> r = connect(xc);
+ if (!hasContent(r))
+ return mkfailure<value>(reason(r));
+
+ // Listen and relay messages in a worker thread
+ worker w(3);
+ const lambda<failable<bool>(const value&, const value&, XMPPClient&)> rl = relay(rel);
+ submit<failable<bool> >(w, lambda<failable<bool>()>(subscribe(rl, xc)));
+
+ // Return the chat sender/receiver component lambda function
+ return value(lambda<value(const list<value>&)>(chatSenderReceiver(xc, w)));
+}
+
+}
+}
+}
+
+extern "C" {
+
+const tuscany::value apply(const tuscany::list<tuscany::value>& params) {
+ const tuscany::value func(car(params));
+ if (func == "start")
+ return tuscany::chat::sendreceiver::start(cdr(params));
+ return tuscany::mkfailure<tuscany::value>();
+}
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/chat/chat.composite b/sandbox/sebastien/cpp/apr-2/components/chat/chat.composite
new file mode 100644
index 0000000000..9eada5c372
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/chat/chat.composite
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/components"
+ name="chat">
+
+ <component name="print-sender">
+ <implementation.cpp path="." library="libchat-sender"/>
+ <property name="jid">sca1@localhost</property>
+ <property name="password">sca1</property>
+ <service name="print-sender">
+ <t:binding.http uri="print-sender"/>
+ </service>
+ </component>
+
+ <component name="print-chatter">
+ <implementation.cpp path="." library="libchat-sendreceiver"/>
+ <property name="jid">sca2@localhost</property>
+ <property name="password">sca2</property>
+ <service name="print-chatter">
+ <t:binding.http uri="print-chatter"/>
+ </service>
+ <reference name="relay" target="print"/>
+ </component>
+
+ <component name="print">
+ <t:implementation.scheme script="server-test.scm"/>
+ <service name="print">
+ <t:binding.http uri="print"/>
+ </service>
+ <reference name="report" target="print-chatter"/>
+ </component>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/components/chat/client-test.cpp b/sandbox/sebastien/cpp/apr-2/components/chat/client-test.cpp
new file mode 100644
index 0000000000..2c91fda1f2
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/chat/client-test.cpp
@@ -0,0 +1,111 @@
+/*
+ * 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 chat component.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "list.hpp"
+#include "element.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "perf.hpp"
+#include "parallel.hpp"
+#include "../../modules/http/http.hpp"
+#include "xmpp.hpp"
+
+namespace tuscany {
+namespace chat {
+
+const value jid1("sca1@localhost");
+const value pass1("sca1");
+const value jid2("sca2@localhost");
+const value pass2("sca2");
+const value jid3("sca3@localhost");
+const value pass3("sca3");
+
+const list<value> item = list<value>()
+ + (list<value>() + "name" + string("Apple"))
+ + (list<value>() + "price" + string("$2.99"));
+const list<value> entry = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), item);
+
+worker w(2);
+bool received;
+
+const failable<bool> listener(const value& from, const value& val, unused XMPPClient& xc) {
+ assert(contains(from, "sca2@localhost"));
+ assert(val == entry);
+ received = true;
+ return false;
+}
+
+struct subscribe {
+ XMPPClient& xc;
+ subscribe(XMPPClient& xc) : xc(xc) {
+ }
+ const failable<bool> operator()() const {
+ const lambda<failable<bool>(const value&, const value&, XMPPClient&)> l(listener);
+ listen(l, xc);
+ return true;
+ }
+};
+
+bool testListen() {
+ received = false;
+ XMPPClient& xc = *(new (gc_new<XMPPClient>()) XMPPClient(jid3, pass3));
+ const failable<bool> c = connect(xc);
+ assert(hasContent(c));
+ const lambda<failable<bool>()> subs = subscribe(xc);
+ submit(w, subs);
+ return true;
+}
+
+bool testPost() {
+ gc_scoped_pool pool;
+ http::CURLSession ch("", "", "");
+ const failable<value> id = http::post(entry, "http://localhost:8090/print-sender/sca2@localhost", ch);
+ assert(hasContent(id));
+ return true;
+}
+
+bool testReceived() {
+ shutdown(w);
+ assert(received == true);
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::chat::testListen();
+ tuscany::chat::testPost();
+ tuscany::chat::testReceived();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/chat/echo-test b/sandbox/sebastien/cpp/apr-2/components/chat/echo-test
new file mode 100755
index 0000000000..271d40d122
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/chat/echo-test
@@ -0,0 +1,31 @@
+#!/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
+./vysper-start
+sleep 3
+
+# Test
+./xmpp-test 2>/dev/null
+rc=$?
+
+# Cleanup
+./vysper-stop
+sleep 1
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/components/chat/server-test b/sandbox/sebastien/cpp/apr-2/components/chat/server-test
new file mode 100755
index 0000000000..dd1dc6faa7
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/chat/server-test
@@ -0,0 +1,39 @@
+#!/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 localhost 8090 ../../modules/http/htdocs
+../../modules/server/server-conf tmp
+../../modules/server/scheme-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+SCAContribution `pwd`/
+SCAComposite chat.composite
+EOF
+
+../../modules/http/httpd-start tmp
+sleep 2
+
+# Test
+./client-test 2>/dev/null
+rc=$?
+
+# Cleanup
+../../modules/http/httpd-stop tmp
+sleep 1
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/components/chat/server-test.scm b/sandbox/sebastien/cpp/apr-2/components/chat/server-test.scm
new file mode 100644
index 0000000000..a6023708e1
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/chat/server-test.scm
@@ -0,0 +1,20 @@
+; 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.
+
+; Chat test case
+
+(define (post key val report) (report "post" '("sca3@localhost") val))
diff --git a/sandbox/sebastien/cpp/apr-2/components/chat/test/TestVysperServer.java b/sandbox/sebastien/cpp/apr-2/components/chat/test/TestVysperServer.java
new file mode 100644
index 0000000000..3d2b7d7c3e
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/chat/test/TestVysperServer.java
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+package test;
+
+/**
+ * A test XMPP server, using Apache Vysper.
+ */
+import static java.lang.System.*;
+
+import java.io.File;
+
+import org.apache.vysper.mina.TCPEndpoint;
+import org.apache.vysper.stanzasession.StanzaSessionFactory;
+import org.apache.vysper.storage.StorageProviderRegistry;
+import org.apache.vysper.storage.inmemory.MemoryStorageProviderRegistry;
+import org.apache.vysper.xmpp.authorization.AccountManagement;
+import org.apache.vysper.xmpp.modules.extension.xep0049_privatedata.PrivateDataModule;
+import org.apache.vysper.xmpp.modules.extension.xep0054_vcardtemp.VcardTempModule;
+import org.apache.vysper.xmpp.modules.extension.xep0092_software_version.SoftwareVersionModule;
+import org.apache.vysper.xmpp.modules.extension.xep0119_xmppping.XmppPingModule;
+import org.apache.vysper.xmpp.modules.extension.xep0202_entity_time.EntityTimeModule;
+import org.apache.vysper.xmpp.server.XMPPServer;
+
+class TestVysperServer {
+ public static void main(final String args[]) throws Exception {
+ out.println("Starting test Vysper server...");
+
+ // Add the XMPP users used by the xmpp-test and server-test test cases
+ // If you're using your own XMPP server you need to add these users manually
+ final StorageProviderRegistry providerRegistry = new MemoryStorageProviderRegistry();
+ final AccountManagement accountManagement = (AccountManagement)providerRegistry.retrieve(AccountManagement.class);
+ accountManagement.addUser("sca1@localhost", "sca1");
+ accountManagement.addUser("sca2@localhost", "sca2");
+ accountManagement.addUser("sca3@localhost", "sca3");
+
+ // Create and start XMPP server for domain: localhost
+ final XMPPServer server = new org.apache.vysper.xmpp.server.XMPPServer("localhost");
+ server.addEndpoint(new TCPEndpoint());
+ server.addEndpoint(new StanzaSessionFactory());
+ server.setStorageProviderRegistry(providerRegistry);
+ final File cert = new File(TestVysperServer.class.getClassLoader().getResource("bogus_mina_tls.cert").getPath());
+ server.setTLSCertificateInfo(cert, "boguspw");
+ server.start();
+ server.addModule(new SoftwareVersionModule());
+ server.addModule(new EntityTimeModule());
+ server.addModule(new VcardTempModule());
+ server.addModule(new XmppPingModule());
+ server.addModule(new PrivateDataModule());
+ out.println("Test Vysper server started...");
+
+ // Wait forever
+ final Object lock = new Object();
+ synchronized(lock) {
+ lock.wait();
+ }
+
+ System.out.println("Stopping test Vysper server...");
+ server.stop();
+ out.println("Test Vysper server stopped.");
+ System.exit(0);
+ }
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/chat/vysper-classpath b/sandbox/sebastien/cpp/apr-2/components/chat/vysper-classpath
new file mode 100755
index 0000000000..7cf16a5ae8
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/chat/vysper-classpath
@@ -0,0 +1,29 @@
+#!/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.
+
+# Compute a classpath for running a Vysper server
+here=`readlink -f $0`; here=`dirname $here`
+
+if [ "$1" = "" ]; then
+ vysper_prefix=`cat $here/vysper.prefix`
+else
+ vysper_prefix=$1
+fi
+jars=`find $vysper_prefix/lib -name "*.jar" | awk '{ printf "%s:", $1 }'`
+echo "$vysper_prefix/config:$jars"
diff --git a/sandbox/sebastien/cpp/apr-2/components/chat/vysper-start b/sandbox/sebastien/cpp/apr-2/components/chat/vysper-start
new file mode 100755
index 0000000000..af95ecadf4
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/chat/vysper-start
@@ -0,0 +1,25 @@
+#!/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.
+
+# Start Vysper test XMPP server
+here=`readlink -f $0`; here=`dirname $here`
+
+java_prefix=`cat $here/../../modules/java/java.prefix`
+mkdir -p $here/tmp/logs
+${java_prefix}/jre/bin/java -cp `$here/vysper-classpath`$here test.TestVysperServer 2>&1 1>>$here/tmp/logs/vysper.log &
diff --git a/sandbox/sebastien/cpp/apr-2/components/chat/vysper-stop b/sandbox/sebastien/cpp/apr-2/components/chat/vysper-stop
new file mode 100755
index 0000000000..3c4be4efa9
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/chat/vysper-stop
@@ -0,0 +1,25 @@
+#!/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.
+
+# Stop Vysper test XMPP server
+here=`readlink -f $0`; here=`dirname $here`
+
+java_prefix=`cat $here/../../modules/java/java.prefix`
+kill `ps -ef | grep -v grep | grep "${java_prefix}/jre/bin/java" | grep "vysper" | awk '{ print $2 }'`
+
diff --git a/sandbox/sebastien/cpp/apr-2/components/chat/xmpp-test.cpp b/sandbox/sebastien/cpp/apr-2/components/chat/xmpp-test.cpp
new file mode 100644
index 0000000000..6b7fa3439f
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/chat/xmpp-test.cpp
@@ -0,0 +1,103 @@
+/*
+ * 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 XMPP support functions.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "list.hpp"
+#include "element.hpp"
+#include "monad.hpp"
+#include "value.hpp"
+#include "perf.hpp"
+#include "parallel.hpp"
+#include "xmpp.hpp"
+
+namespace tuscany {
+namespace chat {
+
+const value jid1("sca1@localhost");
+const value pass1("sca1");
+const value jid2("sca2@localhost");
+const value pass2("sca2");
+
+worker w(2);
+bool received;
+
+const failable<bool> listener(const value& from, const value& val, unused XMPPClient& xc) {
+ assert(contains(from, "sca1@localhost"));
+ assert(val == "hey");
+ received = true;
+ return false;
+}
+
+struct subscribe {
+ XMPPClient& xc;
+ subscribe(XMPPClient& xc) : xc(xc) {
+ }
+ const failable<bool> operator()() const {
+ const lambda<failable<bool>(const value&, const value&, XMPPClient&)> l(listener);
+ listen(l, xc);
+ return true;
+ }
+};
+
+bool testListen() {
+ received = false;
+ XMPPClient& xc = *(new (gc_new<XMPPClient>()) XMPPClient(jid2, pass2));
+ const failable<bool> c = connect(xc);
+ assert(hasContent(c));
+ const lambda<failable<bool>()> subs = subscribe(xc);
+ submit(w, subs);
+ return true;
+}
+
+bool testPost() {
+ XMPPClient xc(jid1, pass1);
+ const failable<bool> c = connect(xc);
+ assert(hasContent(c));
+ const failable<bool> p = post(jid2, "hey", xc);
+ assert(hasContent(p));
+ return true;
+}
+
+bool testReceived() {
+ shutdown(w);
+ assert(received == true);
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::chat::testListen();
+ tuscany::chat::testPost();
+ tuscany::chat::testReceived();
+
+ tuscany::cout << "OK" << tuscany::endl;
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/chat/xmpp.hpp b/sandbox/sebastien/cpp/apr-2/components/chat/xmpp.hpp
new file mode 100644
index 0000000000..3a6aa86c5c
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/chat/xmpp.hpp
@@ -0,0 +1,320 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_queue_hpp
+#define tuscany_queue_hpp
+
+/**
+ * XMPP support functions.
+ */
+
+#include "strophe.h"
+extern "C" {
+#include "common.h"
+}
+#include "string.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "../../modules/scheme/eval.hpp"
+
+namespace tuscany {
+namespace chat {
+
+/**
+ * XMPP runtime, one per process.
+ */
+class XMPPRuntime {
+public:
+ XMPPRuntime() {
+ xmpp_initialize();
+ log = xmpp_get_default_logger(XMPP_LEVEL_DEBUG);
+ }
+
+ ~XMPPRuntime() {
+ xmpp_shutdown();
+ }
+
+private:
+ friend class XMPPClient;
+ xmpp_log_t* log;
+
+} xmppRuntime;
+
+/**
+ * Represents an XMPP client.
+ */
+class XMPPClient {
+public:
+ XMPPClient(const string& jid, const string& pass, bool owner = true) : owner(owner), ctx(xmpp_ctx_new(NULL, xmppRuntime.log)), conn(xmpp_conn_new(ctx)), connecting(false), connected(false), disconnecting(false) {
+ xmpp_conn_set_jid(conn, c_str(jid + "/" + mkuuid()));
+ xmpp_conn_set_pass(conn, c_str(pass));
+ }
+
+ XMPPClient(const XMPPClient& xc) : owner(false), ctx(xc.ctx), conn(xc.conn), listener(xc.listener), connecting(xc.connecting), connected(xc.connected), disconnecting(xc.disconnecting) {
+ }
+
+ ~XMPPClient() {
+ extern const failable<bool> disconnect(XMPPClient& xc);
+ if (!owner)
+ return;
+ if (!disconnecting)
+ disconnect(*this);
+ xmpp_conn_release(conn);
+ xmpp_ctx_free(ctx);
+ }
+
+private:
+ friend int versionHandler(xmpp_conn_t* const conn, xmpp_stanza_t* const stanza, void* const udata);
+ friend void connHandler(xmpp_conn_t * const conn, const xmpp_conn_event_t status, const int err, xmpp_stream_error_t* const errstream, void *const udata);
+ friend int messageHandler(xmpp_conn_t* const conn, xmpp_stanza_t* const stanza, void* const udata);
+ friend const failable<bool> connect(XMPPClient& xc);
+ friend const failable<size_t> send(const char* data, const size_t len, XMPPClient& xc);
+ friend const failable<size_t> send(xmpp_stanza_t* const stanza, XMPPClient& xc);
+ friend const failable<bool> post(const value& to, const value& val, XMPPClient& xc);
+ friend const failable<bool> disconnect(XMPPClient& xc);
+ friend const failable<bool> listen(const lambda<failable<bool>(const value&, const value&, XMPPClient&)>& listener, XMPPClient& xc);
+
+ const bool owner;
+ xmpp_ctx_t* ctx;
+ xmpp_conn_t* conn;
+ lambda<failable<bool>(const value&, const value&, XMPPClient&)> listener;
+ bool connecting;
+ bool connected;
+ bool disconnecting;
+};
+
+/**
+ * Make a text stanza.
+ */
+xmpp_stanza_t* textStanza(const char* text, xmpp_ctx_t* ctx) {
+ xmpp_stanza_t* stanza = xmpp_stanza_new(ctx);
+ xmpp_stanza_set_text(stanza, text);
+ return stanza;
+}
+
+/**
+ * Make a named stanza.
+ */
+xmpp_stanza_t* namedStanza(const char* ns, const char* name, xmpp_ctx_t* ctx) {
+ xmpp_stanza_t* stanza = xmpp_stanza_new(ctx);
+ xmpp_stanza_set_name(stanza, name);
+ if (ns != NULL)
+ xmpp_stanza_set_ns(stanza, ns);
+ return stanza;
+}
+
+/**
+ * Make a named stanza using a qualified name.
+ */
+xmpp_stanza_t* namedStanza(const char* name, xmpp_ctx_t* ctx) {
+ xmpp_stanza_t* stanza = xmpp_stanza_new(ctx);
+ xmpp_stanza_set_name(stanza, name);
+ return stanza;
+}
+
+/**
+ * XMPP version handler.
+ */
+int versionHandler(xmpp_conn_t* const conn, xmpp_stanza_t* const stanza, void* const udata) {
+ XMPPClient& xc = *(XMPPClient*)udata;
+
+ // Build version reply stanza
+ xmpp_stanza_t* reply = namedStanza("iq", xc.ctx);
+ xmpp_stanza_set_type(reply, "result");
+ xmpp_stanza_set_id(reply, xmpp_stanza_get_id(stanza));
+ xmpp_stanza_set_attribute(reply, "to", xmpp_stanza_get_attribute(stanza, "from"));
+ xmpp_stanza_t* query = namedStanza(xmpp_stanza_get_ns(xmpp_stanza_get_children(stanza)), "query", xc.ctx);
+ xmpp_stanza_add_child(reply, query);
+ xmpp_stanza_t* name = namedStanza("name", xc.ctx);
+ xmpp_stanza_add_child(query, name);
+ xmpp_stanza_add_child(name, textStanza("Apache Tuscany", xc.ctx));
+ xmpp_stanza_t* version = namedStanza("version", xc.ctx);
+ xmpp_stanza_add_child(query, version);
+ xmpp_stanza_add_child(version, textStanza("1.0", xc.ctx));
+
+ // Send it
+ xmpp_send(conn, reply);
+ xmpp_stanza_release(reply);
+ return 1;
+}
+
+/**
+ * XMPP message handler
+ */
+int messageHandler(unused xmpp_conn_t* const conn, xmpp_stanza_t* const stanza, void* const udata) {
+ // Ignore noise
+ if(xmpp_stanza_get_child_by_name(stanza, "body") == NULL)
+ return 1;
+ if(!strcmp(xmpp_stanza_get_attribute(stanza, "type"), "error"))
+ return 1;
+
+ // Call the client listener function
+ XMPPClient& xc = *(XMPPClient*)udata;
+ const char* from = xmpp_stanza_get_attribute(stanza, "from");
+ const char* text = xmpp_stanza_get_text(xmpp_stanza_get_child_by_name(stanza, "body"));
+ if (isNil(xc.listener))
+ return 1;
+ const value val(scheme::readValue(text));
+ debug(from, "chat::messageHandler::from");
+ debug(val, "chat::messageHandler::body");
+ const failable<bool> r = xc.listener(value(string(from)), val, xc);
+ if (!hasContent(r) || !content(r)) {
+ // Stop listening
+ xc.listener = lambda<failable<bool>(const value&, const value&, XMPPClient&)>();
+ return 0;
+ }
+ return 1;
+}
+
+/**
+ * XMPP connection handler.
+ */
+void connHandler(xmpp_conn_t * const conn, const xmpp_conn_event_t status, unused const int err, unused xmpp_stream_error_t* const errstream, void *const udata) {
+ XMPPClient& xc = *(XMPPClient*)udata;
+ xc.connecting = false;
+
+ if (status == XMPP_CONN_CONNECT) {
+ debug("chat::connHandler::connected");
+ xmpp_handler_add(conn, versionHandler, "jabber:iq:version", "iq", NULL, &xc);
+
+ // Send a <presence/> stanza so that we appear online to contacts
+ xmpp_stanza_t* pres = xmpp_stanza_new(xc.ctx);
+ xmpp_stanza_set_name(pres, "presence");
+ xmpp_send(conn, pres);
+ xmpp_stanza_release(pres);
+ xc.connected = true;
+ return;
+ }
+
+ debug("chat::connHandler::disconnected");
+ xc.connected = false;
+ if (xc.ctx->loop_status == XMPP_LOOP_RUNNING)
+ xc.ctx->loop_status = XMPP_LOOP_QUIT;
+}
+
+/**
+ * Connect to an XMPP server.
+ */
+const failable<bool> connect(XMPPClient& xc) {
+ xc.connecting = true;
+ xmpp_connect_client(xc.conn, NULL, 0, connHandler, &xc);
+ while(xc.connecting)
+ xmpp_run_once(xc.ctx, 20L);
+ if (!xc.connected)
+ return mkfailure<bool>("Couldn't connect to XMPP server");
+ return true;
+}
+
+/**
+ * Send a buffer on an XMPP session.
+ */
+const failable<size_t> send(const char* data, const size_t len, XMPPClient& xc) {
+ if (len == 0)
+ return 0;
+ const size_t written = xc.conn->tls? tls_write(xc.conn->tls, data, len) : sock_write(xc.conn->sock, data, len);
+ if (written == (size_t)-1) {
+ xc.conn->error = xc.conn->tls? tls_error(xc.conn->tls) : sock_error();
+ return mkfailure<size_t>("Couldn't send stanza to XMPP server");
+ }
+ return send(data + written, len - written, xc);
+}
+
+/**
+ * Send a string on an XMPP session.
+ */
+const failable<size_t> send(const string& data, XMPPClient& xc) {
+ return send(c_str(data), length(data), xc);
+}
+
+/**
+ * Send a stanza on an XMPP session.
+ */
+const failable<size_t> send(xmpp_stanza_t* const stanza, XMPPClient& xc) {
+ char *buf;
+ size_t len;
+ const int rc = xmpp_stanza_to_text(stanza, &buf, &len);
+ if (rc != 0)
+ return mkfailure<size_t>("Couldn't convert stanza to text");
+ const failable<size_t> r = send(buf, len, xc);
+ if (!hasContent(r)) {
+ xmpp_free(xc.conn->ctx, buf);
+ return r;
+ }
+ xmpp_debug(xc.conn->ctx, "conn", "SENT: %s", buf);
+ xmpp_free(xc.conn->ctx, buf);
+ return content(r);
+}
+
+/**
+ * Post a message to an XMPP jid.
+ */
+const failable<bool> post(const value& to, const value& val, XMPPClient& xc) {
+ debug(to, "chat::post::to");
+ debug(val, "chat::post::body");
+
+ // Convert the value to a string
+ const string vs(scheme::writeValue(val));
+
+ // Build message stanza
+ xmpp_stanza_t* stanza = namedStanza("message", xc.ctx);
+ xmpp_stanza_set_type(stanza, "chat");
+ xmpp_stanza_set_attribute(stanza, "to", c_str(string(to)));
+ xmpp_stanza_t* body = namedStanza("body", xc.ctx);
+ xmpp_stanza_add_child(stanza, body);
+ xmpp_stanza_add_child(body, textStanza(c_str(vs), xc.ctx));
+
+ // Send it
+ const failable<size_t> r = send(stanza, xc);
+ xmpp_stanza_release(stanza);
+ if (!hasContent(r))
+ return mkfailure<bool>(reason(r));
+ return true;
+}
+
+/**
+ * Disconnect an XMPP session.
+ */
+const failable<bool> disconnect(XMPPClient& xc) {
+ xc.disconnecting = true;
+ const failable<size_t> r = send("</stream:stream>", xc);
+ if (!hasContent(r))
+ return mkfailure<bool>(reason(r));
+ return true;
+}
+
+/**
+ * Listen to messages received by an XMPP client.
+ */
+const failable<bool> listen(const lambda<failable<bool>(const value&, const value&, XMPPClient&)>& listener, XMPPClient& xc) {
+ debug("chat::listen");
+ xc.listener = listener;
+ xmpp_handler_add(xc.conn, messageHandler, NULL, "message", NULL, &xc);
+ xc.ctx->loop_status = XMPP_LOOP_RUNNING;
+ while(xc.connected && !isNil(xc.listener) && xc.ctx->loop_status == XMPP_LOOP_RUNNING)
+ xmpp_run_once(xc.ctx, 1000L);
+ return true;
+}
+
+}
+}
+
+#endif /* tuscany_xmpp_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/components/filedb/Makefile.am b/sandbox/sebastien/cpp/apr-2/components/filedb/Makefile.am
new file mode 100644
index 0000000000..90c8b4207d
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/filedb/Makefile.am
@@ -0,0 +1,44 @@
+# 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.
+
+INCLUDES = -I${TINYCDB_INCLUDE}
+
+incl_HEADERS = *.hpp
+incldir = $(prefix)/include/components/filedb
+
+compdir=$(prefix)/components/filedb
+
+EXTRA_DIST = filedb.composite filedb.componentType
+
+comp_LTLIBRARIES = libfiledb.la
+noinst_DATA = libfiledb.so
+
+libfiledb_la_SOURCES = filedb.cpp
+libfiledb_la_LDFLAGS = -lxml2 -lmozjs
+libfiledb.so:
+ ln -s .libs/libfiledb.so
+
+file_test_SOURCES = file-test.cpp
+file_test_LDFLAGS = -lxml2 -lmozjs
+
+client_test_SOURCES = client-test.cpp
+client_test_LDFLAGS = -lxml2 -lcurl -lmozjs
+
+dist_noinst_SCRIPTS = filedb-test server-test
+noinst_PROGRAMS = file-test client-test
+TESTS = filedb-test server-test
+
diff --git a/sandbox/sebastien/cpp/apr-2/components/filedb/client-test.cpp b/sandbox/sebastien/cpp/apr-2/components/filedb/client-test.cpp
new file mode 100644
index 0000000000..a65ec45341
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/filedb/client-test.cpp
@@ -0,0 +1,130 @@
+/*
+ * 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 file database component.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "perf.hpp"
+#include "../../modules/http/http.hpp"
+
+namespace tuscany {
+namespace filedb {
+
+const string uri("http://localhost:8090/filedb");
+
+bool testFileDB() {
+ http::CURLSession cs("", "", "");
+
+ const list<value> i = list<value>()
+ + (list<value>() + "name" + string("Apple"))
+ + (list<value>() + "price" + string("$2.99"));
+ const list<value> a = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
+
+ const failable<value> id = http::post(a, uri, cs);
+ assert(hasContent(id));
+
+ const string p = path(content(id));
+ {
+ const failable<value> val = http::get(uri + p, cs);
+ assert(hasContent(val));
+ assert(content(val) == a);
+ }
+
+ const list<value> j = list<value>()
+ + (list<value>() + "name" + string("Apple"))
+ + (list<value>() + "price" + string("$3.55"));
+ const list<value> b = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), j);
+
+ {
+ const failable<value> r = http::put(b, uri + p, cs);
+ assert(hasContent(r));
+ assert(content(r) == value(true));
+ }
+ {
+ const failable<value> val = http::get(uri + p, cs);
+ assert(hasContent(val));
+ assert(content(val) == b);
+ }
+ {
+ const failable<value> r = http::del(uri + p, cs);
+ assert(hasContent(r));
+ assert(content(r) == value(true));
+ }
+ {
+ const failable<value> val = http::get(uri + p, cs);
+ assert(!hasContent(val));
+ }
+
+ return true;
+}
+
+struct getLoop {
+ const string path;
+ const value entry;
+ http::CURLSession cs;
+ getLoop(const string& path, const value& entry, http::CURLSession cs) : path(path), entry(entry), cs(cs) {
+ }
+ const bool operator()() const {
+ const failable<value> val = http::get(uri + path, cs);
+ assert(hasContent(val));
+ assert(content(val) == entry);
+ return true;
+ }
+};
+
+bool testGetPerf() {
+ const list<value> i = list<value>()
+ + (list<value>() + "name" + string("Apple"))
+ + (list<value>() + "price" + string("$4.55"));
+ const value a = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
+
+ http::CURLSession cs("", "", "");
+ const failable<value> id = http::post(a, uri, cs);
+ assert(hasContent(id));
+ const string p = path(content(id));
+
+ const lambda<bool()> gl = getLoop(p, a, cs);
+ cout << "FileDB get test " << time(gl, 5, 200) << " ms" << endl;
+
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::filedb::testFileDB();
+ tuscany::filedb::testGetPerf();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/filedb/file-test.cpp b/sandbox/sebastien/cpp/apr-2/components/filedb/file-test.cpp
new file mode 100644
index 0000000000..ff57bd79ce
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/filedb/file-test.cpp
@@ -0,0 +1,94 @@
+/*
+ * 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 FileDB access functions.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "perf.hpp"
+#include "filedb.hpp"
+
+namespace tuscany {
+namespace filedb {
+
+bool testFileDB(const string& dbname, const string& format) {
+ FileDB db(dbname, format);
+ const value k = mklist<value>("a", "b");
+
+ const list<value> a = mklist<value>(list<value>() + "ns1:a" + (list<value>() + "@xmlns:ns1" + string("http://aaa")) + (list<value>() + "text" + string("Hey!")));
+ const list<value> b = mklist<value>(list<value>() + "ns1:b" + (list<value>() + "@xmlns:ns1" + string("http://bbb")) + (list<value>() + "text" + string("Hey!")));
+
+ assert(hasContent(post(k, a, db)));
+ assert((get(k, db)) == value(a));
+ assert(hasContent(put(k, b, db)));
+ assert((get(k, db)) == value(b));
+ assert(hasContent(del(k, db)));
+ assert(!hasContent(get(k, db)));
+ assert(hasContent(post(k, a, db)));
+
+ return true;
+}
+
+struct getLoop {
+ const value k;
+ FileDB& db;
+ const list<value> c;
+ getLoop(const value& k, FileDB& db) : k(k), db(db),
+ c(mklist<value>(list<value>() + "ns1:c" + (list<value>() + "@xmlns:ns1" + string("http://ccc")) + (list<value>() + "text" + string("Hey!")))) {
+ }
+ const bool operator()() const {
+ assert((get(k, db)) == value(c));
+ return true;
+ }
+};
+
+bool testGetPerf(const string& dbname, const string& format) {
+ FileDB db(dbname, format);
+
+ const value k = mklist<value>("c");
+ const list<value> c = mklist<value>(list<value>() + "ns1:c" + (list<value>() + "@xmlns:ns1" + string("http://ccc")) + (list<value>() + "text" + string("Hey!")));
+ assert(hasContent(post(k, c, db)));
+
+ const lambda<bool()> gl = getLoop(k, db);
+ cout << "FileDB get test " << time(gl, 5, 5000) << " ms" << endl;
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::filedb::testFileDB("tmp/schemedb", "scheme");
+ tuscany::filedb::testGetPerf("tmp/schemedb", "scheme");
+ tuscany::filedb::testFileDB("tmp/xmldb", "xml");
+ tuscany::filedb::testGetPerf("tmp/xmldb", "xml");
+ tuscany::filedb::testFileDB("tmp/jsondb", "json");
+ tuscany::filedb::testGetPerf("tmp/jsondb", "json");
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/filedb/filedb-test b/sandbox/sebastien/cpp/apr-2/components/filedb/filedb-test
new file mode 100755
index 0000000000..083bd1b96c
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/filedb/filedb-test
@@ -0,0 +1,31 @@
+#!/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
+mkdir -p tmp
+mkdir -p tmp/schemedb
+mkdir -p tmp/xmldb
+mkdir -p tmp/jsondb
+
+# Test
+./file-test 2>/dev/null
+rc=$?
+
+# Cleanup
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/components/filedb/filedb.componentType b/sandbox/sebastien/cpp/apr-2/components/filedb/filedb.componentType
new file mode 100644
index 0000000000..31f996ef3e
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/filedb/filedb.componentType
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<componentType xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/components">
+
+ <service name="filedb"/>
+ <property name="dbname" type="xsd:string"/>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/components/filedb/filedb.composite b/sandbox/sebastien/cpp/apr-2/components/filedb/filedb.composite
new file mode 100644
index 0000000000..05a2d50847
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/filedb/filedb.composite
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/components"
+ name="filedb">
+
+ <component name="filedb">
+ <implementation.cpp path="." library="libfiledb"/>
+ <property name="dbname">tmp/testdb</property>
+ <property name="format">scheme</property>
+ <service name="filedb">
+ <t:binding.http uri="filedb"/>
+ </service>
+ </component>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/components/filedb/filedb.cpp b/sandbox/sebastien/cpp/apr-2/components/filedb/filedb.cpp
new file mode 100644
index 0000000000..473dfea281
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/filedb/filedb.cpp
@@ -0,0 +1,124 @@
+/*
+ * 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$ */
+
+/**
+ * File based database component implementation.
+ */
+
+#include "string.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "filedb.hpp"
+
+namespace tuscany {
+namespace filedb {
+
+/**
+ * Get an item from the database.
+ */
+const failable<value> get(const list<value>& params, filedb::FileDB& db) {
+ return filedb::get(car(params), db);
+}
+
+/**
+ * Post an item to the database.
+ */
+const failable<value> post(const list<value>& params, filedb::FileDB& db) {
+ const value id = append<value>(car(params), mklist(mkuuid()));
+ const failable<bool> val = filedb::post(id, cadr(params), db);
+ if (!hasContent(val))
+ return mkfailure<value>(reason(val));
+ return id;
+}
+
+/**
+ * Put an item into the database.
+ */
+const failable<value> put(const list<value>& params, filedb::FileDB& db) {
+ const failable<bool> val = filedb::put(car(params), cadr(params), db);
+ if (!hasContent(val))
+ return mkfailure<value>(reason(val));
+ return value(content(val));
+}
+
+/**
+ * Delete an item from the database.
+ */
+const failable<value> del(const list<value>& params, filedb::FileDB& db) {
+ const failable<bool> val = filedb::del(car(params), db);
+ if (!hasContent(val))
+ return mkfailure<value>(reason(val));
+ return value(content(val));
+}
+
+/**
+ * Component implementation lambda function.
+ */
+class applyfiledb {
+public:
+ applyfiledb(filedb::FileDB& db) : db(db) {
+ }
+
+ const value operator()(const list<value>& params) const {
+ const value func(car(params));
+ if (func == "get")
+ return get(cdr(params), db);
+ if (func == "post")
+ return post(cdr(params), db);
+ if (func == "put")
+ return put(cdr(params), db);
+ if (func == "delete")
+ return del(cdr(params), db);
+ return tuscany::mkfailure<tuscany::value>();
+ }
+
+private:
+ filedb::FileDB& db;
+};
+
+/**
+ * Start the component.
+ */
+const failable<value> start(const list<value>& params) {
+ // Connect to the configured database and table
+ const value dbname = ((lambda<value(list<value>)>)car(params))(list<value>());
+ const value format = ((lambda<value(list<value>)>)cadr(params))(list<value>());
+ filedb::FileDB& db = *(new (gc_new<filedb::FileDB>()) filedb::FileDB(dbname, format));
+
+ // Return the component implementation lambda function
+ return value(lambda<value(const list<value>&)>(applyfiledb(db)));
+}
+
+}
+}
+
+extern "C" {
+
+const tuscany::value apply(const tuscany::list<tuscany::value>& params) {
+ const tuscany::value func(car(params));
+ if (func == "start")
+ return tuscany::filedb::start(cdr(params));
+ return tuscany::mkfailure<tuscany::value>();
+}
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/filedb/filedb.hpp b/sandbox/sebastien/cpp/apr-2/components/filedb/filedb.hpp
new file mode 100644
index 0000000000..89ff3b8157
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/filedb/filedb.hpp
@@ -0,0 +1,225 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_filedb_hpp
+#define tuscany_filedb_hpp
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include "string.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "fstream.hpp"
+#include "element.hpp"
+#include "xml.hpp"
+#include "../../modules/scheme/eval.hpp"
+#include "../../modules/json/json.hpp"
+
+namespace tuscany {
+namespace filedb {
+
+/**
+ * Represents a FileDB connection.
+ */
+class FileDB {
+public:
+ FileDB() : owner(false), jscx(*jscontext("")) {
+ }
+
+ FileDB(const string& name, const string& format) : owner(true), name(name), format(format), jscx(*jscontext(format)) {
+ }
+
+ FileDB(const FileDB& c) : owner(false), name(c.name), format(c.format), jscx(c.jscx) {
+ }
+
+ ~FileDB() {
+ }
+
+private:
+ bool owner;
+ string name;
+ string format;
+ js::JSContext& jscx;
+
+ js::JSContext* jscontext(const string& format) {
+ if (format != "json")
+ return NULL;
+ return new (gc_new<js::JSContext>()) js::JSContext();
+ }
+
+ friend const failable<bool> write(const value& v, ostream& os, const string& format, FileDB& db);
+ friend const failable<value> read(istream& is, const string& format, FileDB& db);
+ friend const failable<bool> post(const value& key, const value& val, FileDB& db);
+ friend const failable<bool> put(const value& key, const value& val, FileDB& db);
+ friend const failable<value> get(const value& key, FileDB& db);
+ friend const failable<bool> del(const value& key, FileDB& db);
+};
+
+/**
+ * Convert a key to a file name.
+ */
+const string filename(const list<value>& path, const string& root) {
+ if (isNil(path))
+ return root;
+ string name = root + "/" + scheme::writeValue(car(path));
+ return filename(cdr(path), name);
+}
+
+const string filename(const value& key, const string& root) {
+ if (!isList(key))
+ return filename(mklist(key), root);
+ return filename((list<value>)key, root);
+}
+
+/**
+ * Make the parent directories of a keyed file.
+ */
+const failable<bool> mkdirs(const list<value>& path, const string& root) {
+ if (isNil(cdr(path)))
+ return true;
+ string dir = root + "/" + scheme::writeValue(car(path));
+ mkdir(c_str(dir), S_IRWXU);
+ return mkdirs(cdr(path), dir);
+}
+
+/**
+ * Write a value to a database file.
+ */
+const failable<bool> write(const value& v, ostream& os, const string& format, FileDB& db) {
+ if (format == "scheme") {
+ const string vs(scheme::writeValue(v));
+ os << vs;
+ return true;
+ }
+ if (format == "xml") {
+ failable<list<string> > s = writeXML(valuesToElements(v));
+ if (!hasContent(s))
+ return mkfailure<bool>(reason(s));
+ write(content(s), os);
+ return true;
+ }
+ if (format == "json") {
+ failable<list<string> > s = json::writeJSON(valuesToElements(v), db.jscx);
+ if (!hasContent(s))
+ return mkfailure<bool>(reason(s));
+ write(content(s), os);
+ return true;
+ }
+ return mkfailure<bool>(string("Unsupported database format: ") + format);
+}
+
+/**
+ * Read a value from a database file.
+ */
+const failable<value> read(istream& is, const string& format, FileDB& db) {
+ if (format == "scheme") {
+ return scheme::readValue(is);
+ }
+ if (format == "xml") {
+ const value v = elementsToValues(readXML(streamList(is)));
+ return v;
+ }
+ if (format == "json") {
+ const failable<list<value> > fv = json::readJSON(streamList(is), db.jscx);
+ if (!hasContent(fv))
+ return mkfailure<value>(reason(fv));
+ const value v = elementsToValues(content(fv));
+ return v;
+ }
+ return mkfailure<value>(string("Unsupported database format: ") + format);
+}
+
+/**
+ * Post a new item to the database.
+ */
+const failable<bool> post(const value& key, const value& val, FileDB& db) {
+ debug(key, "filedb::post::key");
+ debug(val, "filedb::post::value");
+ debug(db.name, "filedb::post::dbname");
+
+ if (isList(key))
+ mkdirs(key, db.name);
+ ofstream os(filename(key, db.name));
+ if (os.fail())
+ return mkfailure<bool>("Couldn't post file database entry.");
+ const failable<bool> r = write(val, os, db.format, db);
+
+ debug(r, "filedb::post::result");
+ return r;
+}
+
+/**
+ * Update an item in the database. If the item doesn't exist it is added.
+ */
+const failable<bool> put(const value& key, const value& val, FileDB& db) {
+ debug(key, "filedb::put::key");
+ debug(val, "filedb::put::value");
+ debug(db.name, "filedb::put::dbname");
+
+ if (isList(key))
+ mkdirs(key, db.name);
+ ofstream os(filename(key, db.name));
+ if (os.fail())
+ return mkfailure<bool>("Couldn't put file database entry.");
+ const failable<bool> r = write(val, os, db.format, db);
+
+ debug(r, "filedb::put::result");
+ return r;
+}
+
+/**
+ * Get an item from the database.
+ */
+const failable<value> get(const value& key, FileDB& db) {
+ debug(key, "filedb::get::key");
+ debug(db.name, "filedb::get::dbname");
+
+ ifstream is(filename(key, db.name));
+ if (is.fail())
+ return mkfailure<value>("Couldn't get file database entry.");
+ const failable<value> val = read(is, db.format, db);
+
+ debug(val, "filedb::get::result");
+ return val;
+}
+
+/**
+ * Delete an item from the database
+ */
+const failable<bool> del(const value& key, FileDB& db) {
+ debug(key, "filedb::delete::key");
+ debug(db.name, "filedb::delete::dbname");
+
+ const int rc = unlink(c_str(filename(key, db.name)));
+ if (rc == -1)
+ return mkfailure<bool>("Couldn't delete file database entry.");
+
+ debug(true, "filedb::delete::result");
+ return true;
+}
+
+}
+}
+
+#endif /* tuscany_filedb_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/components/filedb/server-test b/sandbox/sebastien/cpp/apr-2/components/filedb/server-test
new file mode 100755
index 0000000000..ace8dd59e2
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/filedb/server-test
@@ -0,0 +1,40 @@
+#!/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 localhost 8090 ../../modules/http/htdocs
+../../modules/server/server-conf tmp
+../../modules/server/scheme-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+SCAContribution `pwd`/
+SCAComposite filedb.composite
+EOF
+
+mkdir -p tmp/testdb
+../../modules/http/httpd-start tmp
+sleep 2
+
+# Test
+./client-test 2>/dev/null
+rc=$?
+
+# Cleanup
+../../modules/http/httpd-stop tmp
+sleep 2
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/components/log/Makefile.am b/sandbox/sebastien/cpp/apr-2/components/log/Makefile.am
new file mode 100644
index 0000000000..c53230b23f
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/log/Makefile.am
@@ -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.
+
+if WANT_LOG
+
+INCLUDES = -I${THRIFT_INCLUDE} -I${FB303_INCLUDE}
+
+incl_HEADERS = *.hpp
+incldir = $(prefix)/include/components/log
+
+dist_comp_SCRIPTS = scribed-central-conf scribed-client-conf scribed-central-start scribed-central-stop scribed-client-start scribed-client-stop scribe-tail-start scribe-tail-stop
+compdir=$(prefix)/components/log
+
+comp_DATA = scribe.prefix thrift.prefix
+scribe.prefix: $(top_builddir)/config.status
+ echo ${SCRIBE_PREFIX} >scribe.prefix
+
+thrift.prefix: $(top_builddir)/config.status
+ echo ${THRIFT_PREFIX} >thrift.prefix
+
+EXTRA_DIST = log.composite log.componentType logger.componentType *.scm *.thrift
+
+BUILT_SOURCES=gen-cpp/fb303_constants.cpp gen-cpp/fb303_types.cpp gen-cpp/scribe_constants.cpp gen-cpp/scribe.cpp gen-cpp/scribe_types.cpp gen-cpp/FacebookService.cpp gen-cpp/scribe.h
+gen-cpp/fb303_constants.cpp gen-cpp/fb303_types.cpp gen-cpp/scribe_constants.cpp gen-cpp/scribe.cpp gen-cpp/scribe_types.cpp gen-cpp/FacebookService.cpp gen-cpp/scribe.h: scribe.thrift
+ ${THRIFT_PREFIX}/bin/thrift -r --gen cpp scribe.thrift
+
+CLEANFILES = gen-cpp/*
+
+comp_LTLIBRARIES = liblog.la liblogger.la
+noinst_DATA = liblog.so liblogger.so
+
+CXXFLAGS = ${DEFAULT_CXXFLAGS} -Wno-unused-parameter -Wno-conversion
+
+nodist_liblog_la_SOURCES = gen-cpp/fb303_constants.cpp gen-cpp/fb303_types.cpp gen-cpp/scribe_constants.cpp gen-cpp/scribe.cpp gen-cpp/scribe_types.cpp gen-cpp/FacebookService.cpp gen-cpp/scribe.h
+liblog_la_CXXFLAGS = -Wno-unused-parameter -Wno-conversion
+liblog_la_SOURCES = log.cpp
+liblog_la_LDFLAGS = -L${THRIFT_LIB} -R${THRIFT_LIB} -lthrift -L${FB303_LIB} -R${FB303_LIB} -lfb303 -L${SCRIBE_LIB} -R${SCRIBE_LIB} -lscribe
+liblog.so:
+ ln -s .libs/liblog.so
+
+nodist_liblogger_la_SOURCES = gen-cpp/fb303_constants.cpp gen-cpp/fb303_types.cpp gen-cpp/scribe_constants.cpp gen-cpp/scribe.cpp gen-cpp/scribe_types.cpp gen-cpp/FacebookService.cpp gen-cpp/scribe.h
+liblogger_la_CXXFLAGS = -Wno-unused-parameter -Wno-conversion
+liblogger_la_SOURCES = logger.cpp
+liblogger_la_LDFLAGS = -L${THRIFT_LIB} -R${THRIFT_LIB} -lthrift -L${FB303_LIB} -R${FB303_LIB} -lfb303 -L${SCRIBE_LIB} -R${SCRIBE_LIB} -lscribe
+liblogger.so:
+ ln -s .libs/liblogger.so
+
+comp_PROGRAMS = scribe-cat
+
+nodist_scribe_cat_SOURCES = gen-cpp/fb303_constants.cpp gen-cpp/fb303_types.cpp gen-cpp/scribe_constants.cpp gen-cpp/scribe.cpp gen-cpp/scribe_types.cpp gen-cpp/FacebookService.cpp gen-cpp/scribe.h
+scribe_cat_CXXFLAGS = -Wno-unused-parameter -Wno-conversion
+scribe_cat_SOURCES = scribe-cat.cpp
+scribe_cat_LDFLAGS = -L${THRIFT_LIB} -R${THRIFT_LIB} -lthrift -L${FB303_LIB} -R${FB303_LIB} -lfb303 -L${SCRIBE_LIB} -R${SCRIBE_LIB} -lscribe
+
+client_test_SOURCES = client-test.cpp
+client_test_LDFLAGS = -lxml2 -lcurl -lmozjs
+
+dist_noinst_SCRIPTS = scribe-test server-test
+noinst_PROGRAMS = client-test
+TESTS = scribe-test server-test
+
+endif
diff --git a/sandbox/sebastien/cpp/apr-2/components/log/adder-test.scm b/sandbox/sebastien/cpp/apr-2/components/log/adder-test.scm
new file mode 100644
index 0000000000..ccd5bc555f
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/log/adder-test.scm
@@ -0,0 +1,20 @@
+; 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.
+
+; Logger test case
+
+(define (add a b) (+ a b))
diff --git a/sandbox/sebastien/cpp/apr-2/components/log/client-test.cpp b/sandbox/sebastien/cpp/apr-2/components/log/client-test.cpp
new file mode 100644
index 0000000000..5f13f64ac1
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/log/client-test.cpp
@@ -0,0 +1,107 @@
+/*
+ * 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 log component.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "perf.hpp"
+#include "../../modules/http/http.hpp"
+
+namespace tuscany {
+namespace log {
+
+const string uri("http://localhost:8090/log");
+
+bool testLog() {
+ http::CURLSession cs("", "", "");
+
+ const list<value> i = list<value>()
+ + (list<value>() + "name" + string("Apple"))
+ + (list<value>() + "price" + string("$2.99"));
+ const list<value> a = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
+
+ const failable<value> id = http::post(a, uri, cs);
+ assert(hasContent(id));
+
+ return true;
+}
+
+struct logLoop {
+ const value a;
+ const string uri;
+ http::CURLSession cs;
+ logLoop(const value& a, const string& uri, http::CURLSession cs) : a(a), uri(uri), cs(cs) {
+ }
+ const bool operator()() const {
+ const failable<value> id = http::post(a, uri, cs);
+ assert(hasContent(id));
+ return true;
+ }
+};
+
+bool testLogPerf() {
+ const list<value> i = list<value>()
+ + (list<value>() + "name" + string("Apple"))
+ + (list<value>() + "price" + string("$2.99"));
+ const value a = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
+
+ http::CURLSession cs("", "", "");
+ const failable<value> id = http::post(a, uri, cs);
+ assert(hasContent(id));
+
+ const lambda<bool()> ll = logLoop(a, uri, cs);
+ cout << "Log test " << time(ll, 5, 200) << " ms" << endl;
+
+ return true;
+}
+
+bool testLogger() {
+ http::CURLSession cs("", "", "");
+
+ const failable<value> res = http::evalExpr(mklist<value>(string("sum"), 33, 22), string("http://localhost:8090/client"), cs);
+ assert(hasContent(res));
+ assert((int)content(res) == 55);
+
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::log::testLog();
+ tuscany::log::testLogPerf();
+ tuscany::log::testLogger();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/log/client-test.scm b/sandbox/sebastien/cpp/apr-2/components/log/client-test.scm
new file mode 100644
index 0000000000..1da6ca3564
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/log/client-test.scm
@@ -0,0 +1,20 @@
+; 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.
+
+; Logger test case
+
+(define (sum a b adder) (adder "add" a b))
diff --git a/sandbox/sebastien/cpp/apr-2/components/log/fb303.thrift b/sandbox/sebastien/cpp/apr-2/components/log/fb303.thrift
new file mode 100644
index 0000000000..66c8315274
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/log/fb303.thrift
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+/**
+ * fb303.thrift
+ */
+
+namespace java com.facebook.fb303
+namespace cpp facebook.fb303
+namespace perl Facebook.FB303
+
+/**
+ * Common status reporting mechanism across all services
+ */
+enum fb_status {
+ DEAD = 0,
+ STARTING = 1,
+ ALIVE = 2,
+ STOPPING = 3,
+ STOPPED = 4,
+ WARNING = 5,
+}
+
+/**
+ * Standard base service
+ */
+service FacebookService {
+
+ /**
+ * Returns a descriptive name of the service
+ */
+ string getName(),
+
+ /**
+ * Returns the version of the service
+ */
+ string getVersion(),
+
+ /**
+ * Gets the status of this service
+ */
+ fb_status getStatus(),
+
+ /**
+ * User friendly description of status, such as why the service is in
+ * the dead or warning state, or what is being started or stopped.
+ */
+ string getStatusDetails(),
+
+ /**
+ * Gets the counters for this service
+ */
+ map<string, i64> getCounters(),
+
+ /**
+ * Gets the value of a single counter
+ */
+ i64 getCounter(1: string key),
+
+ /**
+ * Sets an option
+ */
+ void setOption(1: string key, 2: string value),
+
+ /**
+ * Gets an option
+ */
+ string getOption(1: string key),
+
+ /**
+ * Gets all options
+ */
+ map<string, string> getOptions(),
+
+ /**
+ * Returns a CPU profile over the given time interval (client and server
+ * must agree on the profile format).
+ */
+ string getCpuProfile(1: i32 profileDurationInSec),
+
+ /**
+ * Returns the unix time that the server has been running since
+ */
+ i64 aliveSince(),
+
+ /**
+ * Tell the server to reload its configuration, reopen log files, etc
+ */
+ oneway void reinitialize(),
+
+ /**
+ * Suggest a shutdown to the server
+ */
+ oneway void shutdown(),
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/log/log.componentType b/sandbox/sebastien/cpp/apr-2/components/log/log.componentType
new file mode 100644
index 0000000000..e661f568f1
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/log/log.componentType
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<componentType xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/components">
+
+ <service name="log"/>
+ <property name="category" type="xsd:string">default</property>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/components/log/log.composite b/sandbox/sebastien/cpp/apr-2/components/log/log.composite
new file mode 100644
index 0000000000..3e13c410fa
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/log/log.composite
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/components"
+ name="log">
+
+ <component name="log">
+ <implementation.cpp path="." library="liblog"/>
+ <property name="category">default</property>
+ <service name="log">
+ <t:binding.http uri="log"/>
+ </service>
+ </component>
+
+ <component name="client">
+ <implementation.scheme script="client-test.scm"/>
+ <service name="client">
+ <t:binding.http uri="client"/>
+ </service>
+ <reference name="adder" target="logger"/>
+ </component>
+
+ <component name="logger">
+ <implementation.cpp path="." library="liblogger"/>
+ <property name="category">default</property>
+ <service name="logger">
+ <t:binding.http uri="logger"/>
+ </service>
+ <reference name="relay" target="adder"/>
+ </component>
+
+ <component name="adder">
+ <implementation.scheme script="adder-test.scm"/>
+ <service name="adder">
+ <t:binding.http uri="adder"/>
+ </service>
+ </component>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/components/log/log.cpp b/sandbox/sebastien/cpp/apr-2/components/log/log.cpp
new file mode 100644
index 0000000000..24a5844c45
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/log/log.cpp
@@ -0,0 +1,94 @@
+/*
+ * 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$ */
+
+/**
+ * Scribe-based log component implementation.
+ */
+
+#include "string.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "scribe.hpp"
+
+namespace tuscany {
+namespace log {
+
+/**
+ * Post an item to the Scribe log.
+ */
+const failable<value> post(const list<value>& params, const value& category, scribe::Scribe& sc) {
+ debug(cadr(params), "log::post::value");
+ const failable<bool> val = scribe::log(cadr(params), category, sc);
+ if (!hasContent(val))
+ return mkfailure<value>(reason(val));
+ return value(mklist<value>(true));
+}
+
+/**
+ * Component implementation lambda function.
+ */
+class applyLog {
+public:
+ applyLog(const value& category, scribe::Scribe& sc) : category(category), sc(sc) {
+ }
+
+ const value operator()(const list<value>& params) const {
+ const value func(car(params));
+ if (func == "post")
+ return post(cdr(params), category, sc);
+ return tuscany::mkfailure<tuscany::value>();
+ }
+
+private:
+ const value category;
+ scribe::Scribe& sc;
+};
+
+/**
+ * Start the component.
+ */
+const failable<value> start(unused const list<value>& params) {
+ // Connect to Scribe
+ scribe::Scribe& sc = *(new (gc_new<scribe::Scribe>()) scribe::Scribe("localhost", 1464));
+
+ // Extract the configured category
+ const value category = ((lambda<value(list<value>)>)car(params))(list<value>());
+ debug(category, "log::start::category");
+
+ // Return the component implementation lambda function
+ return value(lambda<value(const list<value>&)>(applyLog(category, sc)));
+}
+
+}
+}
+
+extern "C" {
+
+const tuscany::value apply(const tuscany::list<tuscany::value>& params) {
+ const tuscany::value func(car(params));
+ if (func == "start")
+ return tuscany::log::start(cdr(params));
+ return tuscany::mkfailure<tuscany::value>();
+}
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/log/logger.componentType b/sandbox/sebastien/cpp/apr-2/components/log/logger.componentType
new file mode 100644
index 0000000000..1c9546e685
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/log/logger.componentType
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<componentType xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/components">
+
+ <service name="logger"/>
+ <reference name="relay"/>
+ <property name="category" type="xsd:string">default</property>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/components/log/logger.cpp b/sandbox/sebastien/cpp/apr-2/components/log/logger.cpp
new file mode 100644
index 0000000000..e1f4712d61
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/log/logger.cpp
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Scribe-based logger component implementation, used to intercept
+ * and log service invocations.
+ */
+
+#include "string.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "scribe.hpp"
+
+namespace tuscany {
+namespace logger {
+
+/**
+ * Component implementation lambda function.
+ */
+class applyLog {
+public:
+ applyLog(const lambda<value(const list<value>&)>& relay, const value& category, scribe::Scribe& sc) : relay(relay), category(category), sc(sc) {
+ }
+
+ const value operator()(const list<value>& params) const {
+ // Log the function params
+ debug(params, "logger::apply::params");
+ scribe::log(params, category, sc);
+
+ // Relay the function
+ const failable<value> res = relay(params);
+
+ // Log the result
+ scribe::log(res, category, sc);
+ return res;
+ }
+
+private:
+ const lambda<value(const list<value>&)> relay;
+ const value category;
+ scribe::Scribe& sc;
+};
+
+/**
+ * Start the component.
+ */
+const failable<value> start(unused const list<value>& params) {
+ // Connect to Scribe
+ scribe::Scribe& sc = *(new (gc_new<scribe::Scribe>()) scribe::Scribe("localhost", 1464));
+
+ // Extract the configured relay service and category
+ const value rel = car(params);
+ const value category = ((lambda<value(list<value>)>)cadr(params))(list<value>());
+ debug(category, "logger::start::category");
+
+ // Return the component implementation lambda function
+ return value(lambda<value(const list<value>&)>(applyLog(rel, category, sc)));
+}
+
+}
+}
+
+extern "C" {
+
+const tuscany::value apply(const tuscany::list<tuscany::value>& params) {
+ const tuscany::value func(car(params));
+ if (func == "start")
+ return tuscany::logger::start(cdr(params));
+ return tuscany::mkfailure<tuscany::value>();
+}
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/log/scribe-cat.cpp b/sandbox/sebastien/cpp/apr-2/components/log/scribe-cat.cpp
new file mode 100644
index 0000000000..f3c5e898cd
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/log/scribe-cat.cpp
@@ -0,0 +1,77 @@
+/*
+ * 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$ */
+
+/**
+ * A utility that logs stdin into a scribe log.
+ */
+
+#include "string.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+
+#undef debug
+#define debug(...)
+#include "scribe.hpp"
+
+namespace tuscany {
+namespace scribecat {
+
+int cat(const string& category, const string& type) {
+ // Connect to Scribe
+ scribe::Scribe& sc = *(new (gc_new<scribe::Scribe>()) scribe::Scribe("localhost", 1464));
+
+ // Read lines from stdin and log them
+ char buf[8192];
+ for (;;) {
+ const char* s = fgets(buf, 8192, stdin);
+ if (s == NULL)
+ return 0;
+ const int l = strlen(s);
+ if (l < 2)
+ return 0;
+ buf[l - 1] = '\0';
+
+ // Log each line as is
+ if (length(type) == 0) {
+ const failable<bool> val = scribe::log(buf, category, sc);
+ if (!hasContent(val))
+ return 1;
+ continue;
+ }
+
+ // Log each line prefixed with time and a type tag
+ ostringstream os;
+ os << "[" << logTime() << "] [" << type << "] " << buf;
+ const failable<bool> val = scribe::log(c_str(str(os)), category, sc);
+ if (!hasContent(val))
+ return 1;
+ }
+}
+
+}
+}
+
+int main(const int argc, const char** argv) {
+ return tuscany::scribecat::cat(argc < 2? "default" : argv[1], argc < 3? "" : argv[2]);
+}
+
diff --git a/sandbox/sebastien/cpp/apr-2/components/log/scribe-tail-start b/sandbox/sebastien/cpp/apr-2/components/log/scribe-tail-start
new file mode 100755
index 0000000000..0044f1620d
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/log/scribe-tail-start
@@ -0,0 +1,44 @@
+#!/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.
+
+# Tail a file and pipe into scribe-cat
+here=`readlink -f $0`; here=`dirname $here`
+
+category=""
+type=""
+file=""
+if [ "$3" != "" ]; then
+ category=$1
+ type=$2
+ file=$3
+else
+ if [ "$2" != "" ]; then
+ category=$1
+ file=$2
+ else
+ file=$1
+ fi
+fi
+
+mkdir -p `dirname $file`
+touch $file
+file=`readlink -f $file`
+
+tail -f -n 0 $file | $here/scribe-cat $category $type &
+
diff --git a/sandbox/sebastien/cpp/apr-2/components/log/scribe-tail-stop b/sandbox/sebastien/cpp/apr-2/components/log/scribe-tail-stop
new file mode 100755
index 0000000000..e1b74fc0c6
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/log/scribe-tail-stop
@@ -0,0 +1,42 @@
+#!/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.
+
+# Stop tailing a file
+here=`readlink -f $0`; here=`dirname $here`
+
+category=""
+type=""
+file=""
+if [ "$3" != "" ]; then
+ category=$1
+ type=$2
+ file=$3
+else
+ if [ "$2" != "" ]; then
+ category=$1
+ file=$2
+ else
+ file=$1
+ fi
+fi
+file=`readlink -f $file`
+
+cmd="tail -f -n 0 $file"
+kill `ps -ef | grep -v grep | grep "${cmd}" | awk '{ print $2 }'`
+
diff --git a/sandbox/sebastien/cpp/apr-2/components/log/scribe-test b/sandbox/sebastien/cpp/apr-2/components/log/scribe-test
new file mode 100755
index 0000000000..a355026dd0
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/log/scribe-test
@@ -0,0 +1,43 @@
+#!/bin/sh
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+echo "Testing..."
+
+# Setup
+rm -rf tmp
+./scribed-central-conf tmp
+./scribed-client-conf tmp localhost
+./scribed-central-start tmp
+./scribed-client-start tmp
+sleep 1
+
+# Test logging a message
+echo test | ./scribe-cat >/dev/null
+sleep 4
+grep test tmp/scribe/logs/central/default/default_current >/dev/null
+rc=$?
+
+# Cleanup
+./scribed-client-stop tmp
+./scribed-central-stop tmp
+sleep 1
+if [ "$rc" = "0" ]; then
+ echo "OK"
+fi
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/components/log/scribe.hpp b/sandbox/sebastien/cpp/apr-2/components/log/scribe.hpp
new file mode 100644
index 0000000000..5237bd0183
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/log/scribe.hpp
@@ -0,0 +1,147 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_scribe_hpp
+#define tuscany_scribe_hpp
+
+/**
+ * Scribe logging functions.
+ */
+
+// Work around redundant defines in Scribe headers
+#undef PACKAGE
+#undef PACKAGE_BUGREPORT
+#undef PACKAGE_NAME
+#undef PACKAGE_STRING
+#undef PACKAGE_TARNAME
+#undef PACKAGE_VERSION
+#undef VERSION
+
+// Ignore integer conversion issues in Thrift and Scribe headers
+#ifdef WANT_MAINTAINER_MODE
+#pragma GCC diagnostic ignored "-Wconversion"
+#endif
+
+#include <protocol/TBinaryProtocol.h>
+#include <transport/TSocket.h>
+#include <transport/TTransportUtils.h>
+
+#include "gen-cpp/scribe.h"
+
+#ifdef WANT_MAINTAINER_MODE
+#pragma GCC diagnostic warning "-Wconversion"
+#endif
+
+#include "string.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "../../modules/scheme/eval.hpp"
+
+namespace tuscany {
+namespace scribe {
+
+/**
+ * Represents a Scribe connection.
+ */
+class Scribe {
+public:
+ Scribe() : owner(false) {
+ }
+
+ Scribe(const string host, const int port) : owner(true) {
+ init(host, port);
+ }
+
+ Scribe(const Scribe& c) : owner(false) {
+ client = c.client;
+ transport = c.transport;
+ }
+
+ ~Scribe() {
+ if (!owner)
+ return;
+ try {
+ transport->close();
+ delete client;
+ } catch (const std::exception& e) {
+ mkfailure<bool>(e.what());
+ }
+ }
+
+private:
+ bool owner;
+ ::scribe::thrift::scribeClient* client;
+ boost::shared_ptr<apache::thrift::transport::TTransport> transport;
+
+ friend const failable<bool> log(const value& val, const value& category, const Scribe& sc);
+
+ /**
+ * Initialize the Scribe connection.
+ */
+ const failable<bool> init(const string& host, const int port) {
+ try {
+ boost::shared_ptr<apache::thrift::transport::TTransport> sock(new apache::thrift::transport::TSocket(c_str(host), port));
+ boost::shared_ptr<apache::thrift::transport::TFramedTransport> framedSock(new apache::thrift::transport::TFramedTransport(sock));
+ transport = framedSock;
+ boost::shared_ptr<apache::thrift::protocol::TProtocol> proto(new apache::thrift::protocol::TBinaryProtocol(transport));
+ client = new ::scribe::thrift::scribeClient(proto);
+ transport->open();
+ return true;
+ } catch (const std::exception& e) {
+ return mkfailure<bool>(e.what());
+ }
+ }
+};
+
+/**
+ * Log an item.
+ */
+const failable<bool> log(const value& val, const value& category, const Scribe& sc) {
+ debug(val, "scribe::log::value");
+ debug(category, "scribe::log::category");
+
+ const value cat = isString(category)? value(c_str(category)):category;
+ const string cs(scheme::writeValue(cat));
+ const string vs(scheme::writeValue(val));
+
+ try {
+ ::scribe::thrift::LogEntry entry;
+ entry.category = c_str(cs);
+ entry.message = c_str(vs);
+ std::vector< ::scribe::thrift::LogEntry> msgs;
+ msgs.push_back(entry);
+
+ int result = sc.client->Log(msgs);
+ if (result != ::scribe::thrift::OK)
+ return mkfailure<bool>("Could not log value, retry later");
+ } catch (const std::exception& e) {
+ return mkfailure<bool>(e.what());
+ }
+
+ debug(true, "scribe::log::result");
+ return true;
+}
+
+}
+}
+
+#endif /* tuscany_scribe_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/components/log/scribe.thrift b/sandbox/sebastien/cpp/apr-2/components/log/scribe.thrift
new file mode 100644
index 0000000000..592e8b630e
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/log/scribe.thrift
@@ -0,0 +1,39 @@
+#!/usr/local/bin/thrift --cpp --php
+
+## Copyright (c) 2007-2008 Facebook
+##
+## Licensed 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.
+##
+## See accompanying file LICENSE or visit the Scribe site at:
+## http://developers.facebook.com/scribe/
+
+include "fb303.thrift"
+
+namespace cpp scribe.thrift
+
+enum ResultCode
+{
+ OK,
+ TRY_LATER
+}
+
+struct LogEntry
+{
+ 1: string category,
+ 2: string message
+}
+
+service scribe extends fb303.FacebookService
+{
+ ResultCode Log(1: list<LogEntry> messages);
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/log/scribed-central-conf b/sandbox/sebastien/cpp/apr-2/components/log/scribed-central-conf
new file mode 100755
index 0000000000..b23646c24f
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/log/scribed-central-conf
@@ -0,0 +1,73 @@
+#!/bin/sh
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# Generate a Scribe central conf
+here=`readlink -f $0`; here=`dirname $here`
+mkdir -p $1
+root=`readlink -f $1`
+
+port=$2
+if [ "$port" = "" ]; then
+ port="1463"
+fi
+
+mkdir -p $root/scribe/conf
+mkdir -p $root/scribe/logs/central
+mkdir -p $root/scribe/logs/central-secondary
+
+cat >$root/scribe/conf/scribe-central.conf <<EOF
+# Generated by: scribed-central-conf $*
+# Scribe central configuration
+port=$port
+max_msg_per_second=2000000
+check_interval=3
+
+# Log store configuration
+<store>
+category=default
+type=buffer
+
+target_write_size=20480
+max_write_interval=1
+buffer_send_rate=2
+retry_interval=30
+retry_interval_range=10
+
+<primary>
+type=file
+fs_type=std
+file_path=$root/scribe/logs/central
+base_filename=central
+max_size=1000000
+add_newlines=1
+rotate_period=daily
+rotate_hour=0
+rotate_minute=10
+</primary>
+
+<secondary>
+type=file
+fs_type=std
+file_path=$root/scribe/logs/central-secondary
+base_filename=central
+max_size=3000000
+</secondary>
+
+</store>
+EOF
diff --git a/sandbox/sebastien/cpp/apr-2/components/log/scribed-central-start b/sandbox/sebastien/cpp/apr-2/components/log/scribed-central-start
new file mode 100755
index 0000000000..c2035037de
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/log/scribed-central-start
@@ -0,0 +1,27 @@
+#!/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.
+
+# Start central scribed
+here=`readlink -f $0`; here=`dirname $here`
+root=`readlink -f $1`
+
+scribe_prefix=`cat $here/scribe.prefix`
+thrift_prefix=`cat $here/thrift.prefix`
+export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:${thrift_prefix}/lib:${thrift_prefix}/contrib/fb303/lib:${scribe_prefix}/lib
+$scribe_prefix/bin/scribed -c $root/scribe/conf/scribe-central.conf 1>$root/scribe/logs/central.log 2>&1 &
diff --git a/sandbox/sebastien/cpp/apr-2/components/log/scribed-central-stop b/sandbox/sebastien/cpp/apr-2/components/log/scribed-central-stop
new file mode 100755
index 0000000000..95a976813f
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/log/scribed-central-stop
@@ -0,0 +1,28 @@
+#!/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.
+
+# Stop central scribed
+here=`readlink -f $0`; here=`dirname $here`
+root=`readlink -f $1`
+
+scribe_prefix=`cat $here/scribe.prefix`
+thrift_prefix=`cat $here/thrift.prefix`
+scribed="$scribe_prefix/bin/scribed -c $root/scribe/conf/scribe-central.conf"
+
+kill `ps -ef | grep -v grep | grep "${scribed}" | awk '{ print $2 }'`
diff --git a/sandbox/sebastien/cpp/apr-2/components/log/scribed-client-conf b/sandbox/sebastien/cpp/apr-2/components/log/scribed-client-conf
new file mode 100755
index 0000000000..87c8749c2e
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/log/scribed-client-conf
@@ -0,0 +1,67 @@
+#!/bin/sh
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# Generate a Scribe client conf
+here=`readlink -f $0`; here=`dirname $here`
+mkdir -p $1
+root=`readlink -f $1`
+
+central=$2
+cport=$3
+if [ "$cport" = "" ]; then
+ cport="1463"
+fi
+
+mkdir -p $root/scribe/conf
+mkdir -p $root/scribe/logs/client-secondary
+
+cat >$root/scribe/conf/scribe-client.conf <<EOF
+# Generated by: scribed-client-conf $*
+# Scribe client configuration
+port=1464
+max_msg_per_second=2000000
+check_interval=3
+
+# Forward all messages to central Scribe on port 1463
+# Save them locally as well
+<store>
+category=default
+type=buffer
+
+target_write_size=20480
+max_write_interval=1
+buffer_send_rate=1
+retry_interval=30
+retry_interval_range=10
+
+<primary>
+type=network
+remote_host=$central
+remote_port=$cport
+</primary>
+
+<secondary>
+type=file
+fs_type=std
+file_path=$root/scribe/logs/client-secondary
+base_filename=client
+max_size=3000000
+</secondary>
+</store>
+EOF
diff --git a/sandbox/sebastien/cpp/apr-2/components/log/scribed-client-start b/sandbox/sebastien/cpp/apr-2/components/log/scribed-client-start
new file mode 100755
index 0000000000..ed8636d7f2
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/log/scribed-client-start
@@ -0,0 +1,27 @@
+#!/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.
+
+# Start client scribed
+here=`readlink -f $0`; here=`dirname $here`
+root=`readlink -f $1`
+
+scribe_prefix=`cat $here/scribe.prefix`
+thrift_prefix=`cat $here/thrift.prefix`
+export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:${thrift_prefix}/lib:${thrift_prefix}/contrib/fb303/lib:${scribe_prefix}/lib
+$scribe_prefix/bin/scribed -c $root/scribe/conf/scribe-client.conf 1>$root/scribe/logs/client.log 2>&1 &
diff --git a/sandbox/sebastien/cpp/apr-2/components/log/scribed-client-stop b/sandbox/sebastien/cpp/apr-2/components/log/scribed-client-stop
new file mode 100755
index 0000000000..2e8959fbfc
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/log/scribed-client-stop
@@ -0,0 +1,28 @@
+#!/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.
+
+# Stop client scribed
+here=`readlink -f $0`; here=`dirname $here`
+root=`readlink -f $1`
+
+scribe_prefix=`cat $here/scribe.prefix`
+thrift_prefix=`cat $here/thrift.prefix`
+scribed="$scribe_prefix/bin/scribed -c $root/scribe/conf/scribe-client.conf"
+
+kill `ps -ef | grep -v grep | grep "${scribed}" | awk '{ print $2 }'`
diff --git a/sandbox/sebastien/cpp/apr-2/components/log/server-test b/sandbox/sebastien/cpp/apr-2/components/log/server-test
new file mode 100755
index 0000000000..631487c77a
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/log/server-test
@@ -0,0 +1,65 @@
+#!/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 localhost 8090 ../../modules/http/htdocs
+../../modules/server/server-conf tmp
+../../modules/server/scheme-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+SCAContribution `pwd`/
+SCAComposite log.composite
+EOF
+
+rm -rf tmp/scribe
+./scribed-central-conf tmp
+./scribed-client-conf tmp localhost
+./scribed-central-start tmp
+./scribed-client-start tmp
+sleep 1
+../../modules/http/httpd-start tmp
+sleep 2
+
+# Test
+./client-test 2>/dev/null
+rc=$?
+if [ "$rc" = "0" ]; then
+ echo "Testing..."
+ sleep 4
+ grep "Apple" tmp/scribe/logs/central/default/default_current >/dev/null
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ grep "(add 33 22)" tmp/scribe/logs/central/default/default_current >/dev/null
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ grep "55" tmp/scribe/logs/central/default/default_current >/dev/null
+ rc=$?
+fi
+
+# Cleanup
+../../modules/http/httpd-stop tmp
+sleep 1
+./scribed-client-stop tmp
+./scribed-central-stop tmp
+sleep 1
+if [ "$rc" = "0" ]; then
+ echo "OK"
+fi
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/components/nosqldb/Makefile.am b/sandbox/sebastien/cpp/apr-2/components/nosqldb/Makefile.am
new file mode 100644
index 0000000000..6cf829fa7a
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/nosqldb/Makefile.am
@@ -0,0 +1,49 @@
+# 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.
+
+INCLUDES = -I${TINYCDB_INCLUDE}
+
+incl_HEADERS = *.hpp
+incldir = $(prefix)/include/components/nosqldb
+
+dist_comp_SCRIPTS = tinycdb
+compdir=$(prefix)/components/nosqldb
+
+comp_DATA = tinycdb.prefix
+tinycdb.prefix: $(top_builddir)/config.status
+ echo ${TINYCDB_PREFIX} >tinycdb.prefix
+
+EXTRA_DIST = nosqldb.composite nosqldb.componentType
+
+comp_LTLIBRARIES = libnosqldb.la
+noinst_DATA = libnosqldb.so
+
+libnosqldb_la_SOURCES = nosqldb.cpp
+libnosqldb_la_LDFLAGS = -L${TINYCDB_LIB} -R${TINYCDB_LIB} -lcdb
+libnosqldb.so:
+ ln -s .libs/libnosqldb.so
+
+tinycdb_test_SOURCES = tinycdb-test.cpp
+tinycdb_test_LDFLAGS = -L${TINYCDB_LIB} -R${TINYCDB_LIB} -lcdb
+
+client_test_SOURCES = client-test.cpp
+client_test_LDFLAGS = -lxml2 -lcurl -lmozjs
+
+dist_noinst_SCRIPTS = nosqldb-test server-test
+noinst_PROGRAMS = tinycdb-test client-test
+TESTS = nosqldb-test server-test
+
diff --git a/sandbox/sebastien/cpp/apr-2/components/nosqldb/client-test.cpp b/sandbox/sebastien/cpp/apr-2/components/nosqldb/client-test.cpp
new file mode 100644
index 0000000000..8eed7ce8cd
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/nosqldb/client-test.cpp
@@ -0,0 +1,130 @@
+/*
+ * 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 NoSQL database component.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "perf.hpp"
+#include "../../modules/http/http.hpp"
+
+namespace tuscany {
+namespace nosqldb {
+
+const string uri("http://localhost:8090/nosqldb");
+
+bool testNoSqlDb() {
+ http::CURLSession cs("", "", "");
+
+ const list<value> i = list<value>()
+ + (list<value>() + "name" + string("Apple"))
+ + (list<value>() + "price" + string("$2.99"));
+ const list<value> a = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
+
+ const failable<value> id = http::post(a, uri, cs);
+ assert(hasContent(id));
+
+ const string p = path(content(id));
+ {
+ const failable<value> val = http::get(uri + p, cs);
+ assert(hasContent(val));
+ assert(content(val) == a);
+ }
+
+ const list<value> j = list<value>()
+ + (list<value>() + "name" + string("Apple"))
+ + (list<value>() + "price" + string("$3.55"));
+ const list<value> b = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), j);
+
+ {
+ const failable<value> r = http::put(b, uri + p, cs);
+ assert(hasContent(r));
+ assert(content(r) == value(true));
+ }
+ {
+ const failable<value> val = http::get(uri + p, cs);
+ assert(hasContent(val));
+ assert(content(val) == b);
+ }
+ {
+ const failable<value> r = http::del(uri + p, cs);
+ assert(hasContent(r));
+ assert(content(r) == value(true));
+ }
+ {
+ const failable<value> val = http::get(uri + p, cs);
+ assert(!hasContent(val));
+ }
+
+ return true;
+}
+
+struct getLoop {
+ const string path;
+ const value entry;
+ http::CURLSession cs;
+ getLoop(const string& path, const value& entry, http::CURLSession cs) : path(path), entry(entry), cs(cs) {
+ }
+ const bool operator()() const {
+ const failable<value> val = http::get(uri + path, cs);
+ assert(hasContent(val));
+ assert(content(val) == entry);
+ return true;
+ }
+};
+
+bool testGetPerf() {
+ const list<value> i = list<value>()
+ + (list<value>() + "name" + string("Apple"))
+ + (list<value>() + "price" + string("$4.55"));
+ const value a = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
+
+ http::CURLSession cs("", "", "");
+ const failable<value> id = http::post(a, uri, cs);
+ assert(hasContent(id));
+ const string p = path(content(id));
+
+ const lambda<bool()> gl = getLoop(p, a, cs);
+ cout << "NoSqldb get test " << time(gl, 5, 200) << " ms" << endl;
+
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::nosqldb::testNoSqlDb();
+ tuscany::nosqldb::testGetPerf();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/nosqldb/nosqldb-test b/sandbox/sebastien/cpp/apr-2/components/nosqldb/nosqldb-test
new file mode 100755
index 0000000000..30c9f89bc9
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/nosqldb/nosqldb-test
@@ -0,0 +1,29 @@
+#!/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
+mkdir -p tmp
+./tinycdb -c -m tmp/test.cdb </dev/null
+
+# Test
+./tinycdb-test 2>/dev/null
+rc=$?
+
+# Cleanup
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/components/nosqldb/nosqldb.componentType b/sandbox/sebastien/cpp/apr-2/components/nosqldb/nosqldb.componentType
new file mode 100644
index 0000000000..bb79882b5d
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/nosqldb/nosqldb.componentType
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<componentType xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/components">
+
+ <service name="nosqldb"/>
+ <property name="dbname" type="xsd:string"/>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/components/nosqldb/nosqldb.composite b/sandbox/sebastien/cpp/apr-2/components/nosqldb/nosqldb.composite
new file mode 100644
index 0000000000..af2d3a18d7
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/nosqldb/nosqldb.composite
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/components"
+ name="nosqldb">
+
+ <component name="nosqldb">
+ <implementation.cpp path="." library="libnosqldb"/>
+ <property name="dbname">tmp/test.cdb</property>
+ <service name="nosqldb">
+ <t:binding.http uri="nosqldb"/>
+ </service>
+ </component>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/components/nosqldb/nosqldb.cpp b/sandbox/sebastien/cpp/apr-2/components/nosqldb/nosqldb.cpp
new file mode 100644
index 0000000000..cda3ca44a9
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/nosqldb/nosqldb.cpp
@@ -0,0 +1,123 @@
+/*
+ * 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$ */
+
+/**
+ * TinyCDB-based database component implementation.
+ */
+
+#include "string.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "tinycdb.hpp"
+
+namespace tuscany {
+namespace nosqldb {
+
+/**
+ * Get an item from the database.
+ */
+const failable<value> get(const list<value>& params, tinycdb::TinyCDB& cdb) {
+ return tinycdb::get(car(params), cdb);
+}
+
+/**
+ * Post an item to the database.
+ */
+const failable<value> post(const list<value>& params, tinycdb::TinyCDB& cdb) {
+ const value id = append<value>(car(params), mklist(mkuuid()));
+ const failable<bool> val = tinycdb::post(id, cadr(params), cdb);
+ if (!hasContent(val))
+ return mkfailure<value>(reason(val));
+ return id;
+}
+
+/**
+ * Put an item into the database.
+ */
+const failable<value> put(const list<value>& params, tinycdb::TinyCDB& cdb) {
+ const failable<bool> val = tinycdb::put(car(params), cadr(params), cdb);
+ if (!hasContent(val))
+ return mkfailure<value>(reason(val));
+ return value(content(val));
+}
+
+/**
+ * Delete an item from the database.
+ */
+const failable<value> del(const list<value>& params, tinycdb::TinyCDB& cdb) {
+ const failable<bool> val = tinycdb::del(car(params), cdb);
+ if (!hasContent(val))
+ return mkfailure<value>(reason(val));
+ return value(content(val));
+}
+
+/**
+ * Component implementation lambda function.
+ */
+class applyNoSqldb {
+public:
+ applyNoSqldb(tinycdb::TinyCDB& cdb) : cdb(cdb) {
+ }
+
+ const value operator()(const list<value>& params) const {
+ const value func(car(params));
+ if (func == "get")
+ return get(cdr(params), cdb);
+ if (func == "post")
+ return post(cdr(params), cdb);
+ if (func == "put")
+ return put(cdr(params), cdb);
+ if (func == "delete")
+ return del(cdr(params), cdb);
+ return tuscany::mkfailure<tuscany::value>();
+ }
+
+private:
+ tinycdb::TinyCDB& cdb;
+};
+
+/**
+ * Start the component.
+ */
+const failable<value> start(unused const list<value>& params) {
+ // Connect to the configured database and table
+ const value dbname = ((lambda<value(list<value>)>)car(params))(list<value>());
+ tinycdb::TinyCDB& cdb = *(new (gc_new<tinycdb::TinyCDB>()) tinycdb::TinyCDB(dbname));
+
+ // Return the component implementation lambda function
+ return value(lambda<value(const list<value>&)>(applyNoSqldb(cdb)));
+}
+
+}
+}
+
+extern "C" {
+
+const tuscany::value apply(const tuscany::list<tuscany::value>& params) {
+ const tuscany::value func(car(params));
+ if (func == "start")
+ return tuscany::nosqldb::start(cdr(params));
+ return tuscany::mkfailure<tuscany::value>();
+}
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/nosqldb/server-test b/sandbox/sebastien/cpp/apr-2/components/nosqldb/server-test
new file mode 100755
index 0000000000..5a5d792a32
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/nosqldb/server-test
@@ -0,0 +1,40 @@
+#!/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 localhost 8090 ../../modules/http/htdocs
+../../modules/server/server-conf tmp
+../../modules/server/scheme-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+SCAContribution `pwd`/
+SCAComposite nosqldb.composite
+EOF
+
+./tinycdb -c -m tmp/test.cdb </dev/null
+../../modules/http/httpd-start tmp
+sleep 2
+
+# Test
+./client-test 2>/dev/null
+rc=$?
+
+# Cleanup
+../../modules/http/httpd-stop tmp
+sleep 2
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/components/nosqldb/tinycdb b/sandbox/sebastien/cpp/apr-2/components/nosqldb/tinycdb
new file mode 100755
index 0000000000..68459d7622
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/nosqldb/tinycdb
@@ -0,0 +1,24 @@
+#!/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.
+
+here=`readlink -f $0`; here=`dirname $here`
+tinycdb_prefix=`cat $here/tinycdb.prefix`
+
+$tinycdb_prefix/bin/cdb $*
+
diff --git a/sandbox/sebastien/cpp/apr-2/components/nosqldb/tinycdb-test.cpp b/sandbox/sebastien/cpp/apr-2/components/nosqldb/tinycdb-test.cpp
new file mode 100644
index 0000000000..b3b4ea7fd7
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/nosqldb/tinycdb-test.cpp
@@ -0,0 +1,82 @@
+/*
+ * 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 TinyCDB access functions.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "perf.hpp"
+#include "tinycdb.hpp"
+
+namespace tuscany {
+namespace tinycdb {
+
+bool testTinyCDB() {
+ TinyCDB cdb("tmp/test.cdb");
+ const value k = mklist<value>("a");
+
+ assert(hasContent(post(k, string("AAA"), cdb)));
+ assert((get(k, cdb)) == value(string("AAA")));
+ assert(hasContent(put(k, string("aaa"), cdb)));
+ assert((get(k, cdb)) == value(string("aaa")));
+ assert(hasContent(del(k, cdb)));
+ assert(!hasContent(get(k, cdb)));
+
+ return true;
+}
+
+struct getLoop {
+ const value k;
+ TinyCDB& cdb;
+ getLoop(const value& k, TinyCDB& cdb) : k(k), cdb(cdb) {
+ }
+ const bool operator()() const {
+ assert((get(k, cdb)) == value(string("CCC")));
+ return true;
+ }
+};
+
+bool testGetPerf() {
+ const value k = mklist<value>("c");
+ TinyCDB cdb("tmp/test.cdb");
+ assert(hasContent(post(k, string("CCC"), cdb)));
+
+ const lambda<bool()> gl = getLoop(k, cdb);
+ cout << "TinyCDB get test " << time(gl, 5, 100000) << " ms" << endl;
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::tinycdb::testTinyCDB();
+ tuscany::tinycdb::testGetPerf();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/nosqldb/tinycdb.hpp b/sandbox/sebastien/cpp/apr-2/components/nosqldb/tinycdb.hpp
new file mode 100644
index 0000000000..0fab1a9854
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/nosqldb/tinycdb.hpp
@@ -0,0 +1,460 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_tinycdb_hpp
+#define tuscany_tinycdb_hpp
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <cdb.h>
+
+#include "string.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "../../modules/scheme/eval.hpp"
+
+namespace tuscany {
+namespace tinycdb {
+
+/**
+ * A reallocatable buffer.
+ */
+class buffer {
+public:
+ operator void*() const throw() {
+ return buf;
+ }
+
+ operator unsigned char*() const throw() {
+ return (unsigned char*)buf;
+ }
+
+ operator char*() const throw() {
+ return (char*)buf;
+ }
+
+private:
+ buffer(const unsigned int size, void* buf) : size(size), buf(buf) {
+ }
+
+ unsigned int size;
+ void* buf;
+
+ friend const buffer mkbuffer(const unsigned int sz);
+ friend const buffer mkbuffer(const buffer& b, const unsigned int newsz);
+ friend const bool free(const buffer& b);
+};
+
+/**
+ * Make a new buffer.
+ */
+const buffer mkbuffer(const unsigned int sz) {
+ return buffer(sz, malloc(sz));
+}
+
+/**
+ * Make a new buffer by reallocating an existing one.
+ */
+const buffer mkbuffer(const buffer& b, const unsigned int sz) {
+ if (sz <= b.size)
+ return b;
+ return buffer(sz, realloc(b.buf, sz));
+}
+
+/**
+ * Free a buffer.
+ */
+const bool free(const buffer&b) {
+ ::free(b.buf);
+ return true;
+}
+
+/**
+ * Represents a TinyCDB connection.
+ */
+class TinyCDB {
+public:
+ TinyCDB() : owner(false), fd(-1) {
+ st.st_ino = 0;
+ }
+
+ TinyCDB(const string& name) : owner(true), name(name), fd(-1) {
+ st.st_ino = 0;
+ }
+
+ TinyCDB(const TinyCDB& c) : owner(false), name(c.name), fd(c.fd) {
+ st.st_ino = c.st.st_ino;
+ }
+
+ ~TinyCDB() {
+ if (!owner)
+ return;
+ if (fd == -1)
+ return;
+ close(fd);
+ }
+
+private:
+ bool owner;
+ string name;
+ int fd;
+ struct stat st;
+
+ friend const string dbname(const TinyCDB& cdb);
+ friend const failable<int> cdbopen(TinyCDB& cdb);
+ friend const failable<bool> cdbclose(TinyCDB& cdb);
+};
+
+/**
+ * Return the name of the database.
+ */
+const string dbname(const TinyCDB& cdb) {
+ return cdb.name;
+}
+
+/**
+ * Open a database.
+ */
+const failable<int> cdbopen(TinyCDB& cdb) {
+
+ // Get database file serial number
+ struct stat st;
+ const int s = stat(c_str(cdb.name), &st);
+ if (s == -1)
+ return mkfailure<int>(string("Couldn't tinycdb read database stat ") + cdb.name);
+
+ // Open database for the first time
+ if (cdb.fd == -1) {
+ cdb.fd = open(c_str(cdb.name), O_RDONLY);
+ if (cdb.fd == -1)
+ return mkfailure<int>(string("Couldn't open tinycdb database file ") + cdb.name);
+ debug(cdb.fd, "tinycdb::open::fd");
+ cdb.st = st;
+ return cdb.fd;
+ }
+
+ // Close and reopen database after a change
+ if (st.st_ino != cdb.st.st_ino) {
+
+ // Close current fd
+ close(cdb.fd);
+
+ // Reopen database
+ const int newfd = open(c_str(cdb.name), O_RDONLY);
+ if (newfd == -1)
+ return mkfailure<int>(string("Couldn't open tinycdb database file ") + cdb.name);
+ if (newfd == cdb.fd) {
+ debug(cdb.fd, "tinycdb::open::fd");
+ cdb.st = st;
+ return cdb.fd;
+ }
+
+ // We got a different fd, dup it to the current fd then close it
+ if (fcntl(newfd, F_DUPFD, cdb.fd) == -1)
+ return mkfailure<int>(string("Couldn't dup tinycdb database file handle ") + cdb.name);
+ close(newfd);
+
+ debug(cdb.fd, "tinycdb::open::fd");
+ cdb.st = st;
+ return cdb.fd;
+ }
+
+ // No change, just return the current fd
+ return cdb.fd;
+}
+
+/**
+ * Close a database.
+ */
+const failable<bool> cdbclose(TinyCDB& cdb) {
+ close(cdb.fd);
+ cdb.fd = -1;
+ return true;
+}
+
+/**
+ * Rewrite a database. The given update function is passed each entry, and
+ * can return true to let the entry added to the new db, false to skip the
+ * entry, or a failure.
+ */
+const failable<bool> rewrite(const lambda<failable<bool>(buffer& buf, const unsigned int klen, const unsigned int vlen)>& update, const lambda<failable<bool>(struct cdb_make&)>& finish, buffer& buf, const int tmpfd, TinyCDB& cdb) {
+
+ // Initialize new db structure
+ struct cdb_make cdbm;
+ cdb_make_start(&cdbm, tmpfd);
+
+ // Open existing db
+ failable<int> ffd = cdbopen(cdb);
+ if (!hasContent(ffd))
+ return mkfailure<bool>(reason(ffd));
+ const int fd = content(ffd);
+
+ // Read the db header
+ unsigned int pos = 0;
+ if (lseek(fd, 0, SEEK_SET) != 0)
+ return mkfailure<bool>("Could not seek to tinycdb database start");
+ if (::read(fd, buf, 2048) != 2048)
+ return mkfailure<bool>("Could not read tinycdb database header");
+ pos += 2048;
+ unsigned int eod = cdb_unpack(buf);
+ debug(pos, "tinycdb::rewrite::eod");
+
+ // Read and add the existing entries
+ while(pos < eod) {
+ if (eod - pos < 8)
+ return mkfailure<bool>("Invalid tinycdb database format, couldn't read entry header");
+ if (::read(fd, buf, 8) != 8)
+ return mkfailure<bool>("Couldn't read tinycdb entry header");
+ pos += 8;
+ unsigned int klen = cdb_unpack(buf);
+ unsigned int vlen = cdb_unpack(((unsigned char*)buf) + 4);
+ unsigned int elen = klen + vlen;
+
+ // Read existing entry
+ buf = mkbuffer(buf, elen);
+ if (eod - pos < elen)
+ return mkfailure<bool>("Invalid tinycdb database format, couldn't read entry");
+ if ((unsigned int)::read(fd, buf, elen) != elen)
+ return mkfailure<bool>("Couldn't read tinycdb entry");
+ pos += elen;
+
+ // Apply the update function to the entry
+ debug(string((char*)buf, klen), "tinycdb::rewrite::existing key");
+ debug(string(((char*)buf) + klen, vlen), "tinycdb::rewrite::existing value");
+ const failable<bool> u = update(buf, klen, vlen);
+ if (!hasContent(u))
+ return u;
+
+ // Skip the entry if the update function returned false
+ if (u == false)
+ continue;
+
+ // Add the entry to the new db
+ if (cdb_make_add(&cdbm, buf, klen, ((unsigned char*)buf)+klen, vlen) == -1)
+ return mkfailure<bool>("Could not add tinycdb entry");
+ }
+ if (pos != eod)
+ return mkfailure<bool>("Invalid tinycdb database format");
+
+ // Call the finish function
+ const failable<bool> f = finish(cdbm);
+ if (!hasContent(f))
+ return f;
+
+ // Save the new db
+ if (cdb_make_finish(&cdbm) == -1)
+ return mkfailure<bool>("Could not save tinycdb database");
+
+ return true;
+}
+
+const failable<bool> rewrite(const lambda<failable<bool>(buffer& buf, const unsigned int klen, const unsigned int vlen)>& update, const lambda<failable<bool>(struct cdb_make&)>& finish, TinyCDB& cdb) {
+
+ // Create a new temporary db file
+ string tmpname = dbname(cdb) + ".XXXXXX";
+ int tmpfd = mkstemp(const_cast<char*>(c_str(tmpname)));
+ if (tmpfd == -1)
+ return mkfailure<bool>("Could not create temporary tinycdb database");
+
+ // Rewrite the db, apply the update function to each entry
+ buffer buf = mkbuffer(2048);
+ const failable<bool> r = rewrite(update, finish, buf, tmpfd, cdb);
+ if (!hasContent(r)) {
+ close(tmpfd);
+ free(buf);
+ return r;
+ }
+
+ // Atomically replace the db and reopen it in read mode
+ if (rename(c_str(tmpname), c_str(dbname(cdb))) == -1)
+ return mkfailure<bool>("Could not rename temporary tinycdb database");
+ cdbclose(cdb);
+ failable<int> ffd = cdbopen(cdb);
+ if (!hasContent(ffd))
+ return mkfailure<bool>(reason(ffd));
+
+ return true;
+}
+
+/**
+ * Post a new item to the database.
+ */
+struct postUpdate {
+ const string ks;
+ postUpdate(const string& ks) : ks(ks) {
+ }
+ const failable<bool> operator()(buffer& buf, const unsigned int klen, unused const unsigned int vlen) const {
+ if (ks == string((char*)buf, klen))
+ return mkfailure<bool>("Key already exists in tinycdb database");
+ return true;
+ }
+};
+
+struct postFinish {
+ const string ks;
+ const string vs;
+ postFinish(const string& ks, const string& vs) : ks(ks), vs(vs) {
+ }
+ const failable<bool> operator()(struct cdb_make& cdbm) const {
+ if (cdb_make_add(&cdbm, c_str(ks), (unsigned int)length(ks), c_str(vs), (unsigned int)length(vs)) == -1)
+ return mkfailure<bool>("Could not add tinycdb entry");
+ return true;
+ }
+};
+
+const failable<bool> post(const value& key, const value& val, TinyCDB& cdb) {
+ debug(key, "tinycdb::post::key");
+ debug(val, "tinycdb::post::value");
+ debug(dbname(cdb), "tinycdb::post::dbname");
+
+ const string ks(scheme::writeValue(key));
+ const string vs(scheme::writeValue(val));
+
+ // Process each entry and detect existing key
+ const lambda<failable<bool>(buffer& buf, const unsigned int klen, const unsigned int vlen)> update = postUpdate(ks);
+
+ // Add the new entry to the db
+ const lambda<failable<bool>(struct cdb_make& cdbm)> finish = postFinish(ks, vs);
+
+ // Rewrite the db
+ const failable<bool> r = rewrite(update, finish, cdb);
+ debug(r, "tinycdb::post::result");
+ return r;
+}
+
+/**
+ * Update an item in the database. If the item doesn't exist it is added.
+ */
+struct putUpdate {
+ const string ks;
+ putUpdate(const string& ks) : ks(ks) {
+ }
+ const failable<bool> operator()(buffer& buf, const unsigned int klen, unused const unsigned int vlen) const {
+ if (ks == string((char*)buf, klen))
+ return false;
+ return true;
+ }
+};
+
+struct putFinish {
+ const string ks;
+ const string vs;
+ putFinish(const string& ks, const string& vs) : ks(ks), vs(vs) {
+ }
+ const failable<bool> operator()(struct cdb_make& cdbm) const {
+ if (cdb_make_add(&cdbm, c_str(ks), (unsigned int)length(ks), c_str(vs), (unsigned int)length(vs)) == -1)
+ return mkfailure<bool>("Could not add tinycdb entry");
+ return true;
+ }
+};
+
+const failable<bool> put(const value& key, const value& val, TinyCDB& cdb) {
+ debug(key, "tinycdb::put::key");
+ debug(val, "tinycdb::put::value");
+ debug(dbname(cdb), "tinycdb::put::dbname");
+
+ const string ks(scheme::writeValue(key));
+ const string vs(scheme::writeValue(val));
+
+ // Process each entry and skip existing key
+ const lambda<failable<bool>(buffer& buf, const unsigned int klen, const unsigned int vlen)> update = putUpdate(ks);
+
+ // Add the new entry to the db
+ const lambda<failable<bool>(struct cdb_make& cdbm)> finish = putFinish(ks, vs);
+
+ // Rewrite the db
+ const failable<bool> r = rewrite(update, finish, cdb);
+ debug(r, "tinycdb::put::result");
+ return r;
+}
+
+/**
+ * Get an item from the database.
+ */
+const failable<value> get(const value& key, TinyCDB& cdb) {
+ debug(key, "tinycdb::get::key");
+ debug(dbname(cdb), "tinycdb::get::dbname");
+
+ const failable<int> ffd = cdbopen(cdb);
+ if (!hasContent(ffd))
+ return mkfailure<value>(reason(ffd));
+ const int fd = content(ffd);
+
+ const string ks(scheme::writeValue(key));
+
+ cdbi_t vlen;
+ if (cdb_seek(fd, c_str(ks), (unsigned int)length(ks), &vlen) <= 0)
+ return mkfailure<value>("Could not get tinycdb entry");
+ char* data = gc_cnew(vlen + 1);
+ cdb_bread(fd, data, vlen);
+ data[vlen] = '\0';
+ const value val(scheme::readValue(string(data)));
+
+ debug(val, "tinycdb::get::result");
+ return val;
+}
+
+/**
+ * Delete an item from the database
+ */
+struct delUpdate {
+ const string ks;
+ delUpdate(const string& ks) : ks(ks) {
+ }
+ const failable<bool> operator()(buffer& buf, const unsigned int klen, unused const unsigned int vlen) const {
+ if (ks == string((char*)buf, klen))
+ return false;
+ return true;
+ }
+};
+
+struct delFinish {
+ delFinish() {
+ }
+ const failable<bool> operator()(unused struct cdb_make& cdbm) const {
+ return true;
+ }
+};
+
+const failable<bool> del(const value& key, TinyCDB& cdb) {
+ debug(key, "tinycdb::delete::key");
+ debug(dbname(cdb), "tinycdb::delete::dbname");
+
+ const string ks(scheme::writeValue(key));
+
+ // Process each entry and skip existing key
+ const lambda<failable<bool>(buffer& buf, const unsigned int klen, const unsigned int vlen)> update = delUpdate(ks);
+
+ // Nothing to do to finish
+ const lambda<failable<bool>(struct cdb_make& cdbm)> finish = delFinish();
+
+ // Rewrite the db
+ const failable<bool> r = rewrite(update, finish, cdb);
+ debug(r, "tinycdb::delete::result");
+ return r;
+}
+
+}
+}
+
+#endif /* tuscany_tinycdb_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/components/queue/Makefile.am b/sandbox/sebastien/cpp/apr-2/components/queue/Makefile.am
new file mode 100644
index 0000000000..f527488a3b
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/queue/Makefile.am
@@ -0,0 +1,57 @@
+# 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.
+
+if WANT_QUEUE
+
+INCLUDES = -I${QPIDC_INCLUDE}
+
+incl_HEADERS = *.hpp
+incldir = $(prefix)/include/components/queue
+
+dist_comp_SCRIPTS = qpidd-start qpidd-stop
+compdir=$(prefix)/components/queue
+
+comp_DATA = qpidc.prefix
+qpidc.prefix: $(top_builddir)/config.status
+ echo ${QPIDC_PREFIX} >qpidc.prefix
+
+EXTRA_DIST = queue.composite queue-sender.componentType queue-listener.componentType *.scm
+
+comp_LTLIBRARIES = libqueue-sender.la libqueue-listener.la
+noinst_DATA = libqueue-sender.so libqueue-listener.so
+
+libqueue_sender_la_SOURCES = queue-sender.cpp
+libqueue_sender_la_LDFLAGS = -L${QPIDC_LIB} -R${QPIDC_LIB} -lqpidclient -lqpidcommon
+libqueue-sender.so:
+ ln -s .libs/libqueue-sender.so
+
+libqueue_listener_la_SOURCES = queue-listener.cpp
+libqueue_listener_la_LDFLAGS = -L${QPIDC_LIB} -R${QPIDC_LIB} -lqpidclient -lqpidcommon
+libqueue-listener.so:
+ ln -s .libs/libqueue-listener.so
+
+qpid_test_SOURCES = qpid-test.cpp
+qpid_test_LDFLAGS = -L${QPIDC_LIB} -R${QPIDC_LIB} -lqpidclient -lqpidcommon
+
+client_test_SOURCES = client-test.cpp
+client_test_LDFLAGS = -lxml2 -lcurl -lmozjs -L${QPIDC_LIB} -R${QPIDC_LIB} -lqpidclient -lqpidcommon
+
+dist_noinst_SCRIPTS = send-test server-test
+noinst_PROGRAMS = qpid-test client-test
+TESTS = send-test server-test
+
+endif
diff --git a/sandbox/sebastien/cpp/apr-2/components/queue/client-test.cpp b/sandbox/sebastien/cpp/apr-2/components/queue/client-test.cpp
new file mode 100644
index 0000000000..286faa2930
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/queue/client-test.cpp
@@ -0,0 +1,99 @@
+/*
+ * 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 queue component.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "list.hpp"
+#include "element.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "perf.hpp"
+#include "../../modules/http/http.hpp"
+#include "qpid.hpp"
+
+// Ignore conversion issues and redundant declarations in Qpid headers
+#ifdef WANT_MAINTAINER_MODE
+#pragma GCC diagnostic ignored "-Wconversion"
+#pragma GCC diagnostic ignored "-Wredundant-decls"
+#endif
+
+namespace tuscany {
+namespace queue {
+
+const value key(mklist<value>(string("report")));
+const string qname("reportq");
+
+const list<value> item = list<value>()
+ + (list<value>() + "name" + string("Apple"))
+ + (list<value>() + "price" + string("$2.99"));
+const list<value> entry = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), item);
+
+bool testDeclareQueue() {
+ QpidConnection qc;
+ QpidSession qs(qc);
+ const failable<bool> r = declareQueue(key, qname, qs);
+ assert(hasContent(r));
+ return true;
+}
+
+const bool listener(const value& k, const value& v) {
+ cerr << "k " << k << " v " << v << endl;
+ assert(k == key);
+ assert(v == entry);
+ return false;
+}
+
+bool testListen() {
+ QpidConnection qc;
+ QpidSession qs(qc);
+ QpidSubscription qsub(qs);
+ const lambda<bool(const value&, const value&)> l(listener);
+ listen(qname, l, qsub);
+ return true;
+}
+
+bool testPost() {
+ gc_scoped_pool pool;
+ http::CURLSession ch("", "", "");
+ const failable<value> id = http::post(entry, "http://localhost:8090/print-sender", ch);
+ assert(hasContent(id));
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::queue::testDeclareQueue();
+ tuscany::queue::testPost();
+ tuscany::queue::testListen();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/queue/qpid-test.cpp b/sandbox/sebastien/cpp/apr-2/components/queue/qpid-test.cpp
new file mode 100644
index 0000000000..1a650157b2
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/queue/qpid-test.cpp
@@ -0,0 +1,97 @@
+/*
+ * 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 Qpid support functions.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "list.hpp"
+#include "element.hpp"
+#include "monad.hpp"
+#include "value.hpp"
+#include "perf.hpp"
+#include "qpid.hpp"
+
+// Ignore conversion issues and redundant declarations in Qpid headers
+#ifdef WANT_MAINTAINER_MODE
+#pragma GCC diagnostic ignored "-Wconversion"
+#pragma GCC diagnostic ignored "-Wredundant-decls"
+#endif
+
+namespace tuscany {
+namespace queue {
+
+const value key(mklist<value>("test"));
+const string qname("testq");
+
+bool testDeclareQueue() {
+ QpidConnection qc;
+ QpidSession qs(qc);
+ const failable<bool> r = declareQueue(key, qname, qs);
+ assert(hasContent(r));
+ return true;
+}
+
+const list<value> item = list<value>()
+ + (list<value>() + "name" + string("Apple"))
+ + (list<value>() + "price" + string("$2.99"));
+const list<value> entry = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), item);
+
+bool testPost() {
+ QpidConnection qc;
+ QpidSession qs(qc);
+ const failable<bool> r = post(key, entry, qs);
+ assert(hasContent(r));
+ return true;
+}
+
+const bool listener(const value& k, const value& v) {
+ assert(k == key);
+ assert(v == entry);
+ return false;
+}
+
+bool testListen() {
+ QpidConnection qc;
+ QpidSession qs(qc);
+ QpidSubscription qsub(qs);
+ const lambda<bool(const value&, const value&)> l(listener);
+ listen(qname, l, qsub);
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::queue::testDeclareQueue();
+ tuscany::queue::testPost();
+ tuscany::queue::testListen();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/queue/qpid.hpp b/sandbox/sebastien/cpp/apr-2/components/queue/qpid.hpp
new file mode 100644
index 0000000000..2651e3a433
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/queue/qpid.hpp
@@ -0,0 +1,260 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_qpid_hpp
+#define tuscany_qpid_hpp
+
+/**
+ * AMQP queue access functions.
+ */
+
+// Ignore conversion issues and redundant declarations in Qpid headers
+#ifdef WANT_MAINTAINER_MODE
+#pragma GCC diagnostic ignored "-Wconversion"
+#pragma GCC diagnostic ignored "-Wredundant-decls"
+#endif
+
+#include <qpid/client/Connection.h>
+#include <qpid/client/Session.h>
+#include <qpid/client/MessageListener.h>
+#include <qpid/client/SubscriptionManager.h>
+
+#include "string.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "../../modules/scheme/eval.hpp"
+
+namespace tuscany {
+namespace queue {
+
+/**
+ * Represents a Qpid connection.
+ */
+class QpidConnection {
+public:
+ QpidConnection() : owner(true) {
+ c.open("localhost", 5672);
+ }
+
+ QpidConnection(const bool owner) : owner(owner) {
+ c.open("localhost", 5672);
+ }
+
+ QpidConnection(const QpidConnection& qc) : owner(false), c(qc.c) {
+ }
+
+ ~QpidConnection() {
+ if (!owner)
+ return;
+ c.close();
+ }
+
+private:
+ friend const failable<bool> close(QpidConnection& qc);
+ friend class QpidSession;
+
+ const bool owner;
+ qpid::client::Connection c;
+
+};
+
+/**
+ * Close a Qpid connection.
+ */
+const failable<bool> close(QpidConnection& qc) {
+ qc.c.close();
+ return true;
+}
+
+/**
+ * Represents a Qpid session.
+ */
+class QpidSession {
+public:
+ QpidSession(QpidConnection& qc) : owner(true), s(qc.c.newSession()) {
+ }
+
+ QpidSession(QpidConnection& qc, const bool owner) : owner(owner), s(qc.c.newSession()) {
+ }
+
+ QpidSession(const QpidSession& qs) : owner(false), s(qs.s) {
+ }
+
+ ~QpidSession() {
+ if (!owner)
+ return;
+ s.close();
+ }
+
+private:
+ friend const failable<bool> close(QpidSession& qs);
+ friend const failable<bool> declareQueue(const value& key, const string& name, QpidSession& qs);
+ friend const failable<bool> post(const value& key, const value& val, QpidSession& qs);
+ friend class QpidSubscription;
+
+ const bool owner;
+ qpid::client::Session s;
+};
+
+/**
+ * Close a Qpid session.
+ */
+const failable<bool> close(QpidSession& qs) {
+ try {
+ qs.s.close();
+ } catch (const qpid::Exception& e) {
+ return mkfailure<bool>(string("Qpid failure: ") + e.what());
+ }
+ return true;
+}
+
+/**
+ * Declare a key / AMQP queue pair.
+ */
+const failable<bool> declareQueue(const value& key, const string& name, QpidSession& qs) {
+ const string ks(scheme::writeValue(key));
+ try {
+ qs.s.queueDeclare(qpid::client::arg::queue=c_str(name));
+ qs.s.exchangeBind(qpid::client::arg::exchange="amq.direct", qpid::client::arg::queue=c_str(name), qpid::client::arg::bindingKey=c_str(ks));
+ } catch (const qpid::Exception& e) {
+ return mkfailure<bool>(string("Qpid failure: ") + e.what());
+ }
+ return true;
+}
+
+/**
+ * Post a key / value pair message to an AMQP broker.
+ */
+const failable<bool> post(const value& key, const value& val, QpidSession& qs) {
+
+ // Send in a message with the given key.
+ const string ks(scheme::writeValue(key));
+ const string vs(scheme::writeValue(val));
+ try {
+ qpid::client::Message message;
+ message.getDeliveryProperties().setRoutingKey(c_str(ks));
+ message.setData(c_str(vs));
+ qs.s.messageTransfer(qpid::client::arg::content=message, qpid::client::arg::destination="amq.direct");
+ } catch (const qpid::Exception& e) {
+ return mkfailure<bool>(string("Qpid failure: ") + e.what());
+ }
+ return true;
+}
+
+/**
+ * Represents a Qpid subscription.
+ */
+class QpidSubscription {
+public:
+ QpidSubscription(QpidSession& qs) : owner(true), subs(qs.s) {
+ }
+
+ QpidSubscription(QpidSession& qs, const bool owner) : owner(owner), subs(qs.s) {
+ }
+
+ QpidSubscription(const QpidSubscription& qsub) : owner(false), subs(qsub.subs) {
+ }
+
+ ~QpidSubscription() {
+ if (!owner)
+ return;
+ try {
+ subs.stop();
+ } catch (const qpid::Exception& e) {
+ mkfailure<bool>(string("Qpid failure: ") + e.what());
+ }
+ }
+
+private:
+ friend const failable<bool> listen(const string& name, const lambda<bool(const value&, const value&)>& l, QpidSubscription& qsub);
+ friend const failable<bool> stop(QpidSubscription& qsub);
+
+ const bool owner;
+ qpid::client::SubscriptionManager subs;
+};
+
+/**
+ * Register a listener function with an AMQP queue.
+ */
+class Listener : public qpid::client::MessageListener {
+public:
+ Listener(const lambda<bool(const value&, const value&)> l, qpid::client::SubscriptionManager& subs) : l(l), subs(subs) {
+ }
+
+ virtual void received(qpid::client::Message& msg) {
+
+ // Call the listener function
+ const value k(scheme::readValue(msg.getDeliveryProperties().getRoutingKey().c_str()));
+ const value v(scheme::readValue(msg.getData().c_str()));
+ const bool r = l(k, v);
+ if (!r) {
+ try {
+ subs.cancel(msg.getDestination());
+ } catch (const qpid::Exception& e) {
+ mkfailure<bool>(string("Qpid failure: ") + e.what());
+ }
+ }
+ }
+
+private:
+ const lambda<bool(const value&, const value&)> l;
+ qpid::client::SubscriptionManager& subs;
+};
+
+
+const failable<bool> listen(const string& name, const lambda<bool(const value&, const value&)>& l, QpidSubscription& qsub) {
+ debug("queue::listen");
+ Listener listener(l, qsub.subs);
+ try {
+ qsub.subs.subscribe(listener, c_str(name));
+ qsub.subs.run();
+ } catch (const qpid::Exception& e) {
+ return mkfailure<bool>(string("Qpid failure: ") + e.what());
+ }
+ debug("queue::listen::stopped");
+ return true;
+}
+
+/**
+ * Stop an AMQP subscription.
+ */
+const failable<bool> stop(QpidSubscription& qsub) {
+ debug("queue::stop");
+ try {
+ qsub.subs.stop();
+ } catch (const qpid::Exception& e) {
+ return mkfailure<bool>(string("Qpid failure: ") + e.what());
+ }
+ debug("queue::stopped");
+ return true;
+}
+
+}
+}
+
+// Re-enable conversion and redundant declarations warnings
+#ifdef WANT_MAINTAINER_MODE
+#pragma GCC diagnostic warning "-Wconversion"
+#pragma GCC diagnostic warning "-Wredundant-decls"
+#endif
+
+#endif /* tuscany_qpid_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/components/queue/qpidd-start b/sandbox/sebastien/cpp/apr-2/components/queue/qpidd-start
new file mode 100755
index 0000000000..02e048c41e
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/queue/qpidd-start
@@ -0,0 +1,24 @@
+#!/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.
+
+# Start qpidd
+here=`readlink -f $0`; here=`dirname $here`
+
+qpid_prefix=`cat $here/qpidc.prefix`
+$qpid_prefix/sbin/qpidd &
diff --git a/sandbox/sebastien/cpp/apr-2/components/queue/qpidd-stop b/sandbox/sebastien/cpp/apr-2/components/queue/qpidd-stop
new file mode 100755
index 0000000000..3baf2fee27
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/queue/qpidd-stop
@@ -0,0 +1,26 @@
+#!/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.
+
+# Stop qpidd
+here=`readlink -f $0`; here=`dirname $here`
+
+qpid_prefix=`cat $here/qpidc.prefix`
+qpidd="$qpid_prefix/sbin/qpidd"
+
+kill `ps -ef | grep -v grep | grep "${qpidd}" | awk '{ print $2 }'`
diff --git a/sandbox/sebastien/cpp/apr-2/components/queue/queue-listener.componentType b/sandbox/sebastien/cpp/apr-2/components/queue/queue-listener.componentType
new file mode 100644
index 0000000000..1e94f9a2df
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/queue/queue-listener.componentType
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<componentType xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/components">
+
+ <reference name="relay"/>
+ <property name="key" type="xsd:string"/>
+ <property name="queue" type="xsd:string"/>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/components/queue/queue-listener.cpp b/sandbox/sebastien/cpp/apr-2/components/queue/queue-listener.cpp
new file mode 100644
index 0000000000..d714101583
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/queue/queue-listener.cpp
@@ -0,0 +1,158 @@
+/*
+ * 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$ */
+
+/**
+ * AMQP queue listener component implementation.
+ */
+
+#include "string.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "parallel.hpp"
+#include "qpid.hpp"
+
+// Ignore conversion issues and redundant declarations in Qpid headers
+#ifdef WANT_MAINTAINER_MODE
+#pragma GCC diagnostic ignored "-Wconversion"
+#pragma GCC diagnostic ignored "-Wredundant-decls"
+#endif
+
+namespace tuscany {
+namespace queue {
+
+/**
+ * A relay function that posts the AMQP messages it receives to a relay component reference.
+ */
+class relay {
+public:
+ relay(const lambda<value(const list<value>&)>& rel) : rel(rel) {
+ }
+
+ const bool operator()(const value& k, const value& v) const {
+ debug(k, "queue::relay::key");
+ debug(v, "queue::relay::value");
+ const value res = rel(mklist<value>("post", isList(k)? (list<value>)k : mklist<value>(k), v));
+ return true;
+ }
+
+private:
+ const lambda<value(const list<value>&)> rel;
+};
+
+/**
+ * Subscribe and listen to an AMQP queue.
+ */
+class subscribe {
+public:
+ subscribe(const string& qname, const lambda<bool(const value&, const value&)>& l, const QpidSubscription& qsub) : qname(qname), l(l), qsub(qsub) {
+ }
+
+ const failable<bool> operator()() const {
+ gc_pool pool;
+ debug(qname, "queue::subscribe::listen");
+ const failable<bool> r = listen(qname, l, const_cast<QpidSubscription&>(qsub));
+ debug(qname, "queue::subscribe::stopped");
+ return r;
+ }
+
+private:
+ const string qname;
+ const lambda<bool(const value&, const value&)> l;
+ const QpidSubscription qsub;
+};
+
+/**
+ * Listener lambda function, responsible for starting an AMQP subscription in a worker thread, and
+ * apply any function calls to the listener component. The only supported function is stop(),
+ * called to stop the listener component and shutdown the worker thread.
+ */
+class listener {
+public:
+ listener(QpidConnection& qc, QpidSession& qs, QpidSubscription& qsub, worker& w) : qc(qc), qs(qs), qsub(qsub), w(w) {
+ }
+
+ const value operator()(const list<value>& params) const {
+ const tuscany::value func(car(params));
+
+ // Stop the component
+ if (func != "stop")
+ return tuscany::mkfailure<tuscany::value>();
+ debug("queue::listener::stop");
+
+ // TODO check why stop() and close() hang in child processes
+ stop(const_cast<QpidSubscription&>(qsub));
+ close(const_cast<QpidSession&>(qs));
+ close(const_cast<QpidConnection&>(qc));
+ cancel(const_cast<worker&>(w));
+
+ debug("queue::listener::stopped");
+ return failable<value>(value(lambda<value(const list<value>&)>()));
+ }
+
+private:
+ QpidConnection qc;
+ QpidSession qs;
+ QpidSubscription qsub;
+ worker w;
+};
+
+/**
+ * Start the component.
+ */
+const failable<value> start(const list<value>& params) {
+ // Extract the relay reference and the AMQP key and queue name
+ const value rel = car(params);
+ const value pk = ((lambda<value(list<value>)>)cadr(params))(list<value>());
+ const value key = isList(pk)? (list<value>)pk : mklist<value>(pk);
+ const value qname = ((lambda<value(list<value>)>)caddr(params))(list<value>());
+
+ // Create an AMQP session
+ QpidConnection qc(false);
+ QpidSession qs(qc, false);
+
+ // Declare the configured AMQP key / queue pair
+ declareQueue(key, qname, qs);
+
+ // Listen and relay messages in a worker thread
+ QpidSubscription qsub(qs, false);
+ worker w(3);
+ const lambda<bool(const value&, const value&)> rl = relay(rel);
+ submit<failable<bool> >(w, lambda<failable<bool>()>(subscribe(qname, rl, qsub)));
+
+ // Return the listener component lambda function
+ return value(lambda<value(const list<value>&)>(listener(qc, qs, qsub, w)));
+}
+
+}
+}
+
+extern "C" {
+
+const tuscany::value apply(const tuscany::list<tuscany::value>& params) {
+ const tuscany::value func(car(params));
+ if (func == "start")
+ return tuscany::queue::start(cdr(params));
+ return tuscany::mkfailure<tuscany::value>();
+}
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/queue/queue-sender.componentType b/sandbox/sebastien/cpp/apr-2/components/queue/queue-sender.componentType
new file mode 100644
index 0000000000..fc06bf2dcf
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/queue/queue-sender.componentType
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<componentType xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/components">
+
+ <service name="sender"/>
+ <property name="key" type="xsd:string"/>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/components/queue/queue-sender.cpp b/sandbox/sebastien/cpp/apr-2/components/queue/queue-sender.cpp
new file mode 100644
index 0000000000..07f8491f54
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/queue/queue-sender.cpp
@@ -0,0 +1,72 @@
+/*
+ * 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$ */
+
+/**
+ * AMQP queue sender component implementation.
+ */
+
+#include "string.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "qpid.hpp"
+
+// Ignore conversion issues and redundant declarations in Qpid headers
+#ifdef WANT_MAINTAINER_MODE
+#pragma GCC diagnostic ignored "-Wconversion"
+#pragma GCC diagnostic ignored "-Wredundant-decls"
+#endif
+
+namespace tuscany {
+namespace queue {
+
+/**
+ * Post an item to a queue.
+ */
+const failable<value> post(const list<value>& params) {
+ QpidConnection qc;
+ QpidSession qs(qc);
+
+ // Post the item
+ const value pk = ((lambda<value(list<value>)>)caddr(params))(list<value>());
+ const value key = isList(pk)? append<value>(pk, (list<value>)car(params)) : cons<value>(pk, (list<value>)car(params));
+ debug(key, "queue::post::key");
+ debug(cadr(params), "queue::post::value");
+ const failable<bool> r = post(key, cadr(params), qs);
+ if (!hasContent(r))
+ return mkfailure<value>(reason(r));
+ return key;
+}
+
+}
+}
+
+extern "C" {
+
+const tuscany::value apply(const tuscany::list<tuscany::value>& params) {
+ const tuscany::value func(car(params));
+ if (func == "post")
+ return tuscany::queue::post(cdr(params));
+ return tuscany::mkfailure<tuscany::value>();
+}
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/queue/queue.composite b/sandbox/sebastien/cpp/apr-2/components/queue/queue.composite
new file mode 100644
index 0000000000..e8fb1b1049
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/queue/queue.composite
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/components"
+ name="queue">
+
+ <component name="print-sender">
+ <implementation.cpp path="." library="libqueue-sender"/>
+ <property name="key">print</property>
+ <service name="print-sender">
+ <t:binding.http uri="print-sender"/>
+ </service>
+ </component>
+
+ <component name="print-listener">
+ <implementation.cpp path="." library="libqueue-listener"/>
+ <property name="key">print</property>
+ <property name="queue">printq</property>
+ <reference name="relay" target="print"/>
+ </component>
+
+ <component name="print">
+ <t:implementation.scheme script="server-test.scm"/>
+ <service name="print">
+ <t:binding.http uri="print"/>
+ </service>
+ <reference name="report" target="report-sender"/>
+ </component>
+
+ <component name="report-sender">
+ <implementation.cpp path="." library="libqueue-sender"/>
+ <property name="key">report</property>
+ <service name="report-sender">
+ <t:binding.http uri="report-sender"/>
+ </service>
+ </component>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/components/queue/send-test b/sandbox/sebastien/cpp/apr-2/components/queue/send-test
new file mode 100755
index 0000000000..ec6d9d9083
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/queue/send-test
@@ -0,0 +1,31 @@
+#!/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
+./qpidd-start
+sleep 1
+
+# Test
+./qpid-test 2>/dev/null
+rc=$?
+
+# Cleanup
+./qpidd-stop
+sleep 1
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/components/queue/server-test b/sandbox/sebastien/cpp/apr-2/components/queue/server-test
new file mode 100755
index 0000000000..571b09082c
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/queue/server-test
@@ -0,0 +1,43 @@
+#!/bin/sh
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# Setup
+../../modules/http/httpd-conf tmp localhost 8090 ../../modules/http/htdocs
+../../modules/server/server-conf tmp
+../../modules/server/scheme-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+SCAContribution `pwd`/
+SCAComposite queue.composite
+EOF
+
+./qpidd-start
+sleep 1
+../../modules/http/httpd-start tmp
+sleep 2
+
+# Test
+./client-test 2>/dev/null
+rc=$?
+
+# Cleanup
+../../modules/http/httpd-stop tmp
+sleep 1
+./qpidd-stop
+sleep 1
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/components/queue/server-test.scm b/sandbox/sebastien/cpp/apr-2/components/queue/server-test.scm
new file mode 100644
index 0000000000..1a89ce8b31
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/queue/server-test.scm
@@ -0,0 +1,20 @@
+; 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.
+
+; Queue test case
+
+(define (post key val report) (report "post" '() val))
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/Makefile.am b/sandbox/sebastien/cpp/apr-2/components/sqldb/Makefile.am
new file mode 100644
index 0000000000..4cd27e967c
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/Makefile.am
@@ -0,0 +1,55 @@
+# 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.
+
+if WANT_SQLDB
+
+INCLUDES = -I${PGSQL_INCLUDE}
+
+incl_HEADERS = *.hpp
+incldir = $(prefix)/include/components/sqldb
+
+dist_comp_SCRIPTS = pgsql-conf pgsql-start pgsql-stop pgsql pgsql-standby-conf pgsql-backup
+compdir=$(prefix)/components/sqldb
+
+comp_DATA = pgsql.prefix
+pgsql.prefix: $(top_builddir)/config.status
+ echo ${PGSQL_PREFIX} >pgsql.prefix
+
+EXTRA_DIST = sqldb.composite sqldb.componentType
+
+comp_LTLIBRARIES = libsqldb.la
+noinst_DATA = libsqldb.so
+
+libsqldb_la_SOURCES = sqldb.cpp
+libsqldb_la_LDFLAGS = -L${PGSQL_LIB} -R${PGSQL_LIB} -lpq
+libsqldb.so:
+ ln -s .libs/libsqldb.so
+
+pgsql_test_SOURCES = pgsql-test.cpp
+pgsql_test_LDFLAGS = -L${PGSQL_LIB} -R${PGSQL_LIB} -lpq
+
+pgsql_standby_test_SOURCES = pgsql-standby-test.cpp
+pgsql_standby_test_LDFLAGS = -L${PGSQL_LIB} -R${PGSQL_LIB} -lpq
+
+client_test_SOURCES = client-test.cpp
+client_test_LDFLAGS = -lxml2 -lcurl -lmozjs
+
+dist_noinst_SCRIPTS = sqldb-test standby-test server-test
+noinst_PROGRAMS = pgsql-test pgsql-standby-test client-test
+TESTS = sqldb-test standby-test server-test
+
+endif
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/client-test.cpp b/sandbox/sebastien/cpp/apr-2/components/sqldb/client-test.cpp
new file mode 100644
index 0000000000..4e5c067633
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/client-test.cpp
@@ -0,0 +1,130 @@
+/*
+ * 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 SQL database component.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "perf.hpp"
+#include "../../modules/http/http.hpp"
+
+namespace tuscany {
+namespace sqldb {
+
+const string uri("http://localhost:8090/sqldb");
+
+bool testSqlDb() {
+ http::CURLSession cs("", "", "");
+
+ const list<value> i = list<value>()
+ + (list<value>() + "name" + string("Apple"))
+ + (list<value>() + "price" + string("$2.99"));
+ const list<value> a = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
+
+ const failable<value> id = http::post(a, uri, cs);
+ assert(hasContent(id));
+
+ const string p = path(content(id));
+ {
+ const failable<value> val = http::get(uri + p, cs);
+ assert(hasContent(val));
+ assert(content(val) == a);
+ }
+
+ const list<value> j = list<value>()
+ + (list<value>() + "name" + string("Apple"))
+ + (list<value>() + "price" + string("$3.55"));
+ const list<value> b = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), j);
+
+ {
+ const failable<value> r = http::put(b, uri + p, cs);
+ assert(hasContent(r));
+ assert(content(r) == value(true));
+ }
+ {
+ const failable<value> val = http::get(uri + p, cs);
+ assert(hasContent(val));
+ assert(content(val) == b);
+ }
+ {
+ const failable<value> r = http::del(uri + p, cs);
+ assert(hasContent(r));
+ assert(content(r) == value(true));
+ }
+ {
+ const failable<value> val = http::get(uri + p, cs);
+ assert(!hasContent(val));
+ }
+
+ return true;
+}
+
+struct getLoop {
+ const string path;
+ const value entry;
+ http::CURLSession cs;
+ getLoop(const string& path, const value& entry, http::CURLSession cs) : path(path), entry(entry), cs(cs) {
+ }
+ const bool operator()() const {
+ const failable<value> val = http::get(uri + path, cs);
+ assert(hasContent(val));
+ assert(content(val) == entry);
+ return true;
+ }
+};
+
+bool testGetPerf() {
+ const list<value> i = list<value>()
+ + (list<value>() + "name" + string("Apple"))
+ + (list<value>() + "price" + string("$4.55"));
+ const value a = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
+
+ http::CURLSession cs("", "", "");
+ const failable<value> id = http::post(a, uri, cs);
+ assert(hasContent(id));
+ const string p = path(content(id));
+
+ const lambda<bool()> gl = getLoop(p, a, cs);
+ cout << "Sqldb get test " << time(gl, 5, 200) << " ms" << endl;
+
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::sqldb::testSqlDb();
+ tuscany::sqldb::testGetPerf();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql
new file mode 100755
index 0000000000..dab30e642b
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql
@@ -0,0 +1,35 @@
+#!/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.
+
+# Run SQL command
+here=`readlink -f $0`; here=`dirname $here`
+pgsql_prefix=`cat $here/pgsql.prefix`
+
+if [ "$2" = "" ]; then
+ host="localhost"
+ port="5432"
+ cmd="$1"
+else
+ host="$1"
+ port="$2"
+ cmd="$3"
+fi
+
+$pgsql_prefix/bin/psql -h $host -p $port -c "$cmd" db
+
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-backup b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-backup
new file mode 100755
index 0000000000..fad59236bf
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-backup
@@ -0,0 +1,41 @@
+#!/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.
+
+# Backup postgresql data directory
+here=`readlink -f $0`; here=`dirname $here`
+root=`readlink -f $1`
+
+if [ "$2" = "" ]; then
+ host="localhost"
+ port="5432"
+else
+ host="$2"
+ port="$3"
+fi
+
+pgsql_prefix=`cat $here/pgsql.prefix`
+$pgsql_prefix/bin/psql -h $host -p $port -c "SELECT pg_start_backup('backup', true)" db 1>>$root/logs/postgresql 2>&1
+
+echo "Content-type: application/x-compressed"
+echo
+
+tar -C $root/sqldb -cz data
+
+$pgsql_prefix/bin/psql -h $host -p $port -c "SELECT pg_stop_backup()" db 1>>$root/logs/postgresql 2>&1
+
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-conf b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-conf
new file mode 100755
index 0000000000..f5cc2d23e3
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-conf
@@ -0,0 +1,105 @@
+#!/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.
+
+# Configure a postgresql master server
+here=`readlink -f $0`; here=`dirname $here`
+mkdir -p $1
+root=`readlink -f $1`
+
+addr=$2
+if [ "$addr" = "" ]; then
+ ip="*"
+ port="5432"
+else
+ ip=`$here/../../modules/http/httpd-addr ip $addr`
+ if [ "$ip" = "" ]; then
+ ip="*"
+ fi
+ port=`$here/../../modules/http/httpd-addr port $addr`
+fi
+
+pgsql_prefix=`cat $here/pgsql.prefix`
+mkdir -p $root/sqldb/data
+chmod 700 $root/sqldb/data
+mkdir -p $root/sqldb/archive
+mkdir -p $root/logs
+if [ ! -f $root/sqldb/data/postgresql.conf ]; then
+ $pgsql_prefix/bin/pg_ctl init -D $root/sqldb/data 1>>$root/logs/postgresql 2>&1
+ cp $root/sqldb/data/postgresql.conf $root/sqldb/data/postgresql-init.conf
+ cp $root/sqldb/data/pg_hba.conf $root/sqldb/data/pg_hba-init.conf
+fi
+
+# Generate server configuration
+cp $root/sqldb/data/postgresql-init.conf $root/sqldb/data/postgresql.conf
+cat >>$root/sqldb/data/postgresql.conf <<EOF
+
+# Generated by: pgsql-conf $*
+
+# Listen
+listen_addresses = '$ip'
+port = $port
+
+# Setup archival
+archive_mode = on
+archive_command = 'cp %p $root/sqldb/archive/%f'
+
+# Setup hot standby with streaming replication
+wal_level = hot_standby
+max_wal_senders = 5
+wal_keep_segments = 32
+
+EOF
+
+# Generate client auth configuration
+cp $root/sqldb/data/pg_hba-init.conf $root/sqldb/data/pg_hba.conf
+cat >>$root/sqldb/data/pg_hba.conf <<EOF
+
+# Generated by: pgsql-conf $*
+# TYPE DATABASE USER CIDR-ADDRESS METHOD
+host all all samenet trust
+host replication all samenet trust
+
+EOF
+
+# Create the db
+$pgsql_prefix/bin/pg_ctl start -w -D $root/sqldb/data -l $root/logs/postgresql 1>>$root/logs/postgresql 2>&1
+$pgsql_prefix/bin/createdb -h localhost -p $port db 1>>$root/logs/postgresql 2>&1
+$pgsql_prefix/bin/pg_ctl stop -w -D $root/sqldb/data 1>>$root/logs/postgresql 2>&1
+
+# Generate database backup script
+mkdir -p $root/sqldb/scripts
+cat >$root/sqldb/scripts/backup <<EOF
+#!/bin/sh
+$here/pgsql-backup $root localhost $port
+EOF
+chmod 700 $root/sqldb/scripts/backup
+
+# Configure HTTPD to serve backup and archive files
+if [ -f "$root/conf/httpd.conf" ]; then
+ cat >>$root/conf/httpd.conf <<EOF
+# Generated by: pgsql-conf $*
+
+# Serve PostgreSQL backup and WAL archive files
+ScriptAlias /pgsql-backup "$root/sqldb/scripts/backup"
+Alias /pgsql-archive "$root/sqldb/archive"
+
+EOF
+
+fi
+
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-standby-conf b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-standby-conf
new file mode 100755
index 0000000000..cbfd90b48c
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-standby-conf
@@ -0,0 +1,122 @@
+#!/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.
+
+# Configure a postgresql hot standby server
+here=`readlink -f $0`; here=`dirname $here`
+mkdir -p $1
+root=`readlink -f $1`
+
+# Server address
+addr=$2
+if [ "$addr" = "" ]; then
+ ip="*"
+ port="5432"
+else
+ ip=`$here/../../modules/http/httpd-addr ip $addr`
+ if [ "$ip" = "" ]; then
+ ip="*"
+ fi
+ port=`$here/../../modules/http/httpd-addr port $addr`
+fi
+
+# Master server address
+if [ "$3" = "" ]; then
+ mhost="localhost"
+ mport="5432"
+ mhttpport="80"
+else
+ mhost="$3"
+ mport="$4"
+ mhttpport="$5"
+fi
+
+pgsql_prefix=`cat $here/pgsql.prefix`
+mkdir -p $root/sqldb/data
+chmod 700 $root/sqldb/data
+mkdir -p $root/sqldb/archive
+mkdir -p $root/logs
+
+# Initialize from a backup of the master
+if [ ! -f $root/sqldb/data/postgresql.conf ]; then
+ (wget http://$mhost:$mhttpport/pgsql-backup -O - | tar -C $root/sqldb -xz) 1>>$root/logs/postgresql 2>&1
+ rm -rf $root/sqldb/data/postmaster.pid $root/sqldb/data/pg_xlog
+ mkdir -p $root/sqldb/data/pg_xlog/archive_status
+ chmod 700 $root/sqldb/data/pg_xlog/archive_status
+fi
+
+# Generate server configuration
+cp $root/sqldb/data/postgresql-init.conf $root/sqldb/data/postgresql.conf
+cat >>$root/sqldb/data/postgresql.conf <<EOF
+
+# Generated by: standby-conf $*
+
+# Listen
+listen_addresses = '$ip'
+port = $port
+
+# Setup archival
+archive_mode = on
+archive_command = 'cp %p $root/sqldb/archive/%f'
+
+# Setup hot standby with streaming replication
+wal_level = hot_standby
+max_wal_senders = 5
+wal_keep_segments = 32
+
+# Enable hot standby
+hot_standby = on
+
+EOF
+
+# Generate recovery configuration
+cat >$root/sqldb/data/recovery.conf << EOF
+# Generated by: pgsql-slave-conf $*
+
+# Start in standby mode
+standby_mode = 'on'
+primary_conninfo = 'host=$mhost port=$mport'
+
+# Failover
+trigger_file = '$root/sqldb/failover'
+
+restore_command = 'wget http://$mhost:$mhttpport/pgsql-archive/%f -O "%p"'
+
+EOF
+
+# Generate database backup script
+mkdir -p $root/sqldb/scripts
+cat >$root/sqldb/scripts/backup <<EOF
+#!/bin/sh
+$here/pgsql-backup $root localhost $port
+EOF
+chmod 700 $root/sqldb/scripts/backup
+
+# Configure HTTPD to serve backup and archive files
+if [ -f "$root/conf/httpd.conf" ]; then
+ cat >>$root/conf/httpd.conf <<EOF
+# Generated by: pgsql-conf $*
+
+# Serve PostgreSQL backup and WAL archive files
+ScriptAlias /pgsql-backup "$root/sqldb/scripts/backup"
+Alias /pgsql-archive "$root/sqldb/archive"
+
+EOF
+
+fi
+
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-standby-test.cpp b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-standby-test.cpp
new file mode 100644
index 0000000000..44f0a4a9e6
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-standby-test.cpp
@@ -0,0 +1,88 @@
+/*
+ * 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 PostgreSQL hot standby support.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "perf.hpp"
+#include "pgsql.hpp"
+
+namespace tuscany {
+namespace pgsql {
+
+bool testPGSql() {
+ PGSql wpg("host=localhost port=5432 dbname=db", "test");
+ PGSql rpg("host=localhost port=5433 dbname=db", "test");
+ const value k = mklist<value>("a");
+
+ assert(hasContent(post(k, string("AAA"), wpg)));
+ sleep(1);
+ assert((get(k, rpg)) == value(string("AAA")));
+ assert(hasContent(put(k, string("aaa"), wpg)));
+ sleep(1);
+ assert((get(k, rpg)) == value(string("aaa")));
+ assert(hasContent(del(k, wpg)));
+ sleep(1);
+ assert(!hasContent(get(k, rpg)));
+
+ return true;
+}
+
+struct getLoop {
+ const value k;
+ PGSql& pg;
+ getLoop(const value& k, PGSql& pg) : k(k), pg(pg) {
+ }
+ const bool operator()() const {
+ assert((get(k, pg)) == value(string("CCC")));
+ return true;
+ }
+};
+
+bool testGetPerf() {
+ const value k = mklist<value>("c");
+ PGSql wpg("host=localhost port=5432 dbname=db", "test");
+ PGSql rpg("host=localhost port=5433 dbname=db", "test");
+ assert(hasContent(post(k, string("CCC"), wpg)));
+ sleep(1);
+
+ const lambda<bool()> gl = getLoop(k, rpg);
+ cout << "PGSql get test " << time(gl, 5, 200) << " ms" << endl;
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::pgsql::testPGSql();
+ tuscany::pgsql::testGetPerf();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-start b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-start
new file mode 100755
index 0000000000..3f03d0b4dc
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-start
@@ -0,0 +1,29 @@
+#!/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.
+
+# Start postgresql
+here=`readlink -f $0`; here=`dirname $here`
+root=`readlink -f $1`
+
+pgsql_prefix=`cat $here/pgsql.prefix`
+mkdir -p $root/sqldb
+mkdir -p $root/logs
+$pgsql_prefix/bin/pg_ctl start -w -D $root/sqldb/data -l $root/logs/postgresql 1>>$root/logs/postgresql 2>&1
+sleep 1
+
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-stop b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-stop
new file mode 100755
index 0000000000..eefade47d2
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-stop
@@ -0,0 +1,27 @@
+#!/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.
+
+# Stop postgresql
+here=`readlink -f $0`; here=`dirname $here`
+root=`readlink -f $1`
+
+pgsql_prefix=`cat $here/pgsql.prefix`
+mkdir -p $root/logs
+$pgsql_prefix/bin/pg_ctl stop -w -D $root/sqldb/data 1>>$root/logs/postgresql 2>&1
+
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-test.cpp b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-test.cpp
new file mode 100644
index 0000000000..1019667285
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql-test.cpp
@@ -0,0 +1,82 @@
+/*
+ * 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 PostgreSQL access functions.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "perf.hpp"
+#include "pgsql.hpp"
+
+namespace tuscany {
+namespace pgsql {
+
+bool testPGSql() {
+ PGSql pg("host=localhost port=5432 dbname=db", "test");
+ const value k = mklist<value>("a");
+
+ assert(hasContent(post(k, string("AAA"), pg)));
+ assert((get(k, pg)) == value(string("AAA")));
+ assert(hasContent(put(k, string("aaa"), pg)));
+ assert((get(k, pg)) == value(string("aaa")));
+ assert(hasContent(del(k, pg)));
+ assert(!hasContent(get(k, pg)));
+
+ return true;
+}
+
+struct getLoop {
+ const value k;
+ PGSql& pg;
+ getLoop(const value& k, PGSql& pg) : k(k), pg(pg) {
+ }
+ const bool operator()() const {
+ assert((get(k, pg)) == value(string("CCC")));
+ return true;
+ }
+};
+
+bool testGetPerf() {
+ const value k = mklist<value>("c");
+ PGSql pg("host=localhost port=5432 dbname=db", "test");
+ assert(hasContent(post(k, string("CCC"), pg)));
+
+ const lambda<bool()> gl = getLoop(k, pg);
+ cout << "PGSql get test " << time(gl, 5, 200) << " ms" << endl;
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::pgsql::testPGSql();
+ tuscany::pgsql::testGetPerf();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql.hpp b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql.hpp
new file mode 100644
index 0000000000..f4da8db220
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/pgsql.hpp
@@ -0,0 +1,262 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_pgsql_hpp
+#define tuscany_pgsql_hpp
+
+/**
+ * PostgreSQL access functions.
+ */
+
+#include <libpq-fe.h>
+
+#include "string.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "../../modules/scheme/eval.hpp"
+
+namespace tuscany {
+namespace pgsql {
+
+/**
+ * Return and clear a Postgres result failure.
+ */
+const string pgfailure(PGresult* r, PGconn* conn) {
+ const string re = PQresultErrorMessage(r);
+ PQclear(r);
+ if (length(re) != 0)
+ return re;
+ const string ce = PQerrorMessage(conn);
+ return ce;
+}
+
+/**
+ * Represents a PGSql connection.
+ */
+class PGSql {
+public:
+ PGSql() : owner(false) {
+ }
+
+ PGSql(const string& conninfo, const string& table) : owner(true), conn(NULL), conninfo(conninfo), table(table) {
+ conn = PQconnectdb(c_str(conninfo));
+ if (PQstatus(conn) != CONNECTION_OK) {
+ mkfailure<bool>(string("Could not connect to postgresql database: ") + PQerrorMessage(conn));
+ return;
+ }
+ setup(true);
+ }
+
+ PGSql(const PGSql& c) : owner(false), conn(c.conn), conninfo(c.conninfo), table(c.table) {
+ }
+
+ ~PGSql() {
+ if (!owner)
+ return;
+ if (conn == NULL)
+ return;
+ PQfinish(conn);
+ }
+
+private:
+ bool owner;
+ PGconn *conn;
+ string conninfo;
+ string table;
+
+ friend const failable<bool> setup(const PGSql& pgsql);
+ friend const failable<bool> post(const value& key, const value& val, const PGSql& pgsql);
+ friend const failable<bool> put(const value& key, const value& val, const PGSql& pgsql);
+ friend const failable<value> get(const value& key, const PGSql& pgsql);
+ friend const failable<bool> del(const value& key, const PGSql& pgsql);
+
+ /**
+ * Setup the database connection.
+ */
+ const failable<bool> setup(const bool init) const {
+
+ // Check the status of the connection and reconnect if necessary
+ if (!init) {
+ if (PQstatus(conn) == CONNECTION_OK)
+ return true;
+ debug("pgsql::setup::reset");
+ PQreset(conn);
+ if (PQstatus(conn) != CONNECTION_OK)
+ return mkfailure<bool>(string("Could not reconnect to postgresql database: ") + PQerrorMessage(conn));
+ }
+ debug("pgsql::setup::init");
+
+ // Find the name of the first column in the target table
+ // Assume that's the key we need to use
+ string ks = string("select a.attname from pg_attribute a, pg_class c where a.attrelid = c.relfilenode and c.relname = '") + table + string("' and a.attnum in (1, 2) order by a.attnum;");
+ PGresult* kr = PQexec(conn, c_str(ks));
+ if (PQresultStatus(kr) != PGRES_TUPLES_OK)
+ return mkfailure<bool>(string("Could not execute postgresql column select statement: ") + pgfailure(kr, conn));
+ if (PQntuples(kr) != 2) {
+ PQclear(kr);
+ return mkfailure<bool>(string("Could not find postgresql table key and value column names"));
+ }
+ const string kname = PQgetvalue(kr, 0, 0);
+ const string vname = PQgetvalue(kr, 1, 0);
+ PQclear(kr);
+
+ // Prepare the post, put, get and delete statements
+ {
+ PGresult* r = PQprepare(conn, "post", c_str(string("insert into ") + table + string(" values($1, $2);")), 2, NULL);
+ if (PQresultStatus(r) != PGRES_COMMAND_OK)
+ return mkfailure<bool>(string("Could not prepare post postgresql SQL statement: ") + pgfailure(r, conn));
+ PQclear(r);
+ }
+ {
+ PGresult* r = PQprepare(conn, "put", c_str(string("update ") + table + string(" set ") + vname + string(" = $2 where ") + kname + string(" = $1;")), 2, NULL);
+ if (PQresultStatus(r) != PGRES_COMMAND_OK)
+ return mkfailure<bool>(string("Could not prepare put postgresql SQL statement: ") + pgfailure(r, conn));
+ PQclear(r);
+ }
+ {
+ PGresult* r = PQprepare(conn, "get", c_str(string("select * from ") + table + string(" where ") + kname + string(" = $1;")), 1, NULL);
+ if (PQresultStatus(r) != PGRES_COMMAND_OK)
+ return mkfailure<bool>(string("Could not prepare get postgresql SQL statement: ") + pgfailure(r, conn));
+ PQclear(r);
+ }
+ {
+ PGresult* r = PQprepare(conn, "delete", c_str(string("delete from ") + table + string(" where ") + kname + string(" = $1;")), 1, NULL);
+ if (PQresultStatus(r) != PGRES_COMMAND_OK)
+ return mkfailure<bool>(string("Could not prepare delete postgresql SQL statement: ") + pgfailure(r, conn));
+ PQclear(r);
+ }
+ return true;
+ }
+};
+
+/**
+ * Setup the database connection if necessary.
+ */
+const failable<bool> setup(const PGSql& pgsql) {
+ return pgsql.setup(false);
+}
+
+/**
+ * Post a new item to the database.
+ */
+const failable<bool> post(const value& key, const value& val, const PGSql& pgsql) {
+ debug(key, "pgsql::post::key");
+ debug(val, "pgsql::post::value");
+ debug(pgsql.conninfo, "pgsql::post::conninfo");
+ debug(pgsql.table, "pgsql::post::table");
+ setup(pgsql);
+
+ const string ks(scheme::writeValue(key));
+ const string vs(scheme::writeValue(val));
+ const char* params[2] = { c_str(ks), c_str(vs) };
+ PGresult* r = PQexecPrepared(pgsql.conn, "post", 2, params, NULL, NULL, 0);
+ if (PQresultStatus(r) != PGRES_COMMAND_OK)
+ return mkfailure<bool>(string("Could not execute insert postgresql SQL statement: ") + pgfailure(r, pgsql.conn));
+ PQclear(r);
+
+ debug(true, "pgsql::post::result");
+ return true;
+}
+
+/**
+ * Update an item in the database. If the item doesn't exist it is added.
+ */
+const failable<bool> put(const value& key, const value& val, const PGSql& pgsql) {
+ debug(key, "pgsql::put::key");
+ debug(val, "pgsql::put::value");
+ debug(pgsql.conninfo, "pgsql::put::conninfo");
+ debug(pgsql.table, "pgsql::put::table");
+ setup(pgsql);
+
+ const string ks(scheme::writeValue(key));
+ const string vs(scheme::writeValue(val));
+ const char* params[2] = { c_str(ks), c_str(vs) };
+ PGresult* r = PQexecPrepared(pgsql.conn, "put", 2, params, NULL, NULL, 0);
+ if (PQresultStatus(r) != PGRES_COMMAND_OK)
+ return mkfailure<bool>(string("Could not execute update postgresql SQL statement: ") + pgfailure(r, pgsql.conn));
+ const string t = PQcmdTuples(r);
+ if (t != "0") {
+ PQclear(r);
+ debug(true, "pgsql::put::result");
+ return true;
+ }
+ PQclear(r);
+
+ PGresult* pr = PQexecPrepared(pgsql.conn, "post", 2, params, NULL, NULL, 0);
+ if (PQresultStatus(pr) != PGRES_COMMAND_OK)
+ return mkfailure<bool>(string("Could not execute insert postgresql SQL statement: ") + pgfailure(pr, pgsql.conn));
+ PQclear(pr);
+
+ debug(true, "pgsql::put::result");
+ return true;
+}
+
+/**
+ * Get an item from the database.
+ */
+const failable<value> get(const value& key, const PGSql& pgsql) {
+ debug(key, "pgsql::get::key");
+ debug(pgsql.conninfo, "pgsql::get::conninfo");
+ debug(pgsql.table, "pgsql::get::table");
+ setup(pgsql);
+
+ const string ks(scheme::writeValue(key));
+ const char* params[1] = { c_str(ks) };
+ PGresult* r = PQexecPrepared(pgsql.conn, "get", 1, params, NULL, NULL, 0);
+ if (PQresultStatus(r) != PGRES_TUPLES_OK)
+ return mkfailure<value>(string("Could not execute select postgresql SQL statement: ") + pgfailure(r, pgsql.conn));
+ if (PQntuples(r) < 1) {
+ PQclear(r);
+ return mkfailure<value>(string("Could not get postgresql entry: ") + PQerrorMessage(pgsql.conn));
+ }
+ const char* data = PQgetvalue(r, 0, 1);
+ const value val(scheme::readValue(string(data)));
+ PQclear(r);
+
+ debug(val, "pgsql::get::result");
+ return val;
+}
+
+/**
+ * Delete an item from the database
+ */
+const failable<bool> del(const value& key, const PGSql& pgsql) {
+ debug(key, "pgsql::delete::key");
+ debug(pgsql.conninfo, "pgsql::delete::conninfo");
+ debug(pgsql.table, "pgsql::delete::table");
+ setup(pgsql);
+
+ const string ks(scheme::writeValue(key));
+ const char* params[1] = { c_str(ks) };
+ PGresult* r = PQexecPrepared(pgsql.conn, "delete", 1, params, NULL, NULL, 0);
+ if (PQresultStatus(r) != PGRES_COMMAND_OK)
+ return mkfailure<bool>(string("Could not execute delete postgresql SQL statement: ") + pgfailure(r, pgsql.conn));
+ PQclear(r);
+
+ debug(true, "pgsql::delete::result");
+ return true;
+}
+
+}
+}
+
+#endif /* tuscany_pgsql_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/server-test b/sandbox/sebastien/cpp/apr-2/components/sqldb/server-test
new file mode 100755
index 0000000000..c07d3b0510
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/server-test
@@ -0,0 +1,44 @@
+#!/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 localhost 8090 ../../modules/http/htdocs
+./pgsql-conf tmp
+./pgsql-start tmp
+./pgsql "drop table test;" 1>/dev/null 2>&1
+./pgsql "create table test(key text, value text);" 1>/dev/null 2>&1
+
+../../modules/server/server-conf tmp
+../../modules/server/scheme-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+SCAContribution `pwd`/
+SCAComposite sqldb.composite
+EOF
+
+../../modules/http/httpd-start tmp
+sleep 2
+
+# Test
+./client-test 2>/dev/null
+rc=$?
+
+# Cleanup
+../../modules/http/httpd-stop tmp
+./pgsql-stop tmp
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/sqldb-test b/sandbox/sebastien/cpp/apr-2/components/sqldb/sqldb-test
new file mode 100755
index 0000000000..e910ae0059
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/sqldb-test
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# Setup
+./pgsql-conf tmp
+./pgsql-start tmp
+./pgsql "drop table test;" 1>/dev/null 2>&1
+./pgsql "create table test(key text, value text);" 1>/dev/null 2>&1
+
+# Test
+./pgsql-test 2>/dev/null
+rc=$?
+
+# Cleanup
+./pgsql-stop tmp
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/sqldb.componentType b/sandbox/sebastien/cpp/apr-2/components/sqldb/sqldb.componentType
new file mode 100644
index 0000000000..5aa6d8e30f
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/sqldb.componentType
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<componentType xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/components">
+
+ <service name="sqldb"/>
+ <property name="conninfo" type="xsd:string">host=localhost port=5432 dbname=db</property>
+ <property name="table" type=xsd:string"/>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/sqldb.composite b/sandbox/sebastien/cpp/apr-2/components/sqldb/sqldb.composite
new file mode 100644
index 0000000000..1511e66024
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/sqldb.composite
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/components"
+ name="sqldb">
+
+ <component name="sqldb">
+ <implementation.cpp path="." library="libsqldb"/>
+ <property name="conninfo">host=localhost port=5432 dbname=db</property>
+ <property name="table">test</property>
+ <service name="sqldb">
+ <t:binding.http uri="sqldb"/>
+ </service>
+ </component>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/sqldb.cpp b/sandbox/sebastien/cpp/apr-2/components/sqldb/sqldb.cpp
new file mode 100644
index 0000000000..0524b00bd2
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/sqldb.cpp
@@ -0,0 +1,124 @@
+/*
+ * 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$ */
+
+/**
+ * PostgreSQL-based database component implementation.
+ */
+
+#include "string.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "pgsql.hpp"
+
+namespace tuscany {
+namespace sqldb {
+
+/**
+ * Get an item from the database.
+ */
+const failable<value> get(const list<value>& params, pgsql::PGSql& pg) {
+ return pgsql::get(car(params), pg);
+}
+
+/**
+ * Post an item to the database.
+ */
+const failable<value> post(const list<value>& params, pgsql::PGSql& pg) {
+ const value id = append<value>(car(params), mklist(mkuuid()));
+ const failable<bool> val = pgsql::post(id, cadr(params), pg);
+ if (!hasContent(val))
+ return mkfailure<value>(reason(val));
+ return id;
+}
+
+/**
+ * Put an item into the database.
+ */
+const failable<value> put(const list<value>& params, pgsql::PGSql& pg) {
+ const failable<bool> val = pgsql::put(car(params), cadr(params), pg);
+ if (!hasContent(val))
+ return mkfailure<value>(reason(val));
+ return value(content(val));
+}
+
+/**
+ * Delete an item from the database.
+ */
+const failable<value> del(const list<value>& params, pgsql::PGSql& pg) {
+ const failable<bool> val = pgsql::del(car(params), pg);
+ if (!hasContent(val))
+ return mkfailure<value>(reason(val));
+ return value(content(val));
+}
+
+/**
+ * Component implementation lambda function.
+ */
+class applySqldb {
+public:
+ applySqldb(pgsql::PGSql& pg) : pg(pg) {
+ }
+
+ const value operator()(const list<value>& params) const {
+ const value func(car(params));
+ if (func == "get")
+ return get(cdr(params), pg);
+ if (func == "post")
+ return post(cdr(params), pg);
+ if (func == "put")
+ return put(cdr(params), pg);
+ if (func == "delete")
+ return del(cdr(params), pg);
+ return tuscany::mkfailure<tuscany::value>();
+ }
+
+private:
+ pgsql::PGSql& pg;
+};
+
+/**
+ * Start the component.
+ */
+const failable<value> start(unused const list<value>& params) {
+ // Connect to the configured database and table
+ const value conninfo = ((lambda<value(list<value>)>)car(params))(list<value>());
+ const value table = ((lambda<value(list<value>)>)cadr(params))(list<value>());
+ pgsql::PGSql& pg = *(new (gc_new<pgsql::PGSql>()) pgsql::PGSql(conninfo, table));
+
+ // Return the component implementation lambda function
+ return value(lambda<value(const list<value>&)>(applySqldb(pg)));
+}
+
+}
+}
+
+extern "C" {
+
+const tuscany::value apply(const tuscany::list<tuscany::value>& params) {
+ const tuscany::value func(car(params));
+ if (func == "start")
+ return tuscany::sqldb::start(cdr(params));
+ return tuscany::mkfailure<tuscany::value>();
+}
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/sqldb/standby-test b/sandbox/sebastien/cpp/apr-2/components/sqldb/standby-test
new file mode 100755
index 0000000000..9e56bfc039
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/sqldb/standby-test
@@ -0,0 +1,39 @@
+#!/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/master localhost 8090 tmp/master/htdocs
+./pgsql-conf tmp/master 5432
+./pgsql-start tmp/master
+./pgsql localhost 5432 "drop table test;" 1>/dev/null 2>&1
+./pgsql localhost 5432 "create table test(key text, value text);" 1>/dev/null 2>&1
+../../modules/http/httpd-start tmp/master
+sleep 2
+./pgsql-standby-conf tmp/standby 5433 localhost 5432 8090
+./pgsql-start tmp/standby
+
+# Test
+./pgsql-standby-test 2>/dev/null
+rc=$?
+
+# Cleanup
+../../modules/http/httpd-stop tmp/master
+./pgsql-stop tmp/standby
+./pgsql-stop tmp/master
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/components/webservice/Makefile.am b/sandbox/sebastien/cpp/apr-2/components/webservice/Makefile.am
new file mode 100644
index 0000000000..19156e3fdd
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/webservice/Makefile.am
@@ -0,0 +1,71 @@
+# 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.
+
+if WANT_WEBSERVICE
+
+INCLUDES = -I${AXIS2C_INCLUDE}
+
+incl_HEADERS = *.hpp
+incldir = $(prefix)/include/components/webservice
+
+dist_comp_SCRIPTS = axis2-conf
+compdir=$(prefix)/components/webservice
+
+comp_DATA = axis2c.prefix axis2.xml services.xml module.xml
+
+EXTRA_DIST = webservice.composite webservice-client.componentType webservice-listener.componentType axis2.xml services.xml module.xml *.scm
+
+axis2c.prefix: $(top_builddir)/config.status
+ echo ${AXIS2C_PREFIX} >axis2c.prefix
+
+comp_LTLIBRARIES = libwebservice-client.la libwebservice-listener.la libaxis2-dispatcher.la libaxis2-service.la
+noinst_DATA = libwebservice-client.so libwebservice-listener.so libaxis2-dispatcher.so libaxis2-service.so
+
+libwebservice_client_la_SOURCES = webservice-client.cpp
+libwebservice_client_la_LDFLAGS = -lxml2 -L${AXIS2C_LIB} -R${AXIS2C_LIB} -laxis2_engine -laxis2_axiom -laxutil
+libwebservice-client.so:
+ ln -s .libs/libwebservice-client.so
+
+libwebservice_listener_la_SOURCES = webservice-listener.cpp
+libwebservice_listener_la_LDFLAGS = -lxml2 -L${AXIS2C_LIB} -R${AXIS2C_LIB} -laxis2_engine -laxis2_axiom -laxutil
+libwebservice-listener.so:
+ ln -s .libs/libwebservice-listener.so
+
+libaxis2_dispatcher_la_SOURCES = axis2-dispatcher.cpp
+libaxis2_dispatcher_la_LDFLAGS = -lxml2 -L${AXIS2C_LIB} -R${AXIS2C_LIB} -laxis2_engine -laxis2_axiom -laxutil
+libaxis2-dispatcher.so:
+ ln -s .libs/libaxis2-dispatcher.so
+
+libaxis2_service_la_SOURCES = axis2-service.cpp
+libaxis2_service_la_LDFLAGS = -lxml2 -L${AXIS2C_LIB} -R${AXIS2C_LIB} -laxis2_engine -laxis2_axiom -laxutil
+libaxis2-service.so:
+ ln -s .libs/libaxis2-service.so
+
+axiom_test_SOURCES = axiom-test.cpp
+axiom_test_LDFLAGS = -lxml2 -L${AXIS2C_LIB} -R${AXIS2C_LIB} -laxis2_engine -laxis2_axiom -laxutil
+
+axis2_test_SOURCES = axis2-test.cpp
+axis2_test_LDFLAGS = -lxml2 -L${AXIS2C_LIB} -R${AXIS2C_LIB} -laxis2_engine -laxis2_axiom -laxutil
+
+client_test_SOURCES = client-test.cpp
+client_test_LDFLAGS = -lxml2 -lcurl -lmozjs -L${AXIS2C_LIB} -R${AXIS2C_LIB} -laxis2_engine -laxis2_axiom -laxutil
+
+dist_noinst_SCRIPTS = echo-test server-test
+noinst_PROGRAMS = axiom-test axis2-test client-test
+TESTS = axiom-test echo-test server-test
+
+endif
diff --git a/sandbox/sebastien/cpp/apr-2/components/webservice/axiom-test.cpp b/sandbox/sebastien/cpp/apr-2/components/webservice/axiom-test.cpp
new file mode 100644
index 0000000000..a3ab8e7e8f
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/webservice/axiom-test.cpp
@@ -0,0 +1,85 @@
+/*
+ * 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 Web service Axiom support functions.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "list.hpp"
+#include "element.hpp"
+#include "monad.hpp"
+#include "value.hpp"
+#include "perf.hpp"
+#include "axis2.hpp"
+
+namespace tuscany {
+namespace webservice {
+
+const string customerElement =
+"<customer>"
+"<name>jdoe</name>"
+"<address><city>san francisco</city><state>ca</state></address>"
+"<account><id>1234</id><balance>1000</balance></account>"
+"<account><id>6789</id><balance>2000</balance></account>"
+"<account><id>4567</id><balance>3000</balance></account>"
+"</customer>";
+
+bool testAxiom() {
+ const Axis2Context ax;
+ {
+ const failable<axiom_node_t*> n = stringToAxiomNode(customerElement, ax);
+ assert(hasContent(n));
+ const failable<const string> c = axiomNodeToString(content(n), ax);
+ assert(hasContent(c));
+ assert(content(c) == customerElement);
+ }
+ {
+ const list<value> arg = mklist<value>(
+ list<value>() + "ns1:echoString"
+ + (list<value>() + "@xmlns:ns1" + string("http://ws.apache.org/axis2/services/echo"))
+ + (list<value>() + "text" + string("Hello World!")));
+ const failable<axiom_node_t*> n = valuesToAxiomNode(arg, ax);
+ assert(hasContent(n));
+ const failable<const string> x = axiomNodeToString(content(n), ax);
+ assert(hasContent(x));
+ assert(content(x) == "<ns1:echoString xmlns:ns1=\"http://ws.apache.org/axis2/services/echo\"><text>Hello World!</text></ns1:echoString>");
+ const failable<const list<value> > l = axiomNodeToValues(content(n), ax);
+ assert(hasContent(l));
+ assert(l == arg);
+ }
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::webservice::testAxiom();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/webservice/axis2-conf b/sandbox/sebastien/cpp/apr-2/components/webservice/axis2-conf
new file mode 100755
index 0000000000..af5d189b24
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/webservice/axis2-conf
@@ -0,0 +1,64 @@
+#!/bin/sh
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# Generate an Axis2 server conf
+here=`readlink -f $0`; here=`dirname $here`
+mkdir -p $1
+root=`readlink -f $1`
+axis2_prefix=`cat axis2c.prefix`
+
+# Create an Axis2 home directory
+mkdir -p $root/axis2c
+ln -f -s $axis2_prefix/lib $root/axis2c/lib
+mkdir -p $root/axis2c/logs
+mkdir -p $root/axis2c/modules
+ln -f -s $axis2_prefix/modules/addressing $root/axis2c/modules/addressing
+ln -f -s $axis2_prefix/modules/logging $root/axis2c/modules/logging
+mkdir -p $root/axis2c/services
+
+# Install Tuscany Axis2 module and service
+mkdir -p $root/axis2c/modules/tuscany
+ln -f -s $here/libaxis2-dispatcher.so $root/axis2c/modules/tuscany/libaxis2-dispatcher.so
+ln -f -s $here/module.xml $root/axis2c/modules/tuscany/module.xml
+mkdir -p $root/axis2c/services/tuscany
+ln -f -s $here/libaxis2-service.so $root/axis2c/services/tuscany/libaxis2-service.so
+ln -f -s $here/services.xml $root/axis2c/services/tuscany/services.xml
+cp $here/axis2.xml $root/axis2c/axis2.xml
+
+# Configure HTTPD Axis2 module
+cat >>$root/conf/modules.conf <<EOF
+# Generated by: axis2-conf $*
+# Support for Web Services
+LoadModule axis2_module $root/axis2c/lib/libmod_axis2.so
+
+EOF
+
+cat >>$root/conf/httpd.conf <<EOF
+# Generated by: axis2-conf $*
+# Support for Web Services
+SCASetEnv AXIS2C_HOME $root/axis2c
+Axis2RepoPath $root/axis2c
+Axis2LogFile $root/axis2c/logs/mod_axis2.log
+Axis2LogLevel debug
+<Location /axis2>
+ SetHandler axis2_module
+</Location>
+
+EOF
+
diff --git a/sandbox/sebastien/cpp/apr-2/components/webservice/axis2-dispatcher.cpp b/sandbox/sebastien/cpp/apr-2/components/webservice/axis2-dispatcher.cpp
new file mode 100644
index 0000000000..3f753e0e35
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/webservice/axis2-dispatcher.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$ */
+
+/**
+ * Axis2/C module that dispatches all server requests to the Tuscany Axis/2C service.
+ */
+
+#include "axis2.hpp"
+
+namespace tuscany {
+namespace webservice {
+
+/**
+ * Determine the service and operation to dispatch a request to.
+ */
+axis2_svc_t* AXIS2_CALL dispatchFindService(axis2_msg_ctx_t* msg_ctx, const axutil_env_t* env) {
+ const axis2_conf_ctx_t* conf_ctx = axis2_msg_ctx_get_conf_ctx(msg_ctx, env);
+ const axis2_conf_t* conf = axis2_conf_ctx_get_conf(conf_ctx, env);
+ axis2_svc_t* svc = axis2_conf_get_svc(conf, env, "TuscanyService");
+ return svc;
+}
+
+axis2_op_t *AXIS2_CALL dispatchFindOp(unused axis2_msg_ctx_t* msg_ctx, const axutil_env_t* env, axis2_svc_t* svc) {
+ axutil_qname_t* op_qname = axutil_qname_create(env, "execute", NULL, NULL);
+ axis2_op_t *op = axis2_svc_get_op_with_name(svc, env, axutil_qname_get_localpart(op_qname, env));
+ axutil_qname_free(op_qname, env);
+ return op;
+}
+
+/**
+ * Dispatcher invoke function, called by Axis2/C.
+ */
+axis2_status_t AXIS2_CALL dispatchInvoke( struct axis2_handler* handler, const axutil_env_t* env, axis2_msg_ctx_t* msg_ctx) {
+ if (!(axis2_msg_ctx_get_server_side(msg_ctx, env)))
+ return AXIS2_SUCCESS;
+ axis2_msg_ctx_set_find_svc(msg_ctx, env, dispatchFindService);
+ axis2_msg_ctx_set_find_op(msg_ctx, env, dispatchFindOp);
+ return axis2_disp_find_svc_and_op(handler, env, msg_ctx);
+}
+
+/**
+ * Create a dispatch handler.
+ */
+AXIS2_EXPORT axis2_handler_t* AXIS2_CALL dispatchHandler(const axutil_env_t* env, unused axutil_string_t* name) {
+ axis2_handler_t *handler = axis2_handler_create(env);
+ if (handler == NULL)
+ return NULL;
+ axis2_handler_set_invoke(handler, env, dispatchInvoke);
+ return handler;
+}
+
+/**
+ * Initialize dispatch module.
+ */
+axis2_status_t AXIS2_CALL dispatchInit(unused axis2_module_t * module, unused const axutil_env_t * env, unused axis2_conf_ctx_t * conf_ctx, unused axis2_module_desc_t * module_desc) {
+ return AXIS2_SUCCESS;
+}
+
+/**
+ * Initialize dispatch module function map.
+ */
+axis2_status_t AXIS2_CALL dispatchFuncMap(axis2_module_t * module, const axutil_env_t * env) {
+ module->handler_create_func_map = axutil_hash_make(env);
+ axutil_hash_set(module->handler_create_func_map, "TuscanyDispatcher", AXIS2_HASH_KEY_STRING, (const void *)dispatchHandler);
+ return AXIS2_SUCCESS;
+}
+
+/**
+ * Shutdown dispatch module.
+ */
+axis2_status_t AXIS2_CALL dispatchShutdown(axis2_module_t* module, const axutil_env_t* env) {
+ if (module->handler_create_func_map != NULL) {
+ axutil_hash_free(module->handler_create_func_map, env);
+ module->handler_create_func_map = NULL;
+ }
+ AXIS2_FREE(env->allocator, module);
+ return AXIS2_SUCCESS;
+}
+
+/**
+ * Return a new dispatch module.
+ */
+const axis2_module_ops_t dispatchOps = {
+ dispatchInit,
+ dispatchShutdown,
+ dispatchFuncMap
+};
+
+axis2_module_t * dispatchModule(const axutil_env_t* env) {
+ axis2_module_t *module = (axis2_module_t*)AXIS2_MALLOC(env->allocator, sizeof(axis2_module_t));
+ if (module == NULL)
+ return NULL;
+ module->ops = &dispatchOps;
+ module->handler_create_func_map = NULL;
+ return module;
+}
+
+}
+}
+
+extern "C"
+{
+
+/**
+ * Axis2/C module entry point functions.
+ */
+AXIS2_EXPORT int axis2_get_instance(axis2_module_t** inst, const axutil_env_t* env) {
+ *inst = tuscany::webservice::dispatchModule(env);
+ if(*inst == NULL)
+ return AXIS2_FAILURE;
+ return AXIS2_SUCCESS;
+}
+
+AXIS2_EXPORT int axis2_remove_instance(axis2_module_t* inst, const axutil_env_t* env) {
+ if (inst != NULL)
+ return tuscany::webservice::dispatchShutdown(inst, env);
+ return AXIS2_FAILURE;
+}
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/webservice/axis2-service.cpp b/sandbox/sebastien/cpp/apr-2/components/webservice/axis2-service.cpp
new file mode 100644
index 0000000000..4c0ce22722
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/webservice/axis2-service.cpp
@@ -0,0 +1,151 @@
+/*
+ * 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$ */
+
+/**
+ * Axis2/C service implementation that dispatches requests to SCA Web service components.
+ */
+
+#include "value.hpp"
+#include "string.hpp"
+#include "../../modules/http/httpd.hpp"
+#include "axis2.hpp"
+
+namespace tuscany {
+namespace webservice {
+
+/**
+ * Initialize the service.
+ */
+int AXIS2_CALL serviceInit(unused axis2_svc_skeleton_t* svc_skeleton, unused const axutil_env_t* env) {
+ return AXIS2_SUCCESS;
+}
+
+/**
+ * Free the service.
+ */
+int AXIS2_CALL serviceFree(axis2_svc_skeleton_t* svc_skeleton, const axutil_env_t* env) {
+ if (svc_skeleton)
+ AXIS2_FREE(env->allocator, svc_skeleton);
+ return AXIS2_SUCCESS;
+}
+
+typedef struct axis2_apache2_out_transport_info {
+ axis2_http_out_transport_info_t out_transport_info;
+ request_rec *request;
+ axis2_char_t *encoding;
+} axis2_apache2_out_transport_info_t;
+
+extern "C" {
+ extern module axis2_module;
+}
+
+/**
+ * Service invoke function, called by Axis2/C.
+ */
+axiom_node_t *AXIS2_CALL serviceInvoke(unused axis2_svc_skeleton_t* svc_skeleton, const axutil_env_t* env, axiom_node_t* node, axis2_msg_ctx_t* msg_ctx) {
+
+ // Check that we have an input node
+ if (node == NULL || axiom_node_get_node_type(node, env) != AXIOM_ELEMENT)
+ return NULL;
+ axiom_element_t *e = (axiom_element_t *) axiom_node_get_data_element(node, env);
+ if (e == NULL)
+ return NULL;
+
+ // Get the function name
+ const char* func = axiom_element_get_localname(e, env);
+ if (func == NULL)
+ return NULL;
+
+ // Get the target endpoint address
+ const axis2_endpoint_ref_t* epr = axis2_msg_ctx_get_from(msg_ctx, env);
+ if (epr == NULL)
+ return NULL;
+ string address = axis2_endpoint_ref_get_address(epr, env);
+
+ // Get the underlying HTTPD request
+ axis2_out_transport_info_t* tinfo = axis2_msg_ctx_get_out_transport_info(msg_ctx, env);
+ axis2_apache2_out_transport_info_t* httpinfo = (axis2_apache2_out_transport_info_t*)tinfo;
+ request_rec* r = httpinfo->request;
+ httpdDebugRequest(r, "webservice::serviceInvoke");
+
+ // Parse the request Axiom node and construct request expression
+ Axis2Context ax(env);
+ const failable<const list<value> > lv = axiomNodeToValues(node, ax);
+ if (!hasContent(lv))
+ return NULL;
+ const value expr = mklist<value>(func, content(lv));
+ debug(expr, "webservice::serviceInvoke::expr");
+
+ // Retrieve the target lambda function from the HTTPD request and invoke it
+ const value* rv = const_cast<const value*>((value*)ap_get_module_config(r->request_config, &axis2_module));
+ cout << "relay: " << rv << endl;
+ const lambda<value(const list<value>&)> relay = *rv;
+ const value res = relay(expr);
+ debug(res, "webservice::serviceInvoke::result");
+
+ // Construct response Axiom node
+ const failable<axiom_node_t*> rnode = valuesToAxiomNode(res, ax);
+ if (!hasContent(rnode))
+ return NULL;
+ return content(rnode);
+}
+
+/**
+ * Return a new service skeleton.
+ */
+const axis2_svc_skeleton_ops_t serviceOps = {
+ serviceInit,
+ serviceInvoke,
+ NULL,
+ serviceFree,
+ NULL
+};
+
+AXIS2_EXTERN axis2_svc_skeleton_t *AXIS2_CALL serviceSkeleton(const axutil_env_t* env) {
+ axis2_svc_skeleton_t* svc_skeleton = (axis2_svc_skeleton_t*)AXIS2_MALLOC(env->allocator, sizeof(axis2_svc_skeleton_t));
+ svc_skeleton->ops = &serviceOps;
+ svc_skeleton->func_array = NULL;
+ return svc_skeleton;
+}
+
+}
+}
+
+extern "C"
+{
+
+/**
+ * Axis2/C service entry point functions.
+ */
+AXIS2_EXPORT int axis2_get_instance(struct axis2_svc_skeleton** inst, const axutil_env_t* env) {
+ *inst = tuscany::webservice::serviceSkeleton(env);
+ if (inst == NULL)
+ return AXIS2_FAILURE;
+ return AXIS2_SUCCESS;
+}
+
+AXIS2_EXPORT int axis2_remove_instance(axis2_svc_skeleton_t* inst, const axutil_env_t* env) {
+ if (inst != NULL)
+ return AXIS2_SVC_SKELETON_FREE(inst, env);
+ return AXIS2_FAILURE;
+}
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/webservice/axis2-test.cpp b/sandbox/sebastien/cpp/apr-2/components/webservice/axis2-test.cpp
new file mode 100644
index 0000000000..d7c2f3b671
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/webservice/axis2-test.cpp
@@ -0,0 +1,71 @@
+/*
+ * 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 WebService Axis2 client support functions.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "list.hpp"
+#include "element.hpp"
+#include "monad.hpp"
+#include "value.hpp"
+#include "perf.hpp"
+#include "axis2.hpp"
+
+namespace tuscany {
+namespace webservice {
+
+bool testEval() {
+ const Axis2Context ax;
+
+ const value func = "http://ws.apache.org/axis2/c/samples/echoString";
+ const list<value> arg = mklist<value>(
+ list<value>() + "ns1:echoString"
+ + (list<value>() + "@xmlns:ns1" + string("http://ws.apache.org/axis2/services/echo"))
+ + (list<value>() + "text" + string("Hello World!")));
+
+ const failable<value> rval = evalExpr(mklist<value>(func, arg, string("http://localhost:9090/axis2/services/echo")), ax);
+ assert(hasContent(rval));
+
+ const list<value> r = mklist<value>(
+ list<value>() + "ns1:echoString"
+ + (list<value>() + "@xmlns:ns1" + string("http://ws.apache.org/axis2/c/samples"))
+ + (list<value>() + "text" + string("Hello World!")));
+ assert(content(rval) == r);
+
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::webservice::testEval();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/webservice/axis2.hpp b/sandbox/sebastien/cpp/apr-2/components/webservice/axis2.hpp
new file mode 100644
index 0000000000..c2886edb71
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/webservice/axis2.hpp
@@ -0,0 +1,194 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_webservice_hpp
+#define tuscany_webservice_hpp
+
+/**
+ * Web service invocation functions using Axis2.
+ */
+#include "config.hpp"
+
+// Ignore redundant declarations in Axiom headers
+#ifdef WANT_MAINTAINER_MODE
+#pragma GCC diagnostic ignored "-Wredundant-decls"
+#endif
+#include <axiom.h>
+#include <axis2_client.h>
+#include <axis2_module.h>
+#include <axis2_addr_mod.h>
+#include <axis2_conf_ctx.h>
+#include <axis2_disp.h>
+#include <axis2_http_out_transport_info.h>
+#ifdef WANT_MAINTAINER_MODE
+#pragma GCC diagnostic warning "-Wredundant-decls"
+#endif
+
+#include "string.hpp"
+#include "sstream.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "xml.hpp"
+#include "monad.hpp"
+
+namespace tuscany {
+namespace webservice {
+
+/**
+ * Represents an Axis2 runtime context.
+ */
+class Axis2Context {
+public:
+ Axis2Context() : env(axutil_env_create_all("axis2.log", AXIS2_LOG_LEVEL_WARNING)), owner(true) {
+ }
+
+ Axis2Context(const Axis2Context& ax) : env(ax.env), owner(false) {
+ }
+
+ Axis2Context(const axutil_env_t* env) : env(const_cast<axutil_env_t*>(env)), owner(false) {
+ }
+
+ ~Axis2Context() {
+ if (!owner || env == NULL)
+ return;
+ axutil_env_free(env);
+ }
+
+private:
+ axutil_env_t* env;
+ bool owner;
+
+ friend const axutil_env_t* env(const Axis2Context& ax);
+};
+
+const axutil_env_t* env(const Axis2Context& ax) {
+ return ax.env;
+}
+
+/**
+ * Return the latest Axis2 error in an Axis2 context.
+ */
+const string axis2Error(const Axis2Context& ax) {
+ ostringstream os;
+ os << env(ax)->error->error_number << " : " << AXIS2_ERROR_GET_MESSAGE(env(ax)->error);
+ return str(os);
+}
+
+/**
+ * Convert a string to an Axiom node.
+ */
+const failable<axiom_node_t*> stringToAxiomNode(const string& s, const Axis2Context& ax) {
+ axiom_node_t* node = axiom_node_create_from_buffer(env(ax), const_cast<axis2_char_t*>(c_str(s)));
+ if (node == NULL)
+ return mkfailure<axiom_node_t*>(string("Couldn't convert XML to Axiom node: ") + axis2Error(ax));
+ return node;
+}
+
+/**
+ * Convert a list of values representing XML elements to an Axiom node.
+ */
+const failable<axiom_node_t*> valuesToAxiomNode(const list<value>& l, const Axis2Context& ax) {
+ const failable<list<string> > xml = writeXML(valuesToElements(l), false);
+ if (!hasContent(xml))
+ return mkfailure<axiom_node_t*>(reason(xml));
+ ostringstream os;
+ write(content(xml), os);
+ return stringToAxiomNode(str(os), ax);
+}
+
+/**
+ * Convert an axiom node to a string.
+ */
+const failable<const string> axiomNodeToString(axiom_node_t* node, const Axis2Context& ax) {
+ const char* c = axiom_node_to_string(node, env(ax));
+ if (c == NULL)
+ return mkfailure<const string>(string("Couldn't convert Axiom node to XML: ") + axis2Error(ax));
+ const string s(c);
+ AXIS2_FREE(env(ax)->allocator, const_cast<char*>(c));
+ return s;
+}
+
+/**
+ * Convert an axiom node to a list of values representing XML elements.
+ */
+const failable<const list<value> > axiomNodeToValues(axiom_node_t* node, const Axis2Context& ax) {
+ const failable<const string> s = axiomNodeToString(node, ax);
+ if (!hasContent(s))
+ return mkfailure<const list<value> >(reason(s));
+ istringstream is(content(s));
+ const failable<const list<value> > l = readXML(streamList(is));
+ if (!hasContent(l))
+ return l;
+ return elementsToValues(content(l));
+}
+
+/**
+ * Evaluate an expression in the form (soap-action-string, document, uri). Send the
+ * SOAP action and document to the Web Service at the given URI using Axis2.
+ */
+const failable<value> evalExpr(const value& expr, const Axis2Context& ax) {
+ debug(expr, "webservice::evalExpr::input");
+
+ // Extract func name and single argument
+ const value func(car<value>(expr));
+ const list<value> param(cadr<value>(expr));
+ const value uri(caddr<value>(expr));
+
+ // Create Axis2 client
+ axis2_svc_client_t *client = axis2_svc_client_create(env(ax), getenv("AXIS2C_HOME"));
+ if (client == NULL)
+ return mkfailure<value>("Couldn't create Axis2 client: " + axis2Error(ax));
+ axis2_endpoint_ref_t *epr = axis2_endpoint_ref_create(env(ax), c_str(uri));
+ axis2_options_t *opt = axis2_options_create(env(ax));
+ axis2_options_set_to(opt, env(ax), epr);
+ axis2_options_set_action(opt, env(ax), (const axis2_char_t*)c_str(func));
+ axis2_svc_client_set_options(client, env(ax), opt);
+ axis2_svc_client_engage_module(client, env(ax), AXIS2_MODULE_ADDRESSING);
+
+ // Construct request Axiom node
+ const failable<axiom_node_t*> req = valuesToAxiomNode(param, ax);
+ if (!hasContent(req))
+ return mkfailure<value>(reason(req));
+
+ // Call the Web service
+ axiom_node_t* res = axis2_svc_client_send_receive(client, env(ax), content(req));
+ if (res == NULL) {
+ axis2_svc_client_free(client, env(ax));
+ return mkfailure<value>("Couldn't invoke Axis2 service: " + axis2Error(ax));
+ }
+
+ // Parse result Axiom node
+ const failable<const list<value> > lval = axiomNodeToValues(res, ax);
+ if (!hasContent(lval))
+ return mkfailure<value>(reason(lval));
+ const value rval = content(lval);
+ debug(rval, "webservice::evalExpr::result");
+
+ // Cleanup
+ axis2_svc_client_free(client, env(ax));
+
+ return rval;
+}
+
+}
+}
+
+#endif /* tuscany_webservice_hpp */
diff --git a/sandbox/sebastien/cpp/apr-2/components/webservice/axis2.xml b/sandbox/sebastien/cpp/apr-2/components/webservice/axis2.xml
new file mode 100644
index 0000000000..ea9b6d2194
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/webservice/axis2.xml
@@ -0,0 +1,148 @@
+<!--
+ 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.
+-->
+<axisconfig name="Axis2/C">
+ <!-- ================================================= -->
+ <!-- Parameters -->
+ <!-- ================================================= -->
+ <!-- Uncomment following to enable MTOM support globally -->
+ <!--parameter name="enableMTOM" locked="false">true</parameter-->
+
+ <!-- Set the suitable size for optimum memory usage when sending large attachments -->
+ <!--parameter name="MTOMBufferSize" locked="false">10</parameter-->
+ <!--parameter name="MTOMMaxBuffers" locked="false">1000</parameter-->
+ <!--parameter name="EnableMTOMServiceCallback" locked="false">true</parameter-->
+ <!--parameter name="attachmentDIR" locked="false">/path/to/the/attachment/caching/dir/</parameter-->
+ <!--parameter name="MTOMCachingCallback" locked="false">/path/to/the/caching_callback</parameter-->
+ <!--parameter name="MTOMSendingCallback" locked="false">/path/to/the/sending_callback</parameter-->
+
+ <!-- Enable REST -->
+ <parameter name="enableREST" locked="false">true</parameter>
+
+ <!-- Uncomment following to persist op_ctx, useful with RM -->
+ <!--parameter name="persistOperationContext" locked="false">true</parameter-->
+
+ <!--if you want to extract the service archive file and work with that please uncomment this-->
+ <!--else , it wont extract archive file or does not take into consideration if someone drop-->
+ <!--exploded directory into /service directory-->
+ <!--<parameter name="extractServiceArchive" locked="false">true</parameter>-->
+
+
+ <!-- ================================================= -->
+ <!-- Message Receivers -->
+ <!-- ================================================= -->
+ <!-- This is the Deafult Message Receiver for the Request Response style Operations -->
+ <!--messageReceiver mep="INOUT" class="axis2_receivers"/-->
+
+
+ <!-- ================================================= -->
+ <!-- Transport Ins -->
+ <!-- ================================================= -->
+
+ <transportReceiver name="http" class="axis2_http_receiver">
+ <parameter name="port" locked="false">6060</parameter>
+ <parameter name="exposeHeaders" locked="true">false</parameter>
+ </transportReceiver>
+
+ <!--transportReceiver name="https" class="axis2_http_receiver">
+ <parameter name="port" locked="false">6060</parameter>
+ <parameter name="exposeHeaders" locked="true">false</parameter>
+ </transportReceiver-->
+
+ <!--transportReceiver name="tcp" class="axis2_tcp_receiver">
+ <parameter name="port" locked="false">6060</parameter>
+ </transportReceiver-->
+
+
+ <!-- ================================================= -->
+ <!-- Transport Outs -->
+ <!-- ================================================= -->
+
+ <transportSender name="http" class="axis2_http_sender">
+ <parameter name="PROTOCOL" locked="false">HTTP/1.1</parameter>
+ <parameter name="xml-declaration" insert="false"/>
+ <!--parameter name="Transfer-Encoding">chunked</parameter-->
+ <!--parameter name="HTTP-Authentication" username="" password="" locked="true"/-->
+ <!--parameter name="PROXY" proxy_host="127.0.0.1" proxy_port="8080" proxy_username="" proxy_password="" locked="true"/-->
+ </transportSender>
+
+ <!-- Uncomment the following with appropriate parameters to enable the SSL transport sender.
+ Also make sure that the appropriate transport receiver is enabled above.-->
+ <!--transportSender name="https" class="axis2_http_sender">
+ <parameter name="PROTOCOL" locked="false">HTTP/1.1</parameter>
+ <parameter name="xml-declaration" insert="false"/>
+ </transportSender>
+ <parameter name="SERVER_CERT">/path/to/ca/certificate</parameter>
+ <parameter name="KEY_FILE">/path/to/client/certificate/chain/file</parameter>
+ <parameter name="SSL_PASSPHRASE">passphrase</parameter>
+ -->
+
+ <!-- Uncomment this one with the appropriate papameters to enable the TCP transport Sender-->
+ <!--transportSender name="tcp" class="axis2_tcp_sender">
+ <parameter name="PROTOCOL" locked="false">TCP</parameter>
+ <parameter name="xml-declaration" insert="false"/>
+ </transportSender-->
+
+
+ <!-- ================================================= -->
+ <!-- Global Modules -->
+ <!-- ================================================= -->
+ <!-- Comment this to disable Addressing -->
+ <module ref="addressing"/>
+
+ <!-- Tuscany dispatcher module -->
+ <module ref="tuscany"/>
+
+ <!--Configuring module , providing paramters for modules whether they refer or not-->
+ <!--<moduleConfig name="addressing">-->
+ <!--<parameter name="addressingPara" locked="false">N/A</parameter>-->
+ <!--</moduleConfig>-->
+
+ <!-- ================================================= -->
+ <!-- Phases -->
+ <!-- ================================================= -->
+ <phaseOrder type="inflow">
+ <!-- System pre defined phases -->
+ <phase name="Transport"/>
+ <phase name="PreDispatch"/>
+ <phase name="Dispatch"/>
+ <phase name="PostDispatch"/>
+ <!--phase name="Security"/-->
+ <!-- End system pre defined phases -->
+ <!-- After PostDispatch phase, module or service author can add any phase as required -->
+ <!-- User defined phases could be added here -->
+ <!--phase name="userphase1"/-->
+ </phaseOrder>
+ <phaseOrder type="outflow">
+ <!-- User defined phases could be added here -->
+ <!--phase name="userphase1"/-->
+ <!--system predefined phase-->
+ <phase name="MessageOut"/>
+ <!--phase name="Security"/-->
+ </phaseOrder>
+ <phaseOrder type="INfaultflow">
+ <!-- User defined phases could be added here -->
+ <!--phase name="userphase1"/-->
+ </phaseOrder>
+ <phaseOrder type="Outfaultflow">
+ <!-- User defined phases could be added here -->
+ <!--phase name="userphase1"/-->
+ <phase name="MessageOut"/>
+ </phaseOrder>
+</axisconfig>
+
diff --git a/sandbox/sebastien/cpp/apr-2/components/webservice/client-test.cpp b/sandbox/sebastien/cpp/apr-2/components/webservice/client-test.cpp
new file mode 100644
index 0000000000..658c87e2fc
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/webservice/client-test.cpp
@@ -0,0 +1,94 @@
+/*
+ * 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 Web service component.
+ */
+
+#include <assert.h>
+#include "stream.hpp"
+#include "string.hpp"
+#include "list.hpp"
+#include "element.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "perf.hpp"
+#include "../../modules/http/http.hpp"
+#include "axis2.hpp"
+
+namespace tuscany {
+namespace webservice {
+
+
+bool testModAxis2() {
+ const Axis2Context ax;
+
+ const value func = "http://ws.apache.org/axis2/c/samples/echoString";
+ const list<value> arg = mklist<value>(
+ list<value>() + "ns1:echoString"
+ + (list<value>() + "@xmlns:ns1" + string("http://ws.apache.org/axis2/services/echo"))
+ + (list<value>() + "text" + string("Hello World!")));
+
+ const failable<value> rval = evalExpr(mklist<value>(func, arg, string("http://localhost:8090/echo-listener")), ax);
+ assert(hasContent(rval));
+
+ const list<value> r = mklist<value>(
+ list<value>() + "ns1:echoString"
+ + (list<value>() + "@xmlns:ns1" + string("http://ws.apache.org/axis2/services/echo"))
+ + (list<value>() + "text" + string("Hello World!")));
+ assert(content(rval) == r);
+
+ return true;
+}
+
+bool testEval() {
+ http::CURLSession cs("", "", "");
+
+ const value func = "http://ws.apache.org/axis2/c/samples/echoString";
+ const list<value> arg = mklist<value>(
+ list<value>() + "ns1:echoString"
+ + (list<value>() + "@xmlns:ns1" + string("http://ws.apache.org/axis2/services/echo"))
+ + (list<value>() + "text" + string("Hello World!")));
+
+ const failable<value> rval = http::evalExpr(mklist<value>(func, arg), "http://localhost:8090/echo-client", cs);
+ assert(hasContent(rval));
+
+ const list<value> r = mklist<value>(
+ list<value>() + "ns1:echoString"
+ + (list<value>() + "@xmlns:ns1" + string("http://ws.apache.org/axis2/c/samples"))
+ + (list<value>() + "text" + string("Hello World!")));
+ assert(content(rval) == r);
+ return true;
+}
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::webservice::testModAxis2();
+ tuscany::webservice::testEval();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/webservice/echo-test b/sandbox/sebastien/cpp/apr-2/components/webservice/echo-test
new file mode 100755
index 0000000000..e5cd1d9a9d
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/webservice/echo-test
@@ -0,0 +1,37 @@
+#!/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
+axis2_prefix=`cat axis2c.prefix`
+export AXIS2C_HOME=$axis2_prefix
+axis2="$axis2_prefix/bin/axis2_http_server"
+pwd=`pwd`
+cd "$axis2_prefix/bin"
+$axis2 &
+cd $pwd
+sleep 1
+
+# Test
+./axis2-test 2>/dev/null
+rc=$?
+
+# Cleanup
+kill `ps -f | grep -v grep | grep "$axis2" | awk '{ print $2 }'`
+sleep 1
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/components/webservice/module.xml b/sandbox/sebastien/cpp/apr-2/components/webservice/module.xml
new file mode 100644
index 0000000000..8f6ba5018f
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/webservice/module.xml
@@ -0,0 +1,25 @@
+<!--
+ 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.
+-->
+<module name="tuscany" class="axis2-dispatcher">
+ <inflow>
+ <handler name="TuscanyDispatcher" class="axis2-dispatcher">
+ <order phase="Dispatch"/>
+ </handler>
+ </inflow>
+</module>
diff --git a/sandbox/sebastien/cpp/apr-2/components/webservice/server-test b/sandbox/sebastien/cpp/apr-2/components/webservice/server-test
new file mode 100755
index 0000000000..34fdb7266a
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/webservice/server-test
@@ -0,0 +1,49 @@
+#!/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 localhost 8090 ../../modules/http/htdocs
+../../modules/server/server-conf tmp
+../../modules/server/scheme-conf tmp
+./axis2-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+SCAContribution `pwd`/
+SCAComposite webservice.composite
+EOF
+
+../../modules/http/httpd-start tmp
+
+axis2_prefix=`cat axis2c.prefix`
+export AXIS2C_HOME=$axis2_prefix
+axis2="$axis2_prefix/bin/axis2_http_server"
+pwd=`pwd`
+cd "$axis2_prefix/bin"
+$axis2 &
+cd $pwd
+sleep 2
+
+# Test
+./client-test 2>/dev/null
+rc=$?
+
+# Cleanup
+kill `ps -f | grep -v grep | grep "${axis2}" | awk '{ print $2 }'`
+../../modules/http/httpd-stop tmp
+sleep 2
+return $rc
diff --git a/sandbox/sebastien/cpp/apr-2/components/webservice/server-test.scm b/sandbox/sebastien/cpp/apr-2/components/webservice/server-test.scm
new file mode 100644
index 0000000000..44e4eee92a
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/webservice/server-test.scm
@@ -0,0 +1,21 @@
+; Licensed to the Apache Software Foundation (ASF) under one
+; or more contributor license agreements. See the NOTICE file
+; distributed with this work for additional information
+; regarding copyright ownership. The ASF licenses this file
+; to you under the Apache License, Version 2.0 (the
+; "License"); you may not use this file except in compliance
+; with the License. You may obtain a copy of the License at
+;
+; http://www.apache.org/licenses/LICENSE-2.0
+;
+; Unless required by applicable law or agreed to in writing,
+; software distributed under the License is distributed on an
+; "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+; KIND, either express or implied. See the License for the
+; specific language governing permissions and limitations
+; under the License.
+
+; Web service test case
+
+(define (echoString x) x)
+
diff --git a/sandbox/sebastien/cpp/apr-2/components/webservice/services.xml b/sandbox/sebastien/cpp/apr-2/components/webservice/services.xml
new file mode 100644
index 0000000000..0adf136f4f
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/webservice/services.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ 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.
+-->
+<serviceGroup>
+<service name="TuscanyService">
+ <parameter name="ServiceClass" locked="xsd:false">axis2-service</parameter>
+ <operation name="execute"/>
+</service>
+</serviceGroup>
diff --git a/sandbox/sebastien/cpp/apr-2/components/webservice/webservice-client.componentType b/sandbox/sebastien/cpp/apr-2/components/webservice/webservice-client.componentType
new file mode 100644
index 0000000000..043087fe98
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/webservice/webservice-client.componentType
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<componentType xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/components">
+
+ <service name="client"/>
+ <property name="uri" type="xsd:string"/>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/components/webservice/webservice-client.cpp b/sandbox/sebastien/cpp/apr-2/components/webservice/webservice-client.cpp
new file mode 100644
index 0000000000..06db6c01b8
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/webservice/webservice-client.cpp
@@ -0,0 +1,65 @@
+/*
+ * 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$ */
+
+/**
+ * Web service client component implementation.
+ */
+
+#include "string.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "axis2.hpp"
+
+namespace tuscany {
+namespace webservice {
+
+/**
+ * Apply a function provided by a remote Web service using Axis2.
+ */
+const failable<value> apply(const value& func, const list<value>& params) {
+ const Axis2Context ax;
+
+ // Extract parameters
+ const value doc = car<value>(params);
+ const lambda<value(const list<value>&)> l = cadr<value>(params);
+
+ // Call the URI property lambda function to get the configured URI
+ const value uri = l(list<value>());
+
+ // Evaluate using Axis2
+ return evalExpr(mklist<value>(func, doc, uri), ax);
+}
+
+}
+}
+
+extern "C" {
+
+const tuscany::value apply(const tuscany::list<tuscany::value>& params) {
+ const tuscany::value func(car(params));
+ if (func == "start")
+ return tuscany::mkfailure<tuscany::value>();
+ return tuscany::webservice::apply(func, cdr(params));
+}
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/webservice/webservice-listener.componentType b/sandbox/sebastien/cpp/apr-2/components/webservice/webservice-listener.componentType
new file mode 100644
index 0000000000..ecd46b3c90
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/webservice/webservice-listener.componentType
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<componentType xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/components">
+
+ <service name="service"/>
+ <reference name="relay"/>
+
+</composite>
diff --git a/sandbox/sebastien/cpp/apr-2/components/webservice/webservice-listener.cpp b/sandbox/sebastien/cpp/apr-2/components/webservice/webservice-listener.cpp
new file mode 100644
index 0000000000..2127ecf0df
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/webservice/webservice-listener.cpp
@@ -0,0 +1,86 @@
+/*
+ * 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$ */
+
+/**
+ * Web service listener component implementation.
+ */
+
+#include "string.hpp"
+#include "function.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "../../modules/http/httpd.hpp"
+#include "axis2.hpp"
+
+namespace tuscany {
+namespace webservice {
+
+/**
+ * Redirect an HTTP request to the Axis2/C HTTPD module. The given relay lambda function
+ * is stored in the HTTPD request, for later retrieval by the Axis2 service to relay the request
+ * to a target component.
+ */
+extern "C" {
+ extern module axis2_module;
+}
+
+const value redirectToAxis2(const string& uri, request_rec* r, const value& relay) {
+ const failable<request_rec*, int> nr = httpd::internalRedirectRequest(uri, r);
+ if (!hasContent(nr))
+ return value(reason(nr));
+ ap_set_module_config(content(nr)->request_config, &axis2_module, const_cast<void*>((const void*)&relay));
+ return value(httpd::internalRedirect(content(nr)));
+}
+
+/**
+ * Handle an HTTP request.
+ */
+const failable<value> handle(const list<value>& params) {
+
+ // Extract HTTPD request from the params
+ request_rec* r = httpd::request(car(params));
+ httpdDebugRequest(r, "webservice::handle");
+
+ // Extract the relay lambda from the params and store it in the HTTPD request,
+ // for later retrieval by our Axis2 service
+ const value relay = cadr(params);
+ cout << "relay: " << &relay << endl;
+
+ // Redirect HTTPD request to Mod-axis2
+ if (r->args == NULL)
+ return redirectToAxis2(httpd::redirectURI("/axis2", string(r->uri)), r, relay);
+ return redirectToAxis2(httpd::redirectURI("/axis2", string(r->uri), string(r->args)), r, relay);
+}
+
+}
+}
+
+extern "C" {
+
+const tuscany::value apply(const tuscany::list<tuscany::value>& params) {
+ const tuscany::value func(car(params));
+ if (func == "handle")
+ return tuscany::webservice::handle(cdr(params));
+ return tuscany::mkfailure<tuscany::value>();
+}
+
+}
diff --git a/sandbox/sebastien/cpp/apr-2/components/webservice/webservice.composite b/sandbox/sebastien/cpp/apr-2/components/webservice/webservice.composite
new file mode 100644
index 0000000000..0169f5eb3a
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/components/webservice/webservice.composite
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+-->
+<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://tuscany.apache.org/xmlns/sca/components"
+ name="webservice">
+
+ <component name="webservice-client">
+ <implementation.cpp path="." library="libwebservice-client"/>
+ <property name="uri">http://localhost:9090/axis2/services/echo</property>
+ <service name="webservice-client">
+ <t:binding.jsonrpc uri="echo-client"/>
+ </service>
+ </component>
+
+ <component name="webservice-listener">
+ <implementation.cpp path="." library="libwebservice-listener"/>
+ <service name="webservice-listener">
+ <t:binding.http uri="echo-listener"/>
+ </service>
+ <reference name="relay" target="echo"/>
+ </component>
+
+ <component name="echo">
+ <t:implementation.scheme script="server-test.scm"/>
+ <service name="echo">
+ <t:binding.jsonrpc uri="echo"/>
+ </service>
+ </component>
+
+</composite>