diff options
Diffstat (limited to '')
68 files changed, 4985 insertions, 0 deletions
diff --git a/sca-cpp/branches/gcc-4.4/components/Makefile.am b/sca-cpp/branches/gcc-4.4/components/Makefile.am new file mode 100644 index 0000000000..c07ebb1468 --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/components/Makefile.am @@ -0,0 +1,22 @@ +# 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 queue sqldb store webservice + +includedir = $(prefix)/include/components +nobase_include_HEADERS = */*.hpp + diff --git a/sca-cpp/branches/gcc-4.4/components/cache/Makefile.am b/sca-cpp/branches/gcc-4.4/components/cache/Makefile.am new file mode 100644 index 0000000000..0a41f56dbe --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/components/cache/Makefile.am @@ -0,0 +1,35 @@ +# 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. + +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 + +comp_LTLIBRARIES = libmemcache.la +libmemcache_la_SOURCES = memcache.cpp + +memcache_test_SOURCES = memcache-test.cpp +memcache_test_LDFLAGS = -lxml2 + +client_test_SOURCES = client-test.cpp +client_test_LDFLAGS = -lxml2 -lcurl -lmozjs + +noinst_PROGRAMS = memcache-test client-test +TESTS = memcached-test server-test diff --git a/sca-cpp/branches/gcc-4.4/components/cache/client-test.cpp b/sca-cpp/branches/gcc-4.4/components/cache/client-test.cpp new file mode 100644 index 0000000000..e3ec449e69 --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/components/cache/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 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/curl.hpp" + +namespace tuscany { +namespace cache { + +const string uri("http://localhost:8090/memcache"); + +bool testCache() { + 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 << "Cache get test " << time(gl, 5, 200) << " ms" << endl; + + return true; +} + +} +} + +int main() { + tuscany::cout << "Testing..." << tuscany::endl; + + tuscany::cache::testCache(); + tuscany::cache::testGetPerf(); + + tuscany::cout << "OK" << tuscany::endl; + + return 0; +} diff --git a/sca-cpp/branches/gcc-4.4/components/cache/memcache-test.cpp b/sca-cpp/branches/gcc-4.4/components/cache/memcache-test.cpp new file mode 100644 index 0000000000..ea9e9883dc --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/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("127.0.0.1", 11211); + 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("127.0.0.1", 11211); + 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/sca-cpp/branches/gcc-4.4/components/cache/memcache.composite b/sca-cpp/branches/gcc-4.4/components/cache/memcache.composite new file mode 100644 index 0000000000..c9a147960e --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/components/cache/memcache.composite @@ -0,0 +1,32 @@ +<?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=".libs" library="libmemcache"/> + <service name="memcache"> + <t:binding.http uri="memcache"/> + </service> + </component> + +</composite> diff --git a/sca-cpp/branches/gcc-4.4/components/cache/memcache.cpp b/sca-cpp/branches/gcc-4.4/components/cache/memcache.cpp new file mode 100644 index 0000000000..247e38d517 --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/components/cache/memcache.cpp @@ -0,0 +1,133 @@ +/* + * 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 <apr_uuid.h> + +#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 value uuidValue() { + apr_uuid_t uuid; + apr_uuid_get(&uuid); + char buf[APR_UUID_FORMATTED_LENGTH]; + apr_uuid_format(buf, &uuid); + return value(string(buf, APR_UUID_FORMATTED_LENGTH)); +} + +const failable<value> post(const list<value>& params, memcache::MemCached& ch) { + const value id = append<value>(car(params), mklist(uuidValue())); + 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 + memcache::MemCached& ch = *(new (gc_new<memcache::MemCached>()) memcache::MemCached("127.0.0.1", 11211)); + + // 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/sca-cpp/branches/gcc-4.4/components/cache/memcache.hpp b/sca-cpp/branches/gcc-4.4/components/cache/memcache.hpp new file mode 100644 index 0000000000..d410b90767 --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/components/cache/memcache.hpp @@ -0,0 +1,175 @@ +/* + * 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); + init(host, port); + } + + 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); + + /** + * Initialize the memcached context. + */ + const failable<bool> init(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, 0, 1, 1, 60, &server); + if (sc != APR_SUCCESS) + return mkfailure<bool>("Could not create server"); + const apr_status_t as = apr_memcache_add_server(mc, server); + if (as != APR_SUCCESS) + return mkfailure<bool>("Could not add server"); + return true; + } +}; + +/** + * 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, c_str(ks), const_cast<char*>(c_str(vs)), length(vs), 0, 27); + if (rc != APR_SUCCESS) + return mkfailure<bool>("Could not add 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, c_str(ks), const_cast<char*>(c_str(vs)), length(vs), 0, 27); + if (rc != APR_SUCCESS) + return mkfailure<bool>("Could not set 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)); + apr_pool_t* vpool; + const apr_status_t pc = apr_pool_create(&vpool, cache.pool); + if (pc != APR_SUCCESS) + return mkfailure<value>("Could not allocate memory"); + + char *data; + apr_size_t size; + const apr_status_t rc = apr_memcache_getp(cache.mc, cache.pool, c_str(ks), &data, &size, NULL); + if (rc != APR_SUCCESS) { + apr_pool_destroy(vpool); + return mkfailure<value>("Could not get entry"); + } + + const value val(scheme::readValue(string(data, size))); + apr_pool_destroy(vpool); + + 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, c_str(ks), 0); + if (rc != APR_SUCCESS) + return mkfailure<bool>("Could not delete entry"); + + debug(true, "memcache::delete::result"); + return true; +} + +} +} + +#endif /* tuscany_memcache_hpp */ diff --git a/sca-cpp/branches/gcc-4.4/components/cache/memcached-start b/sca-cpp/branches/gcc-4.4/components/cache/memcached-start new file mode 100755 index 0000000000..b10d7f3fe8 --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/components/cache/memcached-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 memcached +here=`readlink -f $0`; here=`dirname $here` + +memcached_prefix=`cat $here/memcached.prefix` +$memcached_prefix/bin/memcached -d -l 127.0.0.1 -m 4 -p 11211 + diff --git a/sca-cpp/branches/gcc-4.4/components/cache/memcached-stop b/sca-cpp/branches/gcc-4.4/components/cache/memcached-stop new file mode 100755 index 0000000000..80801cdfbf --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/components/cache/memcached-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 memcached +here=`readlink -f $0`; here=`dirname $here` + +memcached_prefix=`cat $here/memcached.prefix` +mc="$memcached_prefix/bin/memcached -d -l 127.0.0.1 -m 4 -p 11211" + +kill `ps -ef | grep -v grep | grep "${mc}" | awk '{ print $2 }'` diff --git a/sca-cpp/branches/gcc-4.4/components/cache/memcached-test b/sca-cpp/branches/gcc-4.4/components/cache/memcached-test new file mode 100755 index 0000000000..842e8d2030 --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/components/cache/memcached-test @@ -0,0 +1,30 @@ +#!/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 +sleep 1 + +# Test +./memcache-test 2>/dev/null +rc=$? + +# Cleanup +./memcached-stop +return $rc diff --git a/sca-cpp/branches/gcc-4.4/components/cache/server-test b/sca-cpp/branches/gcc-4.4/components/cache/server-test new file mode 100755 index 0000000000..5c86b75ebc --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/components/cache/server-test @@ -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. + +# 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 memcache.composite +EOF + +./memcached-start +../../modules/http/httpd-start tmp +sleep 2 + +# Test +./client-test 2>/dev/null +rc=$? + +# Cleanup +../../modules/http/httpd-stop tmp +./memcached-stop +sleep 2 +return $rc diff --git a/sca-cpp/branches/gcc-4.4/components/chat/Makefile.am b/sca-cpp/branches/gcc-4.4/components/chat/Makefile.am new file mode 100644 index 0000000000..804238a5d7 --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/components/chat/Makefile.am @@ -0,0 +1,54 @@ +# 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} + +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 + +comp_LTLIBRARIES = libchatter.la +libchatter_la_SOURCES = chatter.cpp +libchatter_la_LDFLAGS = -L${LIBSTROPHE_LIB} -R${LIBSTROPHE_LIB} -lstrophe -lexpat -lssl -lresolv + +xmpp_test_SOURCES = xmpp-test.cpp +xmpp_test_LDFLAGS = -L${LIBSTROPHE_LIB} -R${LIBSTROPHE_LIB} -lstrophe -lexpat -lssl -lresolv + +client_test_SOURCES = client-test.cpp +client_test_LDFLAGS = -lxml2 -lcurl -lmozjs -L${LIBSTROPHE_LIB} -R${LIBSTROPHE_LIB} -lstrophe -lexpat -lssl -lresolv + +noinst_PROGRAMS = xmpp-test client-test + +if WANT_VYSPER + +AM_JAVACFLAGS = -cp `${top_builddir}/components/chat/vysper-classpath ${VYSPER_PREFIX}`${JAVAROOT} + +noinst_JAVA = test/*.java + +CLEANFILES = test/*.class + +TESTS = echo-test +endif + +endif diff --git a/sca-cpp/branches/gcc-4.4/components/chat/chat.composite b/sca-cpp/branches/gcc-4.4/components/chat/chat.composite new file mode 100644 index 0000000000..569dbfc4b2 --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/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=".libs" library="libchatter"/> + <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=".libs" library="libchatter"/> + <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/sca-cpp/branches/gcc-4.4/components/chat/chatter.cpp b/sca-cpp/branches/gcc-4.4/components/chat/chatter.cpp new file mode 100644 index 0000000000..95f2d40077 --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/components/chat/chatter.cpp @@ -0,0 +1,162 @@ +/* + * 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 chatter 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 { + +/** + * 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; +}; + +/** + * Chatter component lambda function + */ +class chatter { +public: + chatter(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 chatter component + if (func != "stop") + return tuscany::mkfailure<tuscany::value>(); + debug("chat::chatter::stop"); + + // Disconnect and shutdown the worker thread + disconnect(const_cast<XMPPClient&>(xc)); + cancel(const_cast<worker&>(w)); + debug("chat::chatter::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 chatter component lambda function + return value(lambda<value(const list<value>&)>(chatter(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::start(cdr(params)); + return tuscany::mkfailure<tuscany::value>(); +} + +} diff --git a/sca-cpp/branches/gcc-4.4/components/chat/client-test.cpp b/sca-cpp/branches/gcc-4.4/components/chat/client-test.cpp new file mode 100644 index 0000000000..f9ca2cabd6 --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/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/curl.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/sca-cpp/branches/gcc-4.4/components/chat/echo-test b/sca-cpp/branches/gcc-4.4/components/chat/echo-test new file mode 100755 index 0000000000..271d40d122 --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/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/sca-cpp/branches/gcc-4.4/components/chat/server-test b/sca-cpp/branches/gcc-4.4/components/chat/server-test new file mode 100755 index 0000000000..dd1dc6faa7 --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/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/sca-cpp/branches/gcc-4.4/components/chat/server-test.scm b/sca-cpp/branches/gcc-4.4/components/chat/server-test.scm new file mode 100644 index 0000000000..a6023708e1 --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/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/sca-cpp/branches/gcc-4.4/components/chat/test/TestVysperServer.java b/sca-cpp/branches/gcc-4.4/components/chat/test/TestVysperServer.java new file mode 100644 index 0000000000..3d2b7d7c3e --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/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/sca-cpp/branches/gcc-4.4/components/chat/vysper-classpath b/sca-cpp/branches/gcc-4.4/components/chat/vysper-classpath new file mode 100755 index 0000000000..7cf16a5ae8 --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/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/sca-cpp/branches/gcc-4.4/components/chat/vysper-start b/sca-cpp/branches/gcc-4.4/components/chat/vysper-start new file mode 100755 index 0000000000..af95ecadf4 --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/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/sca-cpp/branches/gcc-4.4/components/chat/vysper-stop b/sca-cpp/branches/gcc-4.4/components/chat/vysper-stop new file mode 100755 index 0000000000..3c4be4efa9 --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/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/sca-cpp/branches/gcc-4.4/components/chat/xmpp-test.cpp b/sca-cpp/branches/gcc-4.4/components/chat/xmpp-test.cpp new file mode 100644 index 0000000000..6b7fa3439f --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/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/sca-cpp/branches/gcc-4.4/components/chat/xmpp.hpp b/sca-cpp/branches/gcc-4.4/components/chat/xmpp.hpp new file mode 100644 index 0000000000..34ab13ed98 --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/components/chat/xmpp.hpp @@ -0,0 +1,330 @@ +/* + * 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 <apr_uuid.h> + +#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. + */ +const string resourceUUID() { + apr_uuid_t uuid; + apr_uuid_get(&uuid); + char buf[APR_UUID_FORMATTED_LENGTH]; + apr_uuid_format(buf, &uuid); + return string(buf, APR_UUID_FORMATTED_LENGTH); +} + +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 + "/" + resourceUUID())); + 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<int> send(const char* data, const int len, XMPPClient& xc); + friend const failable<int> 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<int> send(const char* data, const int len, XMPPClient& xc) { + if (len == 0) + return 0; + const int written = xc.conn->tls? tls_write(xc.conn->tls, data, len) : sock_write(xc.conn->sock, data, len); + if (written < 0) { + xc.conn->error = xc.conn->tls? tls_error(xc.conn->tls) : sock_error(); + return mkfailure<int>("Couldn't send stanza to XMPP server"); + } + return send(data + written, len - written, xc); +} + +/** + * Send a string on an XMPP session. + */ +const failable<int> send(const string& data, XMPPClient& xc) { + return send(c_str(data), length(data), xc); +} + +/** + * Send a stanza on an XMPP session. + */ +const failable<int> 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<int>("Couldn't convert stanza to text"); + const failable<int> 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<int> 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<int> 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/sca-cpp/branches/gcc-4.4/components/log/Makefile.am b/sca-cpp/branches/gcc-4.4/components/log/Makefile.am new file mode 100644 index 0000000000..de5c2d1b1e --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/components/log/Makefile.am @@ -0,0 +1,17 @@ +# 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. + diff --git a/sca-cpp/branches/gcc-4.4/components/log/log.composite b/sca-cpp/branches/gcc-4.4/components/log/log.composite new file mode 100644 index 0000000000..2b0a557e4e --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/components/log/log.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="log"> + + <component name="log"> + <implementation.cpp path=".libs" library="liblog"/> + <property name="file">sample.log</property>property> + <service name="log"> + <t:binding.http uri="log"/> + </service> + </component> + +</composite> diff --git a/sca-cpp/branches/gcc-4.4/components/queue/Makefile.am b/sca-cpp/branches/gcc-4.4/components/queue/Makefile.am new file mode 100644 index 0000000000..856aef8ea0 --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/components/queue/Makefile.am @@ -0,0 +1,46 @@ +# 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} + +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 + +comp_LTLIBRARIES = libqueue-sender.la libqueue-listener.la + +libqueue_sender_la_SOURCES = queue-sender.cpp +libqueue_sender_la_LDFLAGS = -L${QPIDC_LIB} -R${QPIDC_LIB} -lqpidclient -lqpidcommon + +libqueue_listener_la_SOURCES = queue-listener.cpp +libqueue_listener_la_LDFLAGS = -L${QPIDC_LIB} -R${QPIDC_LIB} -lqpidclient -lqpidcommon + +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 + +noinst_PROGRAMS = qpid-test client-test +TESTS = send-test server-test + +endif diff --git a/sca-cpp/branches/gcc-4.4/components/queue/client-test.cpp b/sca-cpp/branches/gcc-4.4/components/queue/client-test.cpp new file mode 100644 index 0000000000..a448d1fccd --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/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/curl.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/sca-cpp/branches/gcc-4.4/components/queue/qpid-test.cpp b/sca-cpp/branches/gcc-4.4/components/queue/qpid-test.cpp new file mode 100644 index 0000000000..1a650157b2 --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/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/sca-cpp/branches/gcc-4.4/components/queue/qpid.hpp b/sca-cpp/branches/gcc-4.4/components/queue/qpid.hpp new file mode 100644 index 0000000000..2651e3a433 --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/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/sca-cpp/branches/gcc-4.4/components/queue/qpidd-start b/sca-cpp/branches/gcc-4.4/components/queue/qpidd-start new file mode 100755 index 0000000000..02e048c41e --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/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/sca-cpp/branches/gcc-4.4/components/queue/qpidd-stop b/sca-cpp/branches/gcc-4.4/components/queue/qpidd-stop new file mode 100755 index 0000000000..3baf2fee27 --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/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/sca-cpp/branches/gcc-4.4/components/queue/queue-listener.cpp b/sca-cpp/branches/gcc-4.4/components/queue/queue-listener.cpp new file mode 100644 index 0000000000..d714101583 --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/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/sca-cpp/branches/gcc-4.4/components/queue/queue-sender.cpp b/sca-cpp/branches/gcc-4.4/components/queue/queue-sender.cpp new file mode 100644 index 0000000000..07f8491f54 --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/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/sca-cpp/branches/gcc-4.4/components/queue/queue.composite b/sca-cpp/branches/gcc-4.4/components/queue/queue.composite new file mode 100644 index 0000000000..535680c6c3 --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/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=".libs" 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=".libs" 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=".libs" library="libqueue-sender"/> + <property name="key">report</property> + <service name="report-sender"> + <t:binding.http uri="report-sender"/> + </service> + </component> + +</composite> diff --git a/sca-cpp/branches/gcc-4.4/components/queue/send-test b/sca-cpp/branches/gcc-4.4/components/queue/send-test new file mode 100755 index 0000000000..ec6d9d9083 --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/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/sca-cpp/branches/gcc-4.4/components/queue/server-test b/sca-cpp/branches/gcc-4.4/components/queue/server-test new file mode 100755 index 0000000000..571b09082c --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/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/sca-cpp/branches/gcc-4.4/components/queue/server-test.scm b/sca-cpp/branches/gcc-4.4/components/queue/server-test.scm new file mode 100644 index 0000000000..1a89ce8b31 --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/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/sca-cpp/branches/gcc-4.4/components/sqldb/Makefile.am b/sca-cpp/branches/gcc-4.4/components/sqldb/Makefile.am new file mode 100644 index 0000000000..b7c8a4eeaf --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/components/sqldb/Makefile.am @@ -0,0 +1,43 @@ +# 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} + +#comp_SCRIPTS = pgsql-start pgsql-stop +compdir=$(prefix)/components/sqldb + +comp_DATA = pgsql.prefix +pgsql.prefix: $(top_builddir)/config.status + echo ${PGSQL_PREFIX} >pgsql.prefix + +comp_LTLIBRARIES = libsqldb.la + +libsqldb_la_SOURCES = sqldb.cpp +libsqldb_la_LDFLAGS = -L${PGSQL_LIB} -R${PGSQL_LIB} -lpq + +pgsql_test_SOURCES = pgsql-test.cpp +pgsql_test_LDFLAGS = -L${PGSQL_LIB} -R${PGSQL_LIB} -lpq + +client_test_SOURCES = client-test.cpp +client_test_LDFLAGS = -lxml2 -lcurl -lmozjs + +noinst_PROGRAMS = pgsql-test client-test +TESTS = sqldb-test server-test + +endif diff --git a/sca-cpp/branches/gcc-4.4/components/sqldb/client-test.cpp b/sca-cpp/branches/gcc-4.4/components/sqldb/client-test.cpp new file mode 100644 index 0000000000..271ec08bed --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/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 SQLDB 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/curl.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/sca-cpp/branches/gcc-4.4/components/sqldb/pgsql b/sca-cpp/branches/gcc-4.4/components/sqldb/pgsql new file mode 100755 index 0000000000..3cd1904e32 --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/components/sqldb/pgsql @@ -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. + +# Run SQL command +here=`readlink -f $0`; here=`dirname $here` +pgsql_prefix=`cat $here/pgsql.prefix` + +$pgsql_prefix/bin/psql -c "$1" db + diff --git a/sca-cpp/branches/gcc-4.4/components/sqldb/pgsql-start b/sca-cpp/branches/gcc-4.4/components/sqldb/pgsql-start new file mode 100755 index 0000000000..f5c0f87614 --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/components/sqldb/pgsql-start @@ -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. + +# 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 +if [ ! -f $root/sqldb/postgresql.conf ]; then + $pgsql_prefix/bin/pg_ctl init -D $root/sqldb 1>/dev/null 2>&1 + createdb="true" +fi + +$pgsql_prefix/bin/pg_ctl start -D $root/sqldb -l $root/logs/postgresql 1>/dev/null 2>&1 +sleep 2 +if [ "$createdb" = "true" ]; then + $pgsql_prefix/bin/createdb db 1>/dev/null 2>&1 +fi + diff --git a/sca-cpp/branches/gcc-4.4/components/sqldb/pgsql-stop b/sca-cpp/branches/gcc-4.4/components/sqldb/pgsql-stop new file mode 100755 index 0000000000..d0cda096ba --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/components/sqldb/pgsql-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 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 stop -D $root/sqldb 1>/dev/null 2>&1 + diff --git a/sca-cpp/branches/gcc-4.4/components/sqldb/pgsql-test.cpp b/sca-cpp/branches/gcc-4.4/components/sqldb/pgsql-test.cpp new file mode 100644 index 0000000000..7fb6b0c814 --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/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("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("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/sca-cpp/branches/gcc-4.4/components/sqldb/pgsql.hpp b/sca-cpp/branches/gcc-4.4/components/sqldb/pgsql.hpp new file mode 100644 index 0000000000..08e8a44123 --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/components/sqldb/pgsql.hpp @@ -0,0 +1,227 @@ +/* + * 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 + +#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) { + const string e = PQresultErrorMessage(r); + PQclear(r); + return e; +} + +/** + * Represents a PGSql connection. + */ +class PGSql { +public: + PGSql() : owner(false) { + } + + PGSql(const string& conninfo, const string& table) : owner(true), conninfo(conninfo), table(table) { + init(); + } + + PGSql(const PGSql& c) : owner(false) { + conninfo = c.conninfo; + conn = c.conn; + table = c.table; + } + + ~PGSql() { + if (!owner) + return; + PQfinish(conn); + } + +private: + bool owner; + PGconn *conn; + string conninfo; + string table; + + 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); + + /** + * Initialize the database connection + */ + const failable<bool> init() { + conn = PQconnectdb(c_str(conninfo)); + if (PQstatus(conn) != CONNECTION_OK) + return mkfailure<bool>(string("Could not connect to database: ") + PQerrorMessage(conn)); + + // 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 column select statement: ") + pgfailure(kr)); + if (PQntuples(kr) != 2) { + PQclear(kr); + return mkfailure<bool>(string("Could not find 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 SQL statement: ") + pgfailure(r)); + 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 SQL statement: ") + pgfailure(r)); + 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 SQL statement: ") + pgfailure(r)); + 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 SQL statement: ") + pgfailure(r)); + PQclear(r); + } + return true; + } +}; + +/** + * 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.table, "pgsql::post::table"); + + 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 post SQL statement: ") + pgfailure(r)); + 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.table, "pgsql::put::table"); + + 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 put SQL statement: ") + pgfailure(r)); + 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 post SQL statement: ") + pgfailure(pr)); + 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.table, "pgsql::get::table"); + + 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 get SQL statement: ") + pgfailure(r)); + if (PQntuples(r) < 1) { + PQclear(r); + return mkfailure<value>(string("Could not get 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.table, "pgsql::delete::table"); + + 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 SQL statement: ") + pgfailure(r)); + PQclear(r); + + debug(true, "pgsql::delete::result"); + return true; +} + +} +} + +#endif /* tuscany_pgsql_hpp */ diff --git a/sca-cpp/branches/gcc-4.4/components/sqldb/server-test b/sca-cpp/branches/gcc-4.4/components/sqldb/server-test new file mode 100755 index 0000000000..784c7156c5 --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/components/sqldb/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 sqldb.composite +EOF + +./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/http/httpd-start tmp +sleep 2 + +# Test +./client-test 2>/dev/null +rc=$? + +# Cleanup +../../modules/http/httpd-stop tmp +./pgsql-stop tmp +sleep 2 +return $rc diff --git a/sca-cpp/branches/gcc-4.4/components/sqldb/sqldb-test b/sca-cpp/branches/gcc-4.4/components/sqldb/sqldb-test new file mode 100755 index 0000000000..05fe413d50 --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/components/sqldb/sqldb-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 +./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/sca-cpp/branches/gcc-4.4/components/sqldb/sqldb.composite b/sca-cpp/branches/gcc-4.4/components/sqldb/sqldb.composite new file mode 100644 index 0000000000..9675340b0c --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/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=".libs" library="libsqldb"/> + <property name="conninfo">dbname=db</property> + <property name="table">test</property> + <service name="sqldb"> + <t:binding.http uri="sqldb"/> + </service> + </component> + +</composite> diff --git a/sca-cpp/branches/gcc-4.4/components/sqldb/sqldb.cpp b/sca-cpp/branches/gcc-4.4/components/sqldb/sqldb.cpp new file mode 100644 index 0000000000..e84a732511 --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/components/sqldb/sqldb.cpp @@ -0,0 +1,135 @@ +/* + * 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 <apr_uuid.h> + +#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 value uuidValue() { + apr_uuid_t uuid; + apr_uuid_get(&uuid); + char buf[APR_UUID_FORMATTED_LENGTH]; + apr_uuid_format(buf, &uuid); + return value(string(buf, APR_UUID_FORMATTED_LENGTH)); +} + +const failable<value> post(const list<value>& params, pgsql::PGSql& pg) { + const value id = append<value>(car(params), mklist(uuidValue())); + 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/sca-cpp/branches/gcc-4.4/components/store/Makefile.am b/sca-cpp/branches/gcc-4.4/components/store/Makefile.am new file mode 100644 index 0000000000..f372faf8a2 --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/components/store/Makefile.am @@ -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. + +if WANT_NOSQLDB + +endif diff --git a/sca-cpp/branches/gcc-4.4/components/store/store.composite b/sca-cpp/branches/gcc-4.4/components/store/store.composite new file mode 100644 index 0000000000..ccfd61fc4d --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/components/store/store.composite @@ -0,0 +1,32 @@ +<?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="store"> + + <component name="store"> + <implementation.cpp path=".libs" library="libstore"/> + <service name="store"> + <t:binding.http uri="store"/> + </service> + </component> + +</composite> diff --git a/sca-cpp/branches/gcc-4.4/components/webservice/Makefile.am b/sca-cpp/branches/gcc-4.4/components/webservice/Makefile.am new file mode 100644 index 0000000000..1f4ece7003 --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/components/webservice/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. + +if WANT_WEBSERVICE + +INCLUDES = -I${AXIS2C_INCLUDE} + +comp_DATA = axis2c.prefix +compdir=$(prefix)/components/webservice +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 + +libwebservice_client_la_SOURCES = webservice-client.cpp +libwebservice_client_la_LDFLAGS = -lxml2 -L${AXIS2C_LIB} -R${AXIS2C_LIB} -laxis2_engine -laxis2_axiom -laxutil + +libwebservice_listener_la_SOURCES = webservice-listener.cpp +libwebservice_listener_la_LDFLAGS = -lxml2 -L${AXIS2C_LIB} -R${AXIS2C_LIB} -laxis2_engine -laxis2_axiom -laxutil + +libaxis2_dispatcher_la_SOURCES = axis2-dispatcher.cpp +libaxis2_dispatcher_la_LDFLAGS = -lxml2 -L${AXIS2C_LIB} -R${AXIS2C_LIB} -laxis2_engine -laxis2_axiom -laxutil + +libaxis2_service_la_SOURCES = axis2-service.cpp +libaxis2_service_la_LDFLAGS = -lxml2 -L${AXIS2C_LIB} -R${AXIS2C_LIB} -laxis2_engine -laxis2_axiom -laxutil + +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 + +noinst_PROGRAMS = axiom-test axis2-test client-test +TESTS = axiom-test echo-test server-test + +endif diff --git a/sca-cpp/branches/gcc-4.4/components/webservice/axiom-test.cpp b/sca-cpp/branches/gcc-4.4/components/webservice/axiom-test.cpp new file mode 100644 index 0000000000..a3ab8e7e8f --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/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/sca-cpp/branches/gcc-4.4/components/webservice/axis2-conf b/sca-cpp/branches/gcc-4.4/components/webservice/axis2-conf new file mode 100755 index 0000000000..c731733662 --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/components/webservice/axis2-conf @@ -0,0 +1,55 @@ +#!/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` +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/.libs/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/.libs/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/httpd.conf <<EOF +# Support for Web Services +SCASetEnv AXIS2C_HOME $root/axis2c +LoadModule axis2_module $root/axis2c/lib/libmod_axis2.so +Axis2RepoPath $root/axis2c +Axis2LogFile $root/axis2c/logs/mod_axis2.log +Axis2LogLevel debug +<Location /axis2> + SetHandler axis2_module +</Location> + +EOF diff --git a/sca-cpp/branches/gcc-4.4/components/webservice/axis2-dispatcher.cpp b/sca-cpp/branches/gcc-4.4/components/webservice/axis2-dispatcher.cpp new file mode 100644 index 0000000000..3f753e0e35 --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/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/sca-cpp/branches/gcc-4.4/components/webservice/axis2-service.cpp b/sca-cpp/branches/gcc-4.4/components/webservice/axis2-service.cpp new file mode 100644 index 0000000000..4c0ce22722 --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/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/sca-cpp/branches/gcc-4.4/components/webservice/axis2-test.cpp b/sca-cpp/branches/gcc-4.4/components/webservice/axis2-test.cpp new file mode 100644 index 0000000000..d7c2f3b671 --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/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/sca-cpp/branches/gcc-4.4/components/webservice/axis2.hpp b/sca-cpp/branches/gcc-4.4/components/webservice/axis2.hpp new file mode 100644 index 0000000000..c2886edb71 --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/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/sca-cpp/branches/gcc-4.4/components/webservice/axis2.xml b/sca-cpp/branches/gcc-4.4/components/webservice/axis2.xml new file mode 100644 index 0000000000..ea9b6d2194 --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/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/sca-cpp/branches/gcc-4.4/components/webservice/client-test.cpp b/sca-cpp/branches/gcc-4.4/components/webservice/client-test.cpp new file mode 100644 index 0000000000..9030a77676 --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/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/curl.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/sca-cpp/branches/gcc-4.4/components/webservice/echo-test b/sca-cpp/branches/gcc-4.4/components/webservice/echo-test new file mode 100755 index 0000000000..e5cd1d9a9d --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/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/sca-cpp/branches/gcc-4.4/components/webservice/module.xml b/sca-cpp/branches/gcc-4.4/components/webservice/module.xml new file mode 100644 index 0000000000..8f6ba5018f --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/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/sca-cpp/branches/gcc-4.4/components/webservice/server-test b/sca-cpp/branches/gcc-4.4/components/webservice/server-test new file mode 100755 index 0000000000..34fdb7266a --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/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/sca-cpp/branches/gcc-4.4/components/webservice/server-test.scm b/sca-cpp/branches/gcc-4.4/components/webservice/server-test.scm new file mode 100644 index 0000000000..44e4eee92a --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/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/sca-cpp/branches/gcc-4.4/components/webservice/services.xml b/sca-cpp/branches/gcc-4.4/components/webservice/services.xml new file mode 100644 index 0000000000..0adf136f4f --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/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/sca-cpp/branches/gcc-4.4/components/webservice/webservice-client.cpp b/sca-cpp/branches/gcc-4.4/components/webservice/webservice-client.cpp new file mode 100644 index 0000000000..06db6c01b8 --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/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/sca-cpp/branches/gcc-4.4/components/webservice/webservice-listener.cpp b/sca-cpp/branches/gcc-4.4/components/webservice/webservice-listener.cpp new file mode 100644 index 0000000000..2127ecf0df --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/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/sca-cpp/branches/gcc-4.4/components/webservice/webservice.composite b/sca-cpp/branches/gcc-4.4/components/webservice/webservice.composite new file mode 100644 index 0000000000..6d4055aad3 --- /dev/null +++ b/sca-cpp/branches/gcc-4.4/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-client"> + + <component name="webservice-client"> + <implementation.cpp path=".libs" 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=".libs" 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> |