diff options
author | jsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68> | 2010-02-28 19:40:06 +0000 |
---|---|---|
committer | jsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68> | 2010-02-28 19:40:06 +0000 |
commit | e982b4ef38fd043c15e89bdd60763b10434a087e (patch) | |
tree | 6b9d9c3fc9aff22edb0f137040164c1cbf2359af /sca-cpp/branches/cpp-contrib/modules/server | |
parent | 64e2486555a0a14f7d9690c2fc62c30bde803a91 (diff) |
Moving old inactive code to a branch as it's confusing code assist, searches and indexing in trunk.
git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@917273 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to '')
23 files changed, 2156 insertions, 0 deletions
diff --git a/sca-cpp/branches/cpp-contrib/modules/server/Makefile.am b/sca-cpp/branches/cpp-contrib/modules/server/Makefile.am new file mode 100644 index 0000000000..9c18b45dad --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/modules/server/Makefile.am @@ -0,0 +1,39 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +noinst_PROGRAMS = client-test + +libdir=$(prefix)/lib +lib_LTLIBRARIES = libmod_tuscany_eval.la libmod_tuscany_wiring.la + +INCLUDES = -I${HTTPD_INCLUDE} + +libmod_tuscany_eval_la_SOURCES = mod-eval.cpp +libmod_tuscany_eval_la_LDFLAGS = -lxml2 -lcurl -lmozjs + +libmod_tuscany_wiring_la_SOURCES = mod-wiring.cpp +libmod_tuscany_wiring_la_LDFLAGS = -lxml2 -lcurl -lmozjs + +testdir=$(prefix)/test +test_LTLIBRARIES = libimpl-test.la + +libimpl_test_la_SOURCES = impl-test.cpp + +client_test_SOURCES = client-test.cpp +client_test_LDFLAGS = -lxml2 -lcurl -lmozjs + +TESTS = httpd-test server-test wiring-test diff --git a/sca-cpp/branches/cpp-contrib/modules/server/client-test.cpp b/sca-cpp/branches/cpp-contrib/modules/server/client-test.cpp new file mode 100644 index 0000000000..3bc8aa7d10 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/modules/server/client-test.cpp @@ -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. + */ + +/* $Rev$ $Date$ */ + +/** + * Test HTTP client functions. + */ + +#include "stream.hpp" +#include "string.hpp" +#include "client-test.hpp" + +namespace tuscany { +namespace server { + +string testURI = "http://localhost:8090/test"; + +} +} + +int main() { + tuscany::cout << "Testing..." << tuscany::endl; + + tuscany::server::testServer(); + + tuscany::cout << "OK" << tuscany::endl; + + return 0; +} diff --git a/sca-cpp/branches/cpp-contrib/modules/server/client-test.hpp b/sca-cpp/branches/cpp-contrib/modules/server/client-test.hpp new file mode 100644 index 0000000000..651a9016b2 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/modules/server/client-test.hpp @@ -0,0 +1,346 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* $Rev$ $Date$ */ + +/** + * Test HTTP client functions. + */ + +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> +#include <assert.h> +#include "stream.hpp" +#include "string.hpp" +#include "parallel.hpp" +#include "perf.hpp" +#include "../http/curl.hpp" + +namespace tuscany { +namespace server { + +extern string testURI; + +ostream* curlWriter(const string& s, ostream* os) { + (*os) << s; + return os; +} + +const bool testGet() { + gc_scoped_pool pool; + http::CURLSession ch; + { + ostringstream os; + const failable<list<ostream*> > r = http::get<ostream*>(curlWriter, &os, "http://localhost:8090", ch); + assert(hasContent(r)); + assert(contains(str(os), "HTTP/1.1 200 OK")); + assert(contains(str(os), "It works")); + } + { + const failable<value> r = http::getcontent("http://localhost:8090", ch); + assert(hasContent(r)); + assert(contains(car(reverse(list<value>(content(r)))), "It works")); + } + return true; +} + +struct getLoop { + http::CURLSession ch; + getLoop(http::CURLSession& ch) : ch(ch) { + } + const bool operator()() const { + const failable<value> r = http::getcontent("http://localhost:8090", ch); + assert(hasContent(r)); + assert(contains(car(reverse(list<value>(content(r)))), "It works")); + return true; + } +}; + +const bool testGetPerf() { + gc_scoped_pool pool; + http::CURLSession ch; + const lambda<bool()> gl = getLoop(ch); + cout << "Static GET test " << time(gl, 5, 200) << " ms" << endl; + return true; +} + +const bool testEval() { + gc_scoped_pool pool; + http::CURLSession ch; + const value val = content(http::evalExpr(mklist<value>(string("echo"), string("Hello")), testURI, ch)); + assert(val == string("Hello")); + return true; +} + +struct evalLoop { + const string uri; + http::CURLSession ch; + evalLoop(const string& uri, http::CURLSession& ch) : uri(uri), ch(ch) { + } + const bool operator()() const { + const value val = content(http::evalExpr(mklist<value>(string("echo"), string("Hello")), uri, ch)); + assert(val == string("Hello")); + return true; + } +}; + +const value blob(string(2048, 'A')); +const list<value> blobs = mklist(blob, blob); + +struct blobEvalLoop { + const string uri; + http::CURLSession ch; + blobEvalLoop(const string& uri, http::CURLSession& ch) : uri(uri), ch(ch) { + } + const bool operator()() const { + const value val = content(http::evalExpr(mklist<value>(string("echo"), blobs), uri, ch)); + assert(val == blobs); + return true; + } +}; + +const bool testEvalPerf() { + gc_scoped_pool pool; + http::CURLSession ch; + const lambda<bool()> el = evalLoop(testURI, ch); + cout << "JSON-RPC eval echo test " << time(el, 5, 200) << " ms" << endl; + const lambda<bool()> bel = blobEvalLoop(testURI, ch); + cout << "JSON-RPC eval blob test " << time(bel, 5, 200) << " ms" << endl; + return true; +} + +bool testPost() { + gc_scoped_pool pool; + 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); + http::CURLSession ch; + const failable<value> id = http::post(a, testURI, ch); + assert(hasContent(id)); + return true; +} + +struct postLoop { + const string uri; + const value val; + http::CURLSession ch; + postLoop(const string& uri, const value& val, http::CURLSession& ch) : uri(uri), val(val), ch(ch) { + } + const bool operator()() const { + const failable<value> id = http::post(val, uri, ch); + assert(hasContent(id)); + return true; + } +}; + +struct postBlobLoop { + const string uri; + const value val; + http::CURLSession ch; + postBlobLoop(const string& uri, const value& val, http::CURLSession& ch) : uri(uri), val(val), ch(ch) { + } + const bool operator()() const { + gc_scoped_pool pool; + const failable<value> id = http::post(val, uri, ch); + assert(hasContent(id)); + return true; + } +}; + +const bool testPostPerf() { + gc_scoped_pool pool; + http::CURLSession ch; + { + const list<value> i = list<value>() + + (list<value>() + "name" + string("Apple")) + + (list<value>() + "price" + string("$2.99")); + const list<value> val = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i); + const lambda<bool()> pl = postLoop(testURI, val, ch); + cout << "ATOMPub POST small test " << time(pl, 5, 200) << " ms" << endl; + } + { + const list<value> i = list<value>() + + (list<value>() + "name" + string("Apple")) + + (list<value>() + "blob1" + blob) + + (list<value>() + "blob2" + blob) + + (list<value>() + "price" + string("$2.99")); + const list<value> val = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i); + const lambda<bool()> pl = postBlobLoop(testURI, val, ch); + cout << "ATOMPub POST blob test " << time(pl, 5, 200) << " ms" << endl; + } + return true; +} + +#ifdef WANT_THREADS + +const bool postThread(const string& uri, const int count, const value& val) { + gc_scoped_pool pool; + http::CURLSession ch; + const lambda<bool()> pl = postLoop(uri, val, ch); + time(pl, 0, count); + return true; +} + +const list<future<bool> > startPost(worker& w, const int threads, const lambda<bool()>& l) { + if (threads == 0) + return list<future<bool> >(); + return cons(submit(w, l), startPost(w, threads - 1, l)); +} + +const bool checkPost(const list<future<bool> >& r) { + if (isNil(r)) + return true; + assert(car(r) == true); + return checkPost(cdr(r)); +} + +struct postThreadLoop { + const lambda<bool()> l; + const int threads; + const gc_ptr<worker> w; + postThreadLoop(const lambda<bool()>& l, const int threads) : l(l), threads(threads), w(new (gc_new<worker>()) worker(threads)) { + } + const bool operator()() const { + list<future<bool> > r = startPost(*w, threads, l); + checkPost(r); + return true; + } +}; + +const bool testPostThreadPerf() { + gc_scoped_pool pool; + const int count = 50; + const int threads = 10; + + const list<value> i = list<value>() + + (list<value>() + "name" + string("Apple")) + + (list<value>() + "price" + string("$2.99")); + const value val = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i); + + const lambda<bool()> pl= curry(lambda<bool(const string, const int, const value)>(postThread), testURI, count, val); + const lambda<bool()> ptl = postThreadLoop(pl, threads); + double t = time(ptl, 0, 1) / (threads * count); + cout << "ATOMPub POST thread test " << t << " ms" << endl; + + return true; +} + +#else + +const bool postProc(const string& uri, const int count, const value& val) { + gc_scoped_pool pool; + http::CURLSession ch; + const lambda<bool()> pl = postLoop(uri, val, ch); + time(pl, 0, count); + return true; +} + +const list<pid_t> startPost(const int procs, const lambda<bool()>& l) { + if (procs == 0) + return list<pid_t>(); + pid_t pid = fork(); + if (pid == 0) { + assert(l() == true); + exit(0); + } + return cons(pid, startPost(procs - 1, l)); +} + +const bool checkPost(const list<pid_t>& r) { + if (isNil(r)) + return true; + int status; + waitpid(car(r), &status, 0); + assert(status == 0); + return checkPost(cdr(r)); +} + +struct postForkLoop { + const lambda<bool()> l; + const int procs; + postForkLoop(const lambda<bool()>& l, const int procs) : l(l), procs(procs) { + } + const bool operator()() const { + list<pid_t> r = startPost(procs, l); + checkPost(r); + return true; + } +}; + +const bool testPostForkPerf() { + gc_scoped_pool pool; + const int count = 50; + const int procs = 10; + + const list<value> i = list<value>() + + (list<value>() + "name" + string("Apple")) + + (list<value>() + "price" + string("$2.99")); + const value val = mklist<value>(string("item"), string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i); + + const lambda<bool()> pl= curry(lambda<bool(const string, const int, const value)>(postProc), testURI, count, val); + const lambda<bool()> ptl = postForkLoop(pl, procs); + double t = time(ptl, 0, 1) / (procs * count); + cout << "ATOMPub POST fork test " << t << " ms" << endl; + + return true; +} + +#endif + +const bool testPut() { + gc_scoped_pool pool; + 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); + http::CURLSession ch; + value rc = content(http::put(a, testURI + "/111", ch)); + assert(rc == value(true)); + return true; +} + +const bool testDel() { + gc_scoped_pool pool; + http::CURLSession ch; + value rc = content(http::del(testURI + "/111", ch)); + assert(rc == value(true)); + return true; +} + +const bool testServer() { + tuscany::server::testGet(); + tuscany::server::testPost(); + tuscany::server::testPut(); + tuscany::server::testDel(); + tuscany::server::testEval(); + tuscany::server::testGetPerf(); + tuscany::server::testPostPerf(); +#ifdef WANT_THREADS + tuscany::server::testPostThreadPerf(); +#else + tuscany::server::testPostForkPerf(); +#endif + tuscany::server::testEvalPerf(); + return true; +} + +} +} diff --git a/sca-cpp/branches/cpp-contrib/modules/server/client-test.scm b/sca-cpp/branches/cpp-contrib/modules/server/client-test.scm new file mode 100644 index 0000000000..47b799d390 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/modules/server/client-test.scm @@ -0,0 +1,38 @@ +; 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. + +; JSON-RPC test case + +(define (echo x ref) (ref "echo" x)) + +; ATOMPub test case + +(define (get id ref) + (ref "get" id) +) + +(define (post coll entry ref) + (ref "post" coll entry) +) + +(define (put id entry ref) + (ref "put" id entry) +) + +(define (delete id ref) + (ref "delete" id) +) diff --git a/sca-cpp/branches/cpp-contrib/modules/server/cpp-conf b/sca-cpp/branches/cpp-contrib/modules/server/cpp-conf new file mode 100755 index 0000000000..b376585f8c --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/modules/server/cpp-conf @@ -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. + +# Generate a C++ server conf +here=`readlink -f $0`; here=`dirname $here` +root=`readlink -f $1` + +cat >>$root/conf/httpd.conf <<EOF +LoadModule mod_tuscany_eval $here/.libs/libmod_tuscany_eval.so +EOF diff --git a/sca-cpp/branches/cpp-contrib/modules/server/domain-test.composite b/sca-cpp/branches/cpp-contrib/modules/server/domain-test.composite new file mode 100644 index 0000000000..ef85bb919b --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/modules/server/domain-test.composite @@ -0,0 +1,49 @@ +<?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://domain/test" + name="domain-test"> + + <component name="scheme-test"> + <t:implementation.scheme script="server-test.scm"/> + <service name="test"> + <t:binding.http uri="test"/> + </service> + </component> + + <component name="cpp-test"> + <implementation.cpp path=".libs" library="libimpl-test"/> + <service name="cpp"> + <t:binding.http uri="cpp"/> + </service> + </component> + + <component name="client-test"> + <t:implementation.scheme script="client-test.scm"/> + <service name="client"> + <t:binding.http uri="client"/> + </service> + <reference name="ref" target="scheme-test"> + <t:binding.http/> + </reference> + </component> + +</composite> diff --git a/sca-cpp/branches/cpp-contrib/modules/server/htdocs/entry.xml b/sca-cpp/branches/cpp-contrib/modules/server/htdocs/entry.xml new file mode 100644 index 0000000000..86b8a10547 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/modules/server/htdocs/entry.xml @@ -0,0 +1,2 @@ +<?xml version="1.0" encoding="UTF-8"?> +<entry xmlns="http://www.w3.org/2005/Atom"><title type="text">Item</title><id>111</id><content type="application/xml"><item><javaClass>services.Item</javaClass><name>Apple</name><currencyCode>USD</currencyCode><currencySymbol>$</currencySymbol><price>2.99</price></item></content><link href="111"/></entry> diff --git a/sca-cpp/branches/cpp-contrib/modules/server/htdocs/feed.xml b/sca-cpp/branches/cpp-contrib/modules/server/htdocs/feed.xml new file mode 100644 index 0000000000..5e37de6580 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/modules/server/htdocs/feed.xml @@ -0,0 +1,2 @@ +<?xml version="1.0" encoding="UTF-8"?> +<feed xmlns="http://www.w3.org/2005/Atom"><title type="text">Sample Feed</title><id>123456789</id><entry xmlns="http://www.w3.org/2005/Atom"><title type="text">Item</title><id>111</id><content type="application/xml"><item><javaClass>services.Item</javaClass><name>Apple</name><currencyCode>USD</currencyCode><currencySymbol>$</currencySymbol><price>2.99</price></item></content><link href="111"/></entry><entry xmlns="http://www.w3.org/2005/Atom"><title type="text">Item</title><id>222</id><content type="application/xml"><item><javaClass>services.Item</javaClass><name>Orange</name><currencyCode>USD</currencyCode><currencySymbol>$</currencySymbol><price>3.55</price></item></content><link href="222"/></entry><entry xmlns="http://www.w3.org/2005/Atom"><title type="text">Item</title><id>333</id><content type="application/xml"><item><javaClass>services.Item</javaClass><name>Pear</name><currencyCode>USD</currencyCode><currencySymbol>$</currencySymbol><price>1.55</price></item></content><link href="333"/></entry></feed> diff --git a/sca-cpp/branches/cpp-contrib/modules/server/htdocs/index.html b/sca-cpp/branches/cpp-contrib/modules/server/htdocs/index.html new file mode 100644 index 0000000000..1bfb3e30c2 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/modules/server/htdocs/index.html @@ -0,0 +1,21 @@ +<!-- + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +--> + +<html><body><h1>It works!</h1></body></html> + diff --git a/sca-cpp/branches/cpp-contrib/modules/server/htdocs/json-request.txt b/sca-cpp/branches/cpp-contrib/modules/server/htdocs/json-request.txt new file mode 100644 index 0000000000..b4bd07fc46 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/modules/server/htdocs/json-request.txt @@ -0,0 +1 @@ +{"id":1,"method":"echo","params":["Hello"]} diff --git a/sca-cpp/branches/cpp-contrib/modules/server/htdocs/json-result.txt b/sca-cpp/branches/cpp-contrib/modules/server/htdocs/json-result.txt new file mode 100644 index 0000000000..121bf74902 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/modules/server/htdocs/json-result.txt @@ -0,0 +1 @@ +{"id":1,"result":"Hello"}
\ No newline at end of file diff --git a/sca-cpp/branches/cpp-contrib/modules/server/httpd-test b/sca-cpp/branches/cpp-contrib/modules/server/httpd-test new file mode 100755 index 0000000000..86718f96c5 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/modules/server/httpd-test @@ -0,0 +1,76 @@ +#!/bin/sh + +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +echo "Testing..." + +# Setup +../http/httpd-conf tmp 8090 htdocs +./server-conf tmp +./scheme-conf tmp +cat >>tmp/conf/httpd.conf <<EOF +SCAContribution `pwd`/ +SCAComposite domain-test.composite +EOF + +../http/httpd-start tmp +sleep 2 + +# Test HTTP GET +curl http://localhost:8090/index.html 2>/dev/null >tmp/index.html +diff tmp/index.html htdocs/index.html +rc=$? + +# Test ATOMPub +if [ "$rc" = "0" ]; then + curl http://localhost:8090/test/ >tmp/feed.xml 2>/dev/null + diff tmp/feed.xml htdocs/feed.xml + rc=$? +fi +if [ "$rc" = "0" ]; then + curl http://localhost:8090/test/111 >tmp/entry.xml 2>/dev/null + diff tmp/entry.xml htdocs/entry.xml + rc=$? +fi +if [ "$rc" = "0" ]; then + curl http://localhost:8090/test/ -X POST -H "Content-type: application/atom+xml" --data @htdocs/entry.xml 2>/dev/null + rc=$? +fi +if [ "$rc" = "0" ]; then + curl http://localhost:8090/test/111 -X PUT -H "Content-type: application/atom+xml" --data @htdocs/entry.xml 2>/dev/null + rc=$? +fi +if [ "$rc" = "0" ]; then + curl http://localhost:8090/test/111 -X DELETE 2>/dev/null + rc=$? +fi + +# Test JSON-RPC +if [ "$rc" = "0" ]; then + curl http://localhost:8090/test/ -X POST -H "Content-type: application/json-rpc" --data @htdocs/json-request.txt >tmp/json-result.txt 2>/dev/null + diff tmp/json-result.txt htdocs/json-result.txt + rc=$? +fi + +# Cleanup +../http/httpd-stop tmp +sleep 2 +if [ "$rc" = "0" ]; then + echo "OK" +fi +return $rc diff --git a/sca-cpp/branches/cpp-contrib/modules/server/impl-test.cpp b/sca-cpp/branches/cpp-contrib/modules/server/impl-test.cpp new file mode 100644 index 0000000000..1bd0843745 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/modules/server/impl-test.cpp @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* $Rev$ $Date$ */ + +/** + * Test component implementation. + */ + +#include "string.hpp" + +#include "function.hpp" +#include "list.hpp" +#include "value.hpp" +#include "monad.hpp" + +namespace tuscany { +namespace server { + +const failable<value> get(unused const list<value>& params) { + return value(mklist<value>("text/html", mklist<value>("Hey"))); +} + +const failable<value> post(unused const list<value>& params) { + return value(mklist<value>(string("123456789"))); +} + +const failable<value> put(unused const list<value>& params) { + return value(true); +} + +const failable<value> del(unused const list<value>& params) { + return value(true); +} + +const failable<value> echo(const list<value>& params) { + return value(car(params)); +} + +} +} + +extern "C" { + +const tuscany::value apply(const tuscany::list<tuscany::value>& params) { + const tuscany::value func(car(params)); + if (func == "get") + return tuscany::server::get(cdr(params)); + if (func == "post") + return tuscany::server::post(cdr(params)); + if (func == "put") + return tuscany::server::put(cdr(params)); + if (func == "delete") + return tuscany::server::del(cdr(params)); + if (func == "echo") + return tuscany::server::echo(cdr(params)); + return tuscany::mkfailure<tuscany::value>(); +} + +} diff --git a/sca-cpp/branches/cpp-contrib/modules/server/mod-cpp.hpp b/sca-cpp/branches/cpp-contrib/modules/server/mod-cpp.hpp new file mode 100644 index 0000000000..b3828dd7d2 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/modules/server/mod-cpp.hpp @@ -0,0 +1,102 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* $Rev$ $Date$ */ + +#ifndef tuscany_modcpp_hpp +#define tuscany_modcpp_hpp + +/** + * Evaluation functions used by mod-eval to evaluate C++ + * component implementations. + */ + +#include "string.hpp" +#include "stream.hpp" + +#include "function.hpp" +#include "list.hpp" +#include "element.hpp" +#include "value.hpp" +#include "monad.hpp" +#include "dynlib.hpp" +#include "../scheme/driver.hpp" + +namespace tuscany { +namespace server { +namespace modcpp { + +/** + * Apply a C++ component implementation function. + */ +const list<value> failableResult(const value& func, const list<value>& v) { + if (isNil(cdr(v))) + return v; + + // Report a failure with an empty reason as 'function not supported' + // Except for the start, and stop functions, which are optional + const value reason = cadr(v); + if (length(reason) == 0) { + if (func == "start" || func == "stop") + return mklist<value>(lambda<value(const list<value>&)>()); + return mklist<value>(value(), string("Function not supported: ") + func); + } + return v; +} + +struct applyImplementation { + const lib ilib; + const lambda<value(const list<value>&)> impl; + const list<value> px; + applyImplementation(const lib& ilib, const lambda<value(const list<value>&)>& impl, const list<value>& px) : ilib(ilib), impl(impl), px(px) { + } + const value operator()(const list<value>& params) const { + debug(params, "modeval::cpp::applyImplementation::input"); + + // Apply the component implementation function + const value val = failableResult(car(params), impl(append(params, px))); + + debug(val, "modeval::cpp::applyImplementation::result"); + return val; + } +}; + +/** + * Evaluate a C++ component implementation and convert it to + * an applicable lambda function. + */ +const failable<lambda<value(const list<value>&)> > evalImplementation(const string& path, const value& impl, const list<value>& px) { + + // Configure the implementation's lambda function + const value ipath(attributeValue("path", impl)); + const value iname(attributeValue("library", impl)); + const string fpath(isNil(ipath)? path + iname : path + ipath + "/" + iname); + const lib ilib(*(new (gc_new<lib>()) lib(fpath + dynlibExt))); + const failable<lambda<value(const list<value>&)> > evalf(dynlambda<value(const list<value>&)>("apply", ilib)); + if (!hasContent(evalf)) + return evalf; + const lambda<value(const list<value>&)> l(applyImplementation(ilib, content(evalf), px)); + return l; +} + +} +} +} + +#endif /* tuscany_modcpp_hpp */ diff --git a/sca-cpp/branches/cpp-contrib/modules/server/mod-eval.cpp b/sca-cpp/branches/cpp-contrib/modules/server/mod-eval.cpp new file mode 100644 index 0000000000..a94ccf5bbe --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/modules/server/mod-eval.cpp @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* $Rev$ $Date$ */ + +/** + * HTTPD module used to eval C++ and Scheme component implementations. + */ + +#include "string.hpp" +#include "function.hpp" +#include "list.hpp" +#include "value.hpp" +#include "monad.hpp" +#include "mod-eval.hpp" +#include "mod-scheme.hpp" +#include "mod-cpp.hpp" + +namespace tuscany { +namespace server { +namespace modeval { + +/** + * Apply a lifecycle start or restart event. + */ +const value applyLifecycle(unused const list<value>& params) { + // Return a nil function as we don't need to handle any subsequent events + return failable<value>(lambda<value(const list<value>&)>()); +} + +/** + * Evaluate a Scheme or C++ component implementation and convert it to an + * applicable lambda function. + */ +const failable<lambda<value(const list<value>&)> > evalImplementation(const string& path, const value& impl, const list<value>& px, unused const lambda<value(const list<value>&)>& lifecycle) { + const string itype(elementName(impl)); + if (contains(itype, ".scheme")) + return modscheme::evalImplementation(path, impl, px); + if (contains(itype, ".cpp")) + return modcpp::evalImplementation(path, impl, px); + return mkfailure<lambda<value(const list<value>&)> >(string("Unsupported implementation type: ") + itype); +} + +} +} +} diff --git a/sca-cpp/branches/cpp-contrib/modules/server/mod-eval.hpp b/sca-cpp/branches/cpp-contrib/modules/server/mod-eval.hpp new file mode 100644 index 0000000000..f319942f8d --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/modules/server/mod-eval.hpp @@ -0,0 +1,583 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* $Rev$ $Date$ */ + +#ifndef tuscany_modeval_hpp +#define tuscany_modeval_hpp + +/** + * HTTPD module used to eval component implementations. + */ + +#include "string.hpp" +#include "stream.hpp" +#include "function.hpp" +#include "list.hpp" +#include "tree.hpp" +#include "value.hpp" +#include "element.hpp" +#include "monad.hpp" +#include "../atom/atom.hpp" +#include "../json/json.hpp" +#include "../scdl/scdl.hpp" +#include "../http/curl.hpp" +#include "../http/httpd.hpp" + +extern "C" { +extern module AP_MODULE_DECLARE_DATA mod_tuscany_eval; +} + +namespace tuscany { +namespace server { +namespace modeval { + +/** + * Server configuration. + */ +class ServerConf { +public: + ServerConf(server_rec* s) : s(s), home(""), wiringServerName(""), contributionPath(""), compositeName("") { + } + + const server_rec* s; + lambda<value(const list<value>&)> lifecycle; + string home; + string wiringServerName; + string contributionPath; + string compositeName; + list<value> implementations; + list<value> implTree; +}; + +/** + * Convert a result represented as a content + failure pair to a + * failable monad. + */ +const failable<value> failableResult(const list<value>& v) { + if (isNil(cdr(v))) + return car(v); + return mkfailure<value>(string(cadr(v))); +} + +/** + * Handle an HTTP GET. + */ +const failable<int> get(request_rec* r, const lambda<value(const list<value>&)>& impl) { + debug(r->uri, "modeval::get::uri"); + + // Inspect the query string + const list<list<value> > args = httpd::queryArgs(r); + const list<value> ia = assoc(value("id"), args); + const list<value> ma = assoc(value("method"), args); + + // Evaluate a JSON-RPC request and return a JSON result + if (!isNil(ia) && !isNil(ma)) { + + // Extract the request id, method and params + const value id = cadr(ia); + const value func = c_str(json::funcName(string(cadr(ma)))); + + // Apply the requested function + const failable<value> val = failableResult(impl(cons(func, httpd::queryParams(args)))); + if (!hasContent(val)) + return mkfailure<int>(reason(val)); + + // Return JSON result + json::JSONContext cx; + return httpd::writeResult(json::jsonResult(id, content(val), cx), "application/json-rpc", r); + } + + // Evaluate the GET expression + const list<value> path(pathValues(r->uri)); + const failable<value> val = failableResult(impl(cons<value>("get", mklist<value>(cddr(path))))); + if (!hasContent(val)) + return mkfailure<int>(reason(val)); + const value c = content(val); + + // Write returned content-type / content-list pair + if (isList(cadr<value>(c))) + return httpd::writeResult(convertValues<string>(cadr<value>(c)), car<value>(c), r); + + // Write returned ATOM feed or entry + if (isNil(cddr(path))) + return httpd::writeResult(atom::writeATOMFeed(atom::feedValuesToElements(c)), "application/atom+xml;type=feed", r); + else + return httpd::writeResult(atom::writeATOMEntry(atom::entryValuesToElements(c)), "application/atom+xml;type=entry", r); +} + +/** + * Handle an HTTP POST. + */ +const failable<int> post(request_rec* r, const lambda<value(const list<value>&)>& impl) { + debug(r->uri, "modeval::post::url"); + + // Evaluate a JSON-RPC request and return a JSON result + const string ct = httpd::contentType(r); + if (contains(ct, "application/json-rpc") || contains(ct, "text/plain")) { + + // Read the JSON request + const int rc = httpd::setupReadPolicy(r); + if(rc != OK) + return rc; + const list<string> ls = httpd::read(r); + debug(ls, "modeval::post::input"); + json::JSONContext cx; + const list<value> json = elementsToValues(content(json::readJSON(ls, cx))); + const list<list<value> > args = httpd::postArgs(json); + + // Extract the request id, method and params + const value id = cadr(assoc(value("id"), args)); + const value func = c_str(json::funcName(cadr(assoc(value("method"), args)))); + const list<value> params = (list<value>)cadr(assoc(value("params"), args)); + + // Evaluate the request expression + const failable<value> val = failableResult(impl(cons<value>(func, params))); + if (!hasContent(val)) + return mkfailure<int>(reason(val)); + + // Return JSON result + return httpd::writeResult(json::jsonResult(id, content(val), cx), "application/json-rpc", r); + } + + // Evaluate an ATOM POST request and return the location of the corresponding created resource + if (contains(ct, "application/atom+xml")) { + + // Read the ATOM entry + const list<value> path(pathValues(r->uri)); + const int rc = httpd::setupReadPolicy(r); + if(rc != OK) + return rc; + const list<string> ls = httpd::read(r); + debug(ls, "modeval::post::input"); + const value entry = atom::entryValue(content(atom::readEntry(ls))); + + // Evaluate the POST expression + const failable<value> val = failableResult(impl(cons<value>("post", mklist<value>(cddr(path), entry)))); + if (!hasContent(val)) + return mkfailure<int>(reason(val)); + + // Return the created resource location + debug(content(val), "modeval::post::location"); + apr_table_setn(r->headers_out, "Location", apr_pstrdup(r->pool, httpd::url(content(val), r))); + r->status = HTTP_CREATED; + return OK; + } + + // Unknown content type, wrap the HTTP request struct in a value and pass it to + // the component implementation function + const failable<value> val = failableResult(impl(cons<value>("handle", mklist<value>(httpd::requestValue(r))))); + if (!hasContent(val)) + return mkfailure<int>(reason(val)); + return (int)content(val); +} + +/** + * Handle an HTTP PUT. + */ +const failable<int> put(request_rec* r, const lambda<value(const list<value>&)>& impl) { + debug(r->uri, "modeval::put::url"); + + // Read the ATOM entry + const list<value> path(pathValues(r->uri)); + const int rc = httpd::setupReadPolicy(r); + if(rc != OK) + return rc; + const list<string> ls = httpd::read(r); + debug(ls, "modeval::put::input"); + const value entry = atom::entryValue(content(atom::readEntry(ls))); + + // Evaluate the PUT expression and update the corresponding resource + const failable<value> val = failableResult(impl(cons<value>("put", mklist<value>(cddr(path), entry)))); + if (!hasContent(val)) + return mkfailure<int>(reason(val)); + if (val == value(false)) + return HTTP_NOT_FOUND; + return OK; +} + +/** + * Handle an HTTP DELETE. + */ +const failable<int> del(request_rec* r, const lambda<value(const list<value>&)>& impl) { + debug(r->uri, "modeval::delete::url"); + + // Evaluate an ATOM delete request + const list<value> path(pathValues(r->uri)); + const failable<value> val = failableResult(impl(cons<value>("delete", mklist<value>(cddr(path))))); + if (!hasContent(val)) + return mkfailure<int>(reason(val)); + if (val == value(false)) + return HTTP_NOT_FOUND; + return OK; +} + +/** + * Translate a component request. + */ +int translate(request_rec *r) { + gc_scoped_pool pool(r->pool); + if (strncmp(r->uri, "/components/", 12) != 0) + return DECLINED; + r->handler = "mod_tuscany_eval"; + return OK; +} + +/** + * HTTP request handler. + */ +int handler(request_rec *r) { + gc_scoped_pool pool(r->pool); + if(strcmp(r->handler, "mod_tuscany_eval")) + return DECLINED; + httpdDebugRequest(r, "modeval::handler::input"); + + // Get the component implementation lambda + const ServerConf& sc = httpd::serverConf<ServerConf>(r, &mod_tuscany_eval); + const list<value> path(pathValues(r->uri)); + const list<value> impl(assoctree<value>(cadr(path), sc.implTree)); + if (isNil(impl)) + return HTTP_NOT_FOUND; + + // Handle HTTP method + const lambda<value(const list<value>&)> l(cadr<value>(impl)); + if (r->header_only) + return OK; + if(r->method_number == M_GET) + return httpd::reportStatus(get(r, l)); + if(r->method_number == M_POST) + return httpd::reportStatus(post(r, l)); + if(r->method_number == M_PUT) + return httpd::reportStatus(put(r, l)); + if(r->method_number == M_DELETE) + return httpd::reportStatus(del(r, l)); + return HTTP_NOT_IMPLEMENTED; +} + +/** + * Convert a list of component references to a list of HTTP proxy lambdas. + */ +const value mkrefProxy(const value& ref, const string& base) { + return lambda<value(const list<value>&)>(http::proxy(base + string(scdl::name(ref)))); +} + +const list<value> refProxies(const list<value>& refs, const string& base) { + if (isNil(refs)) + return refs; + return cons(mkrefProxy(car(refs), base), refProxies(cdr(refs), base)); +} + +/** + * Convert a list of component properties to a list of lambda functions that just return + * the property value. + */ +struct propProxy { + const value v; + propProxy(const value& v) : v(v) { + } + const value operator()(unused const list<value>& params) const { + return v; + } +}; + +const value mkpropProxy(const value& prop) { + return lambda<value(const list<value>&)>(propProxy(elementValue(prop))); +} + +const list<value> propProxies(const list<value>& props) { + if (isNil(props)) + return props; + return cons(mkpropProxy(car(props)), propProxies(cdr(props))); +} + +/** + * Evaluate a component and convert it to an applicable lambda function. + */ +const value evalComponent(ServerConf& sc, server_rec& server, const value& comp) { + extern const failable<lambda<value(const list<value>&)> > evalImplementation(const string& cpath, const value& impl, const list<value>& px, const lambda<value(const list<value>&)>& lifecycle); + + const value impl = scdl::implementation(comp); + + // Convert component references to configured proxy lambdas + ostringstream base; + if (sc.wiringServerName == "") + base << (server.server_scheme == NULL? "http" : server.server_scheme) + << "://" << (server.server_hostname == NULL? "localhost" : server.server_hostname) + << ":" << (server.port == 0? 80 : server.port) + << "/references/" << string(scdl::name(comp)) << "/"; + else + base << sc.wiringServerName << "/references/" << string(scdl::name(comp)) << "/"; + const list<value> rpx(refProxies(scdl::references(comp), str(base))); + + // Convert component proxies to configured proxy lambdas + const list<value> ppx(propProxies(scdl::properties(comp))); + + // Evaluate the component implementation and convert it to an applicable lambda function + const failable<lambda<value(const list<value>&)> > cimpl(evalImplementation(sc.contributionPath, impl, append(rpx, ppx), sc.lifecycle)); + if (!hasContent(cimpl)) + return reason(cimpl); + return content(cimpl); +} + +/** + * Return a list of component-name + configured-implementation pairs. + */ +const list<value> componentToImplementationAssoc(ServerConf& sc, server_rec& server, const list<value>& c) { + if (isNil(c)) + return c; + return cons<value>(mklist<value>(scdl::name(car(c)), evalComponent(sc, server, car(c))), componentToImplementationAssoc(sc, server, cdr(c))); +} + +/** + * Read the components declared in a composite. + */ +const failable<list<value> > readComponents(const string& path) { + ifstream is(path); + if (fail(is)) + return mkfailure<list<value> >(string("Could not read composite: ") + path); + return scdl::components(readXML(streamList(is))); +} + +/** + * Apply a list of component implementations to a start or restart lifecycle expression. + * Return the functions returned by the component implementations. + */ +const failable<list<value> > applyLifecycleExpr(const list<value>& impls, const list<value>& expr) { + if (isNil(impls)) + return list<value>(); + + // Evaluate lifecycle expression against a component implementation lambda + const lambda<value(const list<value>&)> l = cadr<value>(car(impls)); + const failable<value> r = failableResult(l(expr)); + if (!hasContent(r)) + return mkfailure<list<value> >(reason(r)); + const lambda<value(const list<value>&)> rl = content(r); + + // Use the returned lambda function, if any, from now on + const lambda<value(const list<value>&)> al = isNil(rl)? l : rl; + + // Continue with the rest of the list + const failable<list<value> > nr = applyLifecycleExpr(cdr(impls), expr); + if (!hasContent(nr)) + return nr; + return cons<value>(mklist<value>(car<value>(car(impls)), value(al)), content(nr)); +} + +/** + * Configure the components declared in the deployed composite. + */ +const failable<bool> confComponents(ServerConf& sc, server_rec& server) { + if (sc.contributionPath == "" || sc.compositeName == "") + return false; + + // Read the components and get their implementation lambda functions + const failable<list<value> > comps = readComponents(sc.contributionPath + sc.compositeName); + if (!hasContent(comps)) + return mkfailure<bool>(reason(comps)); + sc.implementations = componentToImplementationAssoc(sc, server, content(comps)); + debug(sc.implementations, "modeval::confComponents::implementations"); + + // Store the implementation lambda functions in a tree for fast retrieval + sc.implTree = mkbtree(sort(sc.implementations)); + return true; +} + +/** + * Start the components declared in the deployed composite. + */ +const failable<bool> startComponents(ServerConf& sc) { + + // Start the components and record the returned implementation lambda functions + debug(sc.implementations, "modeval::startComponents::start"); + const failable<list<value> > impls = applyLifecycleExpr(sc.implementations, mklist<value>("start")); + if (!hasContent(impls)) + return mkfailure<bool>(reason(impls)); + sc.implementations = content(impls); + debug(sc.implementations, "modeval::startComponents::implementations"); + + // Store the implementation lambda functions in a tree for fast retrieval + sc.implTree = mkbtree(sort(sc.implementations)); + return true; +} + +/** + * Cleanup callback, called when the server is stopped or restarted. + */ +apr_status_t serverCleanup(void* v) { + gc_pool pool; + ServerConf& sc = *(ServerConf*)v; + debug("modeval::serverCleanup"); + + // Stop the component implementations + applyLifecycleExpr(sc.implementations, mklist<value>("stop")); + + // Call the module lifecycle function + if (isNil(sc.lifecycle)) + return APR_SUCCESS; + debug("modeval::serverCleanup::stop"); + sc.lifecycle(mklist<value>("stop")); + + return APR_SUCCESS; +} + +/** + * Called after all the configuration commands have been run. + * Process the server configuration and configure the deployed components. + */ +int postConfig(apr_pool_t *p, unused apr_pool_t *plog, unused apr_pool_t *ptemp, server_rec *s) { + extern const value applyLifecycle(const list<value>&); + + gc_scoped_pool pool(p); + ServerConf& sc = httpd::serverConf<ServerConf>(s, &mod_tuscany_eval); + + // Count the calls to post config + const string k("tuscany::modeval::postConfig"); + const int count = (int)httpd::userData(k, s); + httpd::putUserData(k, (void*)(count + 1), s); + + // Count == 0, do nothing as post config is always called twice, + // count == 1 is the first start, count > 1 is a restart + if (count == 0) + return OK; + if (count == 1) { + debug("modeval::postConfig::start"); + const failable<value> r = failableResult(applyLifecycle(mklist<value>("start"))); + if (!hasContent(r)) + return -1; + sc.lifecycle = content(r); + } + if (count > 1) { + debug("modeval::postConfig::restart"); + const failable<value> r = failableResult(applyLifecycle(mklist<value>("restart"))); + if (!hasContent(r)) + return -1; + sc.lifecycle = content(r); + } + + // Configure the deployed components + debug(sc.wiringServerName, "modeval::postConfig::wiringServerName"); + debug(sc.contributionPath, "modeval::postConfig::contributionPath"); + debug(sc.compositeName, "modeval::postConfig::compositeName"); + const failable<bool> res = confComponents(sc, *s); + if (!hasContent(res)) { + cerr << "[Tuscany] Due to one or more errors mod_tuscany_eval loading failed. Causing apache to stop loading." << endl; + return -1; + } + + // Register a cleanup callback, called when the server is stopped or restarted + apr_pool_pre_cleanup_register(p, (void*)&sc, serverCleanup); + + return OK; +} + +/** + * Child process initialization. + */ +void childInit(apr_pool_t* p, server_rec* s) { + gc_scoped_pool pool(p); + ServerConf* sc = (ServerConf*)ap_get_module_config(s->module_config, &mod_tuscany_eval); + if(sc == NULL) { + cerr << "[Tuscany] Due to one or more errors mod_tuscany_eval loading failed. Causing apache to stop loading." << endl; + exit(APEXIT_CHILDFATAL); + } + + // Start the components in the child process + const failable<bool> res = startComponents(*sc); + if (!hasContent(res)) { + cerr << "[Tuscany] Due to one or more errors mod_tuscany_eval loading failed. Causing apache to stop loading." << endl; + exit(APEXIT_CHILDFATAL); + } + + // Register a cleanup callback, called when the child is stopped or restarted + apr_pool_pre_cleanup_register(p, (void*)sc, serverCleanup); +} + +/** + * Configuration commands. + */ +const char* confHome(cmd_parms *cmd, unused void *c, const char *arg) { + gc_scoped_pool pool(cmd->pool); + ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_eval); + sc.home = arg; + return NULL; +} +const char* confWiringServerName(cmd_parms *cmd, unused void *c, const char *arg) { + gc_scoped_pool pool(cmd->pool); + ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_eval); + sc.wiringServerName = arg; + return NULL; +} +const char* confContribution(cmd_parms *cmd, unused void *c, const char *arg) { + gc_scoped_pool pool(cmd->pool); + ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_eval); + sc.contributionPath = arg; + return NULL; +} +const char* confComposite(cmd_parms *cmd, unused void *c, const char *arg) { + gc_scoped_pool pool(cmd->pool); + ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_eval); + sc.compositeName = arg; + return NULL; +} + +const char* confEnv(unused cmd_parms *cmd, unused void *c, const char *name, const char *value) { + gc_scoped_pool pool(cmd->pool); + setenv(name, value != NULL? value : "", 1); + return NULL; +} + +/** + * HTTP server module declaration. + */ +const command_rec commands[] = { + AP_INIT_TAKE1("TuscanyHome", (const char*(*)())confHome, NULL, RSRC_CONF, "Tuscany home directory"), + AP_INIT_TAKE1("SCAWiringServerName", (const char*(*)())confWiringServerName, NULL, RSRC_CONF, "SCA wiring server name"), + AP_INIT_TAKE1("SCAContribution", (const char*(*)())confContribution, NULL, RSRC_CONF, "SCA contribution location"), + AP_INIT_TAKE1("SCAComposite", (const char*(*)())confComposite, NULL, RSRC_CONF, "SCA composite location"), + AP_INIT_TAKE12("SetEnv", (const char*(*)())confEnv, NULL, OR_FILEINFO, "Environment variable name and optional value"), + {NULL, NULL, NULL, 0, NO_ARGS, NULL} +}; + + +void registerHooks(unused apr_pool_t *p) { + ap_hook_post_config(postConfig, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_child_init(childInit, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_handler(handler, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_translate_name(translate, NULL, NULL, APR_HOOK_FIRST); +} + +} +} +} + +extern "C" { + +module AP_MODULE_DECLARE_DATA mod_tuscany_eval = { + STANDARD20_MODULE_STUFF, + // dir config and merger + NULL, NULL, + // server config and merger + tuscany::httpd::makeServerConf<tuscany::server::modeval::ServerConf>, NULL, + // commands and hooks + tuscany::server::modeval::commands, tuscany::server::modeval::registerHooks +}; + +} + +#endif diff --git a/sca-cpp/branches/cpp-contrib/modules/server/mod-scheme.hpp b/sca-cpp/branches/cpp-contrib/modules/server/mod-scheme.hpp new file mode 100644 index 0000000000..f5b9554c3f --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/modules/server/mod-scheme.hpp @@ -0,0 +1,89 @@ +/* + * 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_modscheme_hpp +#define tuscany_modscheme_hpp + +/** + * Evaluation functions used by mod-eval to evaluate Scheme + * component implementations. + */ + +#include "string.hpp" +#include "stream.hpp" +#include "function.hpp" +#include "list.hpp" +#include "value.hpp" +#include "monad.hpp" +#include "../scheme/eval.hpp" + +namespace tuscany { +namespace server { +namespace modscheme { + +/** + * Convert proxy lambdas to evaluator primitive procedures. + */ +const list<value> primitiveProcedures(const list<value>& l) { + if (isNil(l)) + return l; + return cons<value>(mklist<value>(scheme::primitiveSymbol, car(l)), primitiveProcedures(cdr(l))); +} + +/** + * Apply a Scheme component implementation function. + */ +struct applyImplementation { + const value impl; + const list<value> px; + applyImplementation(const value& impl, const list<value>& px) : impl(impl), px(scheme::quotedParameters(primitiveProcedures(px))) { + } + const value operator()(const list<value>& params) const { + const value expr = cons<value>(car(params), append(scheme::quotedParameters(cdr(params)), px)); + debug(expr, "modeval::scheme::applyImplementation::input"); + scheme::Env env = scheme::setupEnvironment(); + const value res = scheme::evalScript(expr, impl, env); + const value val = isNil(res)? mklist<value>(value(), string("Could not evaluate expression")) : mklist<value>(res); + debug(val, "modeval::scheme::applyImplementation::result"); + return val; + } +}; + +/** + * Evaluate a Scheme component implementation and convert it to an + * applicable lambda function. + */ +const failable<lambda<value(const list<value>&)> > evalImplementation(const string& path, const value& impl, const list<value>& px) { + const string fpath(path + attributeValue("script", impl)); + ifstream is(fpath); + if (fail(is)) + return mkfailure<lambda<value(const list<value>&)> >(string("Could not read implementation: ") + fpath); + const value script = scheme::readScript(is); + if (isNil(script)) + return mkfailure<lambda<value(const list<value>&)> >(string("Could not read implementation: ") + fpath); + return lambda<value(const list<value>&)>(applyImplementation(script, px)); +} + +} +} +} + +#endif /* tuscany_modscheme_hpp */ diff --git a/sca-cpp/branches/cpp-contrib/modules/server/mod-wiring.cpp b/sca-cpp/branches/cpp-contrib/modules/server/mod-wiring.cpp new file mode 100644 index 0000000000..c21b0fe254 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/modules/server/mod-wiring.cpp @@ -0,0 +1,383 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* $Rev$ $Date$ */ + +/** + * HTTPD module used to wire component references and route requests to + * target service components. + */ + +#include <sys/stat.h> + +#include "string.hpp" +#include "stream.hpp" +#include "list.hpp" +#include "tree.hpp" +#include "value.hpp" +#include "monad.hpp" +#include "../scdl/scdl.hpp" +#include "../http/httpd.hpp" + +extern "C" { +extern module AP_MODULE_DECLARE_DATA mod_tuscany_wiring; +} + +namespace tuscany { +namespace server { +namespace modwiring { + +/** + * Server configuration. + */ +class ServerConf { +public: + ServerConf(server_rec* s) : s(s), start(false), home(""), wiringServerName(""), contributionPath(""), compositeName("") { + } + const server_rec* s; + bool start; + string home; + string wiringServerName; + string contributionPath; + string compositeName; + list<value> references; + list<value> services; +}; + +/** + * Set to true to wire using mod_proxy, false to wire using HTTP client redirects. + */ +const bool useModProxy = true; + +/** + * Returns true if a URI is absolute. + */ +const bool isAbsolute(const string& uri) { + return contains(uri, "://"); +} + +/** + * Route a /references/component-name/reference-name request, + * to the target of the component reference. + */ +int translateReference(request_rec *r) { + httpdDebugRequest(r, "modwiring::translateReference::input"); + debug(r->uri, "modwiring::translateReference::uri"); + + // Find the requested component + const ServerConf& sc = httpd::serverConf<ServerConf>(r, &mod_tuscany_wiring); + const list<value> rpath(pathValues(r->uri)); + const list<value> comp(assoctree(cadr(rpath), sc.references)); + if (isNil(comp)) + return HTTP_NOT_FOUND; + + // Find the requested reference and target configuration + const list<value> ref(assoctree<value>(caddr(rpath), cadr(comp))); + if (isNil(ref)) + return HTTP_NOT_FOUND; + const string target(cadr(ref)); + debug(target, "modwiring::translateReference::target"); + + // Route to an absolute target URI using mod_proxy or an HTTP client redirect + if (isAbsolute(target)) { + if (useModProxy) { + r->filename = apr_pstrdup(r->pool, c_str(string("proxy:") + target)); + r->proxyreq = PROXYREQ_REVERSE; + r->handler = "proxy-server"; + return OK; + } + + r->status = HTTP_MOVED_TEMPORARILY; + apr_table_setn(r->headers_out, "Location", apr_pstrdup(r->pool, c_str(target))); + r->handler = "mod_tuscany_wiring"; + return OK; + } + + // Route to a relative target URI using a local internal redirect + r->filename = apr_pstrdup(r->pool, c_str(string("/redirect:/components/") + target)); + r->handler = "mod_tuscany_wiring"; + return OK; +} + +/** + * Find a leaf matching a request path in a tree of URI paths. + */ +const int matchPath(const list<value>& k, const list<value>& p) { + if (isNil(p)) + return true; + if (isNil(k)) + return false; + if (car(k) != car(p)) + return false; + return matchPath(cdr(k), cdr(p)); +} + +const list<value> assocPath(const value& k, const list<value>& tree) { + if (isNil(tree)) + return tree; + if (matchPath(k, car<value>(car(tree)))) + return car(tree); + if (k < car<value>(car(tree))) + return assocPath(k, cadr(tree)); + return assocPath(k, caddr(tree)); +} + +/** + * Route a service request to the component providing the requested service. + */ +int translateService(request_rec *r) { + httpdDebugRequest(r, "modwiring::translateService::input"); + debug(r->uri, "modwiring::translateService::uri"); + + // Find the requested component + const ServerConf& sc = httpd::serverConf<ServerConf>(r, &mod_tuscany_wiring); + const list<value> p(pathValues(r->uri)); + const list<value> svc(assocPath(p, sc.services)); + if (isNil(svc)) + return DECLINED; + debug(svc, "modwiring::translateService::service"); + + // Build a component-name + path-info URI + const list<value> target(cons<value>(cadr(svc), httpd::pathInfo(p, car(svc)))); + debug(target, "modwiring::translateService::target"); + + // Dispatch to the target component using a local internal redirect + const string tp(path(target)); + debug(tp, "modwiring::translateService::path"); + const string redir(string("/redirect:/components") + tp); + debug(redir, "modwiring::translateService::redirect"); + r->filename = apr_pstrdup(r->pool, c_str(redir)); + r->handler = "mod_tuscany_wiring"; + return OK; +} + +/** + * Translate an HTTP service or reference request and route it + * to the target component. + */ +int translate(request_rec *r) { + gc_scoped_pool pool(r->pool); + if (!strncmp(r->uri, "/components/", 12) != 0) + return DECLINED; + + // Translate a component reference request + if (!strncmp(r->uri, "/references/", 12) != 0) + return translateReference(r); + + // Translate a service request + return translateService(r); +} + +/** + * HTTP request handler, redirect to a target component. + */ +int handler(request_rec *r) { + gc_scoped_pool pool(r->pool); + if(strcmp(r->handler, "mod_tuscany_wiring")) + return DECLINED; + httpdDebugRequest(r, "modwiring::handler::input"); + + // Do an internal redirect + if (r->filename == NULL || strncmp(r->filename, "/redirect:", 10) != 0) + return DECLINED; + debug(r->uri, "modwiring::handler::uri"); + debug(r->filename, "modwiring::handler::filename"); + debug(r->path_info, "modwiring::handler::path info"); + + if (r->args == NULL) + return httpd::internalRedirect(httpd::redirectURI(string(r->filename + 10), string(r->path_info)), r); + return httpd::internalRedirect(httpd::redirectURI(string(r->filename + 10), string(r->path_info), string(r->args)), r); +} + +/** + * Read the components declared in a composite. + */ +const failable<list<value> > readComponents(const string& path) { + ifstream is(path); + if (fail(is)) + return mkfailure<list<value> >(string("Could not read composite: ") + path); + return scdl::components(readXML(streamList(is))); +} + +/** + * Return a list of component-name + references pairs. The references are + * arranged in trees of reference-name + reference-target pairs. + */ +const list<value> componentReferenceToTargetTree(const value& c) { + return mklist<value>(scdl::name(c), mkbtree(sort(scdl::referenceToTargetAssoc(scdl::references(c))))); +} + +const list<value> componentReferenceToTargetAssoc(const list<value>& c) { + if (isNil(c)) + return c; + return cons<value>(componentReferenceToTargetTree(car(c)), componentReferenceToTargetAssoc(cdr(c))); +} + +/** + * Return a list of service-URI-path + component-name pairs. Service-URI-paths are + * represented as lists of URI path fragments. + */ +const list<value> defaultBindingURI(const string& cn, const string& sn) { + return mklist<value>(cn, sn); +} + +const list<value> bindingToComponentAssoc(const string& cn, const string& sn, const list<value>& b) { + if (isNil(b)) + return b; + const value uri(scdl::uri(car(b))); + if (isNil(uri)) + return cons<value>(mklist<value>(defaultBindingURI(cn, sn), cn), bindingToComponentAssoc(cn, sn, cdr(b))); + return cons<value>(mklist<value>(pathValues(c_str(string(uri))), cn), bindingToComponentAssoc(cn, sn, cdr(b))); +} + +const list<value> serviceToComponentAssoc(const string& cn, const list<value>& s) { + if (isNil(s)) + return s; + const string sn(scdl::name(car(s))); + const list<value> btoc(bindingToComponentAssoc(cn, sn, scdl::bindings(car(s)))); + if (isNil(btoc)) + return cons<value>(mklist<value>(defaultBindingURI(cn, sn), cn), serviceToComponentAssoc(cn, cdr(s))); + return append<value>(btoc, serviceToComponentAssoc(cn, cdr(s))); +} + +const list<value> uriToComponentAssoc(const list<value>& c) { + if (isNil(c)) + return c; + return append<value>(serviceToComponentAssoc(scdl::name(car(c)), scdl::services(car(c))), uriToComponentAssoc(cdr(c))); +} + +/** + * Configure the components declared in the server's deployment composite. + */ +const bool confComponents(ServerConf& sc) { + if (sc.contributionPath == "" || sc.compositeName == "") + return true; + + // Read the component configuration and store the references and service URIs + // in trees for fast retrieval later + const failable<list<value> > comps = readComponents(sc.contributionPath + sc.compositeName); + if (!hasContent(comps)) + return true; + const list<value> refs = componentReferenceToTargetAssoc(content(comps)); + debug(refs, "modwiring::confComponents::references"); + sc.references = mkbtree(sort(refs)); + + const list<value> svcs = uriToComponentAssoc(content(comps)); + debug(svcs, "modwiring::confComponents::services"); + sc.services = mkbtree(sort(svcs)); + return true; +} + +/** + * Called after all the configuration commands have been run. + * Process the server configuration and configure the wiring for the deployed components. + */ +int postConfig(unused apr_pool_t *p, unused apr_pool_t *plog, unused apr_pool_t *ptemp, server_rec *s) { + // Count the calls to post config, skip the first one as + // postConfig is always called twice + const string k("tuscany::modwiring::postConfig"); + const int count = (int)httpd::userData(k, s); + httpd::putUserData(k, (void*)(count + 1), s); + if (count == 0) + return OK; + + // Configure the wiring for the deployed components + ServerConf& sc = httpd::serverConf<ServerConf>(s, &mod_tuscany_wiring); + debug(sc.wiringServerName, "modwiring::postConfig::wiringServerName"); + debug(sc.contributionPath, "modwiring::postConfig::contributionPath"); + debug(sc.compositeName, "modwiring::postConfig::compositeName"); + confComponents(sc); + return OK; +} + +/** + * Child process initialization. + */ +void childInit(apr_pool_t* p, server_rec* svr_rec) { + gc_scoped_pool pool(p); + ServerConf *conf = (ServerConf*)ap_get_module_config(svr_rec->module_config, &mod_tuscany_wiring); + if(conf == NULL) { + cerr << "[Tuscany] Due to one or more errors mod_tuscany_wiring loading failed. Causing apache to stop loading." << endl; + exit(APEXIT_CHILDFATAL); + } +} + +/** + * Configuration commands. + */ +const char *confHome(cmd_parms *cmd, unused void *c, const char *arg) { + gc_scoped_pool pool(cmd->pool); + ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_wiring); + sc.home = arg; + return NULL; +} +const char *confWiringServerName(cmd_parms *cmd, unused void *c, const char *arg) { + gc_scoped_pool pool(cmd->pool); + ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_wiring); + sc.wiringServerName = arg; + return NULL; +} +const char *confContribution(cmd_parms *cmd, unused void *c, const char *arg) { + gc_scoped_pool pool(cmd->pool); + ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_wiring); + sc.contributionPath = arg; + return NULL; +} +const char *confComposite(cmd_parms *cmd, unused void *c, const char *arg) { + gc_scoped_pool pool(cmd->pool); + ServerConf& sc = httpd::serverConf<ServerConf>(cmd, &mod_tuscany_wiring); + sc.compositeName = arg; + return NULL; +} + +/** + * HTTP server module declaration. + */ +const command_rec commands[] = { + AP_INIT_TAKE1("TuscanyHome", (const char*(*)())confHome, NULL, RSRC_CONF, "Tuscany home directory"), + AP_INIT_TAKE1("SCAWiringServerName", (const char*(*)())confWiringServerName, NULL, RSRC_CONF, "SCA wiring server name"), + AP_INIT_TAKE1("SCAContribution", (const char*(*)())confContribution, NULL, RSRC_CONF, "SCA contribution location"), + AP_INIT_TAKE1("SCAComposite", (const char*(*)())confComposite, NULL, RSRC_CONF, "SCA composite location"), + {NULL, NULL, NULL, 0, NO_ARGS, NULL} +}; + +void registerHooks(unused apr_pool_t *p) { + ap_hook_post_config(postConfig, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_child_init(childInit, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_handler(handler, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_translate_name(translate, NULL, NULL, APR_HOOK_FIRST); +} + +} +} +} + +extern "C" { + +module AP_MODULE_DECLARE_DATA mod_tuscany_wiring = { + STANDARD20_MODULE_STUFF, + // dir config and merger + NULL, NULL, + // server config and merger + tuscany::httpd::makeServerConf<tuscany::server::modwiring::ServerConf>, NULL, + // commands and hooks + tuscany::server::modwiring::commands, tuscany::server::modwiring::registerHooks +}; + +} diff --git a/sca-cpp/branches/cpp-contrib/modules/server/scheme-conf b/sca-cpp/branches/cpp-contrib/modules/server/scheme-conf new file mode 100755 index 0000000000..248255608e --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/modules/server/scheme-conf @@ -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. + +# Generate a Scheme server conf +here=`readlink -f $0`; here=`dirname $here` +root=`readlink -f $1` + +cat >>$root/conf/httpd.conf <<EOF +LoadModule mod_tuscany_eval $here/.libs/libmod_tuscany_eval.so +EOF diff --git a/sca-cpp/branches/cpp-contrib/modules/server/server-conf b/sca-cpp/branches/cpp-contrib/modules/server/server-conf new file mode 100755 index 0000000000..ae175ee2f8 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/modules/server/server-conf @@ -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. + +# Generate a server conf +here=`readlink -f $0`; here=`dirname $here` +root=`readlink -f $1` + +mkdir -p $root +mkdir -p $root/logs +mkdir -p $root/conf +cat >>$root/conf/httpd.conf <<EOF +LoadModule mod_tuscany_wiring $here/.libs/libmod_tuscany_wiring.so +EOF diff --git a/sca-cpp/branches/cpp-contrib/modules/server/server-test b/sca-cpp/branches/cpp-contrib/modules/server/server-test new file mode 100755 index 0000000000..e1d9932a5d --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/modules/server/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 +../http/httpd-conf tmp 8090 htdocs +./server-conf tmp +./scheme-conf tmp +cat >>tmp/conf/httpd.conf <<EOF +SCAContribution `pwd`/ +SCAComposite domain-test.composite +EOF + +../http/httpd-start tmp +sleep 2 + +# Test +./client-test 2>/dev/null +rc=$? + +# Cleanup +../http/httpd-stop tmp +sleep 2 +return $rc diff --git a/sca-cpp/branches/cpp-contrib/modules/server/server-test.scm b/sca-cpp/branches/cpp-contrib/modules/server/server-test.scm new file mode 100644 index 0000000000..5d545ecf8b --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/modules/server/server-test.scm @@ -0,0 +1,44 @@ +; Licensed to the Apache Software Foundation (ASF) under one +; or more contributor license agreements. See the NOTICE file +; distributed with this work for additional information +; regarding copyright ownership. The ASF licenses this file +; to you under the Apache License, Version 2.0 (the +; "License"); you may not use this file except in compliance +; with the License. You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, +; software distributed under the License is distributed on an +; "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +; KIND, either express or implied. See the License for the +; specific language governing permissions and limitations +; under the License. + +; JSON-RPC test case + +(define (echo x) x) + +; ATOMPub test case + +(define (get id) + (if (nul id) + '("Sample Feed" "123456789" + ("Item" "111" ((javaClass "services.Item") (name "Apple") (currencyCode "USD") (currencySymbol "$") (price 2.99))) + ("Item" "222" ((javaClass "services.Item") (name "Orange") (currencyCode "USD") (currencySymbol "$") (price 3.55))) + ("Item" "333" ((javaClass "services.Item") (name "Pear") (currencyCode "USD") (currencySymbol "$") (price 1.55)))) + + (list "Item" (car id) '((javaClass "services.Item") (name "Apple") (currencyCode "USD") (currencySymbol "$") (price 2.99)))) +) + +(define (post collection item) + '("123456789") +) + +(define (put id item) + true +) + +(define (delete id) + true +) diff --git a/sca-cpp/branches/cpp-contrib/modules/server/wiring-test b/sca-cpp/branches/cpp-contrib/modules/server/wiring-test new file mode 100755 index 0000000000..0deab33d68 --- /dev/null +++ b/sca-cpp/branches/cpp-contrib/modules/server/wiring-test @@ -0,0 +1,76 @@ +#!/bin/sh + +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +echo "Testing..." + +# Setup +../http/httpd-conf tmp 8090 htdocs +./server-conf tmp +./scheme-conf tmp +cat >>tmp/conf/httpd.conf <<EOF +SCAContribution `pwd`/ +SCAComposite domain-test.composite +EOF + +../http/httpd-start tmp +sleep 2 + +# Test HTTP GET +curl http://localhost:8090/index.html 2>/dev/null >tmp/index.html +diff tmp/index.html htdocs/index.html +rc=$? + +# Test ATOMPub +if [ "$rc" = "0" ]; then + curl http://localhost:8090/client/ >tmp/feed.xml 2>/dev/null + diff tmp/feed.xml htdocs/feed.xml + rc=$? +fi +if [ "$rc" = "0" ]; then + curl http://localhost:8090/client/111 >tmp/entry.xml 2>/dev/null + diff tmp/entry.xml htdocs/entry.xml + rc=$? +fi +if [ "$rc" = "0" ]; then + curl http://localhost:8090/client/ -X POST -H "Content-type: application/atom+xml" --data @htdocs/entry.xml 2>/dev/null + rc=$? +fi +if [ "$rc" = "0" ]; then + curl http://localhost:8090/client/111 -X PUT -H "Content-type: application/atom+xml" --data @htdocs/entry.xml 2>/dev/null + rc=$? +fi +if [ "$rc" = "0" ]; then + curl http://localhost:8090/client/111 -X DELETE 2>/dev/null + rc=$? +fi + +# Test JSON-RPC +if [ "$rc" = "0" ]; then + curl http://localhost:8090/client/ -X POST -H "Content-type: application/json-rpc" --data @htdocs/json-request.txt >tmp/json-result.txt 2>/dev/null + diff tmp/json-result.txt htdocs/json-result.txt + rc=$? +fi + +# Cleanup +../http/httpd-stop tmp +sleep 2 +if [ "$rc" = "0" ]; then + echo "OK" +fi +return $rc |