summaryrefslogtreecommitdiffstats
path: root/sca-cpp
diff options
context:
space:
mode:
Diffstat (limited to 'sca-cpp')
-rw-r--r--sca-cpp/trunk/kernel/dynlib-test.cpp48
-rw-r--r--sca-cpp/trunk/kernel/dynlib.hpp102
-rw-r--r--sca-cpp/trunk/kernel/kernel-test.cpp21
-rw-r--r--sca-cpp/trunk/kernel/monad.hpp137
-rw-r--r--sca-cpp/trunk/kernel/xml.hpp12
-rw-r--r--sca-cpp/trunk/modules/atom/atom-test.cpp8
-rw-r--r--sca-cpp/trunk/modules/atom/atom.hpp8
-rw-r--r--sca-cpp/trunk/modules/http/curl-test.cpp161
-rw-r--r--sca-cpp/trunk/modules/http/curl.hpp39
-rwxr-xr-xsca-cpp/trunk/modules/http/http-test12
-rwxr-xr-xsca-cpp/trunk/modules/http/httpd-conf2
-rwxr-xr-xsca-cpp/trunk/modules/http/httpd-test41
-rw-r--r--sca-cpp/trunk/modules/http/httpd.hpp146
-rw-r--r--sca-cpp/trunk/modules/http/mod-eval.cpp532
-rw-r--r--sca-cpp/trunk/modules/json/json-test.cpp20
-rw-r--r--sca-cpp/trunk/modules/json/json.hpp10
-rwxr-xr-xsca-cpp/trunk/modules/scdl/scdl-testbin477277 -> 0 bytes
-rw-r--r--sca-cpp/trunk/modules/server/Makefile.am36
-rw-r--r--sca-cpp/trunk/modules/server/client-test.cpp251
-rw-r--r--sca-cpp/trunk/modules/server/htdocs/entry.xml (renamed from sca-cpp/trunk/modules/http/htdocs/entry.xml)0
-rw-r--r--sca-cpp/trunk/modules/server/htdocs/feed.xml (renamed from sca-cpp/trunk/modules/http/htdocs/feed.xml)0
-rw-r--r--sca-cpp/trunk/modules/server/htdocs/index.html21
-rw-r--r--sca-cpp/trunk/modules/server/htdocs/json-request.txt (renamed from sca-cpp/trunk/modules/http/htdocs/json-request.txt)0
-rw-r--r--sca-cpp/trunk/modules/server/htdocs/json-result.txt (renamed from sca-cpp/trunk/modules/http/htdocs/json-result.txt)0
-rwxr-xr-xsca-cpp/trunk/modules/server/http-test43
-rw-r--r--sca-cpp/trunk/modules/server/httpd-client.scm (renamed from sca-cpp/trunk/modules/http/httpd-client.scm)0
-rwxr-xr-xsca-cpp/trunk/modules/server/httpd-test80
-rw-r--r--sca-cpp/trunk/modules/server/httpd-test.composite (renamed from sca-cpp/trunk/modules/http/httpd-test.composite)0
-rw-r--r--sca-cpp/trunk/modules/server/httpd-test.scm (renamed from sca-cpp/trunk/modules/http/httpd-test.scm)0
-rw-r--r--sca-cpp/trunk/modules/server/mod-cpp.hpp91
-rw-r--r--sca-cpp/trunk/modules/server/mod-eval.cpp387
-rw-r--r--sca-cpp/trunk/modules/server/mod-eval.hpp50
-rw-r--r--sca-cpp/trunk/modules/server/mod-scm.hpp92
-rw-r--r--sca-cpp/trunk/modules/server/mod-wiring.cpp (renamed from sca-cpp/trunk/modules/http/mod-wiring.cpp)83
-rwxr-xr-xsca-cpp/trunk/modules/server/server-conf32
-rwxr-xr-xsca-cpp/trunk/modules/server/wiring-test (renamed from sca-cpp/trunk/modules/http/wiring-test)17
-rwxr-xr-xsca-cpp/trunk/test/store-script/store-http-test5
37 files changed, 1575 insertions, 912 deletions
diff --git a/sca-cpp/trunk/kernel/dynlib-test.cpp b/sca-cpp/trunk/kernel/dynlib-test.cpp
new file mode 100644
index 0000000000..0123b5ec79
--- /dev/null
+++ b/sca-cpp/trunk/kernel/dynlib-test.cpp
@@ -0,0 +1,48 @@
+/*
+ * 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 library.
+ */
+
+#include "function.hpp"
+
+namespace tuscany {
+namespace test {
+
+ const int cppsquare(int x) {
+ return x * x;
+ }
+
+}
+}
+
+extern "C" {
+
+ const int csquare(const int x) {
+ return tuscany::test::cppsquare(x);
+ }
+
+ const tuscany::lambda<int(int)> csquarel(const int x) {
+ return tuscany::lambda<int(int)>(tuscany::test::cppsquare);
+ }
+
+}
diff --git a/sca-cpp/trunk/kernel/dynlib.hpp b/sca-cpp/trunk/kernel/dynlib.hpp
new file mode 100644
index 0000000000..10a5a030cb
--- /dev/null
+++ b/sca-cpp/trunk/kernel/dynlib.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_dlib_hpp
+#define tuscany_dlib_hpp
+
+/**
+ * Simple dynamic library access functions.
+ */
+
+#include <dlfcn.h>
+
+#include "function.hpp"
+#include "gc.hpp"
+#include "monad.hpp"
+
+namespace tuscany {
+
+/**
+ * OS specific dynamic library file extension.
+ */
+#ifdef IS_DARWIN
+const std::string dynlibExt(".dylib");
+#else
+const std::string dynlibExt(".so");
+#endif
+
+/**
+ * Represents a reference to a dynamic library.
+ */
+class lib {
+public:
+ lib() : dl(NULL) {
+ }
+
+ lib(const std::string& name) : dl(new DynLib(name)) {
+ }
+
+ ~lib() {
+ }
+
+private:
+ class DynLib {
+ public:
+ DynLib(const std::string& name) : name(name), h(dlopen(name.c_str(), RTLD_NOW)) {
+ }
+ ~DynLib() {
+ if (h == NULL)
+ return;
+ dlclose(h);
+ }
+
+ const std::string name;
+ void* h;
+ };
+
+ gc_ptr<DynLib> dl;
+
+ friend const failable<lib, std::string> dynlib(const std::string& name);
+ template<typename S> friend const failable<lambda<S>, std::string> dynlambda(const std::string& name, const lib& l);
+};
+
+/**
+ * Load a dynamic library.
+ */
+const failable<lib, std::string> dynlib(const std::string& name) {
+ const lib l(name);
+ if (l.dl->h == NULL)
+ return mkfailure<lib, std::string>("Could not load library: " + name + ": " + dlerror());
+ return l;
+}
+
+/**
+ * Find a lambda function in a dynamic library.
+ */
+template<typename S> const failable<lambda<S>, std::string> dynlambda(const std::string& name, const lib& l) {
+ const void* s = dlsym(l.dl->h, name.c_str());
+ if (s == NULL)
+ return mkfailure<lambda<S>, std::string>(std::string("Could not load symbol: " + name));
+ return lambda<S>((S*)s);
+}
+
+}
+#endif /* tuscany_dlib_hpp */
diff --git a/sca-cpp/trunk/kernel/kernel-test.cpp b/sca-cpp/trunk/kernel/kernel-test.cpp
index 9346e31b71..24d67e1a9a 100644
--- a/sca-cpp/trunk/kernel/kernel-test.cpp
+++ b/sca-cpp/trunk/kernel/kernel-test.cpp
@@ -37,6 +37,7 @@
#include "element.hpp"
#include "xml.hpp"
#include "monad.hpp"
+#include "dynlib.hpp"
namespace tuscany {
@@ -660,8 +661,8 @@ struct tickInc {
const double v;
tickInc(const double v) : v(v) {
}
- const svp<int, double> operator()(int s) const {
- return svp<int, double>(s + 1, v);
+ const scp<int, double> operator()(int s) const {
+ return scp<int, double>(s + 1, v);
}
};
@@ -693,6 +694,21 @@ bool testStateMonad() {
return true;
}
+bool testDynLib() {
+ const failable<lib, std::string> dl(dynlib(".libs/libdynlib-test" + dynlibExt));
+ assert(hasContent(dl));
+ const failable<lambda<int(int)>, std::string> sq(dynlambda<int(int)>("csquare", content(dl)));
+ assert(hasContent(sq));
+ lambda<int(int)> l(content(sq));
+ assert(l(2) == 4);
+
+ const failable<lambda<lambda<int(int)>()>, std::string> sql(dynlambda<lambda<int(int)>()>("csquarel", content(dl)));
+ assert(hasContent(sql));
+ lambda<lambda<int(int)>()> ll(content(sql));
+ assert(ll()(3) == 9);
+ return true;
+}
+
}
int main() {
@@ -730,6 +746,7 @@ int main() {
tuscany::testMaybeMonad();
tuscany::testFailableMonad();
tuscany::testStateMonad();
+ tuscany::testDynLib();
std::cout << "OK" << std::endl;
diff --git a/sca-cpp/trunk/kernel/monad.hpp b/sca-cpp/trunk/kernel/monad.hpp
index 98eb3799c0..1a45640c32 100644
--- a/sca-cpp/trunk/kernel/monad.hpp
+++ b/sca-cpp/trunk/kernel/monad.hpp
@@ -42,10 +42,6 @@ public:
id(const V& v) : v(v) {
}
- operator const V() const {
- return v;
- }
-
const id<V>& operator=(const id<V>& m) {
if(this == &m)
return *this;
@@ -65,17 +61,26 @@ public:
private:
const V v;
+
+ template<typename X> friend const X content(const id<X>& m);
};
/**
* Write an identity monad to a stream.
*/
template<typename V> std::ostream& operator<<(std::ostream& out, const id<V>& m) {
- out << (V)m;
+ out << content(m);
return out;
}
/**
+ * Returns the content of an identity monad.
+ */
+template<typename V> const V content(const id<V>& m) {
+ return m.v;
+}
+
+/**
* Return an identity monad from a value.
*/
template<typename V> const id<V> mkunit(const V& v) {
@@ -90,11 +95,11 @@ template<typename V> const lambda<id<V>(V)> unit() {
* Bind a function to an identity monad. Pass the value in the monad to the function.
*/
template<typename R, typename V> const id<R> operator>>(const id<V>& m, const lambda<id<R>(V)>& f) {
- return f(m);
+ return f(content(m));
}
template<typename R, typename V> const id<R> operator>>(const id<V>& m, const id<R> (* const f)(const V)) {
- return f(m);
+ return f(content(m));
}
/**
@@ -109,10 +114,6 @@ public:
maybe() : hasv(false) {
}
- operator const V() const {
- return v;
- }
-
const maybe<V>& operator=(const maybe<V>& m) {
if(this == &m)
return *this;
@@ -138,18 +139,19 @@ private:
const bool hasv;
V v;
- template<typename A> friend const bool hasValue(const maybe<A>& m);
+ template<typename X> friend const bool hasContent(const maybe<X>& m);
+ template<typename X> friend const X content(const maybe<X>& m);
};
/**
* Write a maybe monad to a stream.
*/
template<typename V> std::ostream& operator<<(std::ostream& out, const maybe<V>& m) {
- if (!hasValue(m)) {
+ if (!hasContent(m)) {
out << "nothing";
return out;
}
- out << (V)m;
+ out << content(m);
return out;
}
@@ -165,26 +167,33 @@ template<typename V> const lambda<maybe<V>(V)> just() {
}
/**
- * Returns true if the monad contains a value.
+ * Returns true if a maybe monad contains a content.
*/
-template<typename V> const bool hasValue(const maybe<V>& m) {
+template<typename V> const bool hasContent(const maybe<V>& m) {
return m.hasv;
}
/**
+ * Returns the content of a maybe monad.
+ */
+template<typename V> const V content(const maybe<V>& m) {
+ return m.v;
+}
+
+/**
* Bind a function to a maybe monad. Passes the value in the monad to the function
* if present, or does nothing if there's no value.
*/
template<typename R, typename V> const maybe<R> operator>>(const maybe<V>& m, const lambda<maybe<R>(V)>& f) {
- if (!hasValue(m))
+ if (!hasContent(m))
return m;
- return f(m);
+ return f(content(m));
}
template<typename R, typename V> const maybe<R> operator>>(const maybe<V>& m, const maybe<R> (* const f)(const V)) {
- if (!hasValue(m))
+ if (!hasContent(m))
return m;
- return f(m);
+ return f(content(m));
}
/**
@@ -207,10 +216,6 @@ public:
f = m.f;
}
- operator const V() const {
- return v;
- }
-
const failable<V, F>& operator=(const failable<V, F>& m) {
if(this == &m)
return *this;
@@ -242,7 +247,8 @@ private:
failable(const bool hasv, const F& f) : hasv(hasv), f(f) {
}
- template<typename A, typename B> friend const bool hasValue(const failable<A, B>& m);
+ template<typename A, typename B> friend const bool hasContent(const failable<A, B>& m);
+ template<typename A, typename B> friend const A content(const failable<A, B>& m);
template<typename A, typename B> friend const B reason(const failable<A, B>& m);
template<typename A, typename B> friend const failable<A, B> mkfailure(const B& f);
};
@@ -251,12 +257,11 @@ private:
* Write a failable monad to a stream.
*/
template<typename V, typename F> std::ostream& operator<<(std::ostream& out, const failable<V, F>& m) {
- if (!hasValue(m)) {
+ if (!hasContent(m)) {
out << reason(m);
return out;
}
- const V v = m;
- out << v;
+ out << content(m);
return out;
}
@@ -283,13 +288,20 @@ template<typename V, typename F> const lambda<failable<V, F>(V)> failure() {
}
/**
- * Returns true if the monad contains a value.
+ * Returns true if the monad contains a content.
*/
-template<typename V, typename F> const bool hasValue(const failable<V, F>& m) {
+template<typename V, typename F> const bool hasContent(const failable<V, F>& m) {
return m.hasv;
}
/**
+ * Returns the content of a failable monad.
+ */
+template<typename V, typename F> const V content(const failable<V, F>& m) {
+ return m.v;
+}
+
+/**
* Returns the reason for failure of a failable monad.
*/
template<typename V, typename F> const F reason(const failable<V, F>& m) {
@@ -302,24 +314,24 @@ template<typename V, typename F> const F reason(const failable<V, F>& m) {
*/
template<typename R, typename FR, typename V, typename FV>
const failable<R, FR> operator>>(const failable<V, FV>& m, const lambda<failable<R, FR>(V)>& f) {
- if (!hasValue(m))
+ if (!hasContent(m))
return m;
- return f(m);
+ return f(content(m));
}
template<typename R, typename FR, typename V, typename FV>
const failable<R, FR> operator>>(const failable<V, FV>& m, const failable<R, FR> (* const f)(const V)) {
- if (!hasValue(m))
+ if (!hasContent(m))
return m;
- return f(m);
+ return f(content(m));
}
/**
- * State + value pair data type used by the state monad.
+ * State + content pair data type used by the state monad.
*/
-template<typename S, typename V> class svp {
+template<typename S, typename V> class scp {
public:
- svp(const S& s, const V& v) : s(s), v(v) {
+ scp(const S& s, const V& v) : s(s), v(v) {
}
operator const S() const {
@@ -330,7 +342,7 @@ public:
return v;
}
- const svp<S, V>& operator=(const svp<S, V>& p) {
+ const scp<S, V>& operator=(const scp<S, V>& p) {
if(this == &p)
return *this;
s = p.s;
@@ -338,11 +350,11 @@ public:
return *this;
}
- const bool operator!=(const svp<S, V>& p) const {
+ const bool operator!=(const scp<S, V>& p) const {
return !this->operator==(p);
}
- const bool operator==(const svp<S, V>& p) const {
+ const bool operator==(const scp<S, V>& p) const {
if (this == &p)
return true;
return s == p.s && v == p.v;
@@ -351,19 +363,34 @@ public:
private:
const S s;
const V v;
+
+ template<typename A, typename B> friend const A scpstate(const scp<A, B>& m);
+ template<typename A, typename B> friend const B content(const scp<A, B>& m);
};
/**
- * State monad. Used to represent the combination of a state and a value.
- * To get the state in the monad, just cast it to the state type.
- * To get the value in the monad, just cast it to the value type.
+ * Returns the state of a state-content pair.
+ */
+template<typename S, typename V> const S scpstate(const scp<S, V>& m) {
+ return m.s;
+}
+
+/**
+ * Returns the content of a state-content pair.
+ */
+template<typename S, typename V> const S content(const scp<S, V>& m) {
+ return m.v;
+}
+
+/**
+ * State monad. Used to represent the combination of a state and a content.
*/
template<typename S, typename V> class state {
public:
- state(const lambda<svp<S, V>(S)>& f) : f(f) {
+ state(const lambda<scp<S, V>(S)>& f) : f(f) {
}
- const svp<S, V> operator()(const S& s) const {
+ const scp<S, V> operator()(const S& s) const {
return f(s);
}
@@ -385,7 +412,7 @@ public:
}
private:
- const lambda<svp<S, V>(S)> f;
+ const lambda<scp<S, V>(S)> f;
};
/**
@@ -399,14 +426,14 @@ template<typename S, typename V> std::ostream& operator<<(std::ostream& out, con
}
/**
- * Return a state monad carrying a result value.
+ * Return a state monad carrying a result content.
*/
template<typename S, typename V> struct returnState {
const V v;
returnState(const V& v) : v(v) {
}
- const svp<S, V> operator()(const S& s) const {
- return svp<S, V>(s, v);
+ const scp<S, V> operator()(const S& s) const {
+ return scp<S, V>(s, v);
}
};
@@ -416,16 +443,16 @@ template<typename S, typename V> const state<S, V> result(const V& v) {
/**
* Return a state monad with a transformer function.
- * A transformer function takes a state and returns an svp pair carrying a value and a
+ * A transformer function takes a state and returns an scp pair carrying a content and a
* new (transformed) state.
*/
-template<typename S, typename V> const state<S, V> transformer(const lambda<svp<S, V>(S)>& f) {
+template<typename S, typename V> const state<S, V> transformer(const lambda<scp<S, V>(S)>& f) {
return state<S, V>(f);
}
/**
- * Bind a function to a state monad. The function takes a value and returns a state
- * monad carrying a return value.
+ * Bind a function to a state monad. The function takes a content and returns a state
+ * monad carrying a return content.
*/
template<typename S, typename A, typename B> struct stateBind {
const state<S, A> st;
@@ -434,8 +461,8 @@ template<typename S, typename A, typename B> struct stateBind {
stateBind(const state<S, A>& st, const lambda<state<S, B>(A)>& f) : st(st), f(f) {
}
- const svp<S, B> operator()(const S& is) const {
- const svp<S, A> iscp = st(is);
+ const scp<S, B> operator()(const S& is) const {
+ const scp<S, A> iscp = st(is);
const state<S, B> m = f((A)iscp);
return m((S)iscp);
}
diff --git a/sca-cpp/trunk/kernel/xml.hpp b/sca-cpp/trunk/kernel/xml.hpp
index 8d561557ca..4b4bcd098e 100644
--- a/sca-cpp/trunk/kernel/xml.hpp
+++ b/sca-cpp/trunk/kernel/xml.hpp
@@ -261,7 +261,7 @@ const failable<bool, std::string> writeList(const list<value>& l, const xmlTextW
// Write its children
const failable<bool, std::string> w = writeList(elementChildren(token), xml);
- if (!hasValue(w))
+ if (!hasContent(w))
return w;
if (xmlTextWriterEndElement(xml) < 0)
@@ -276,7 +276,7 @@ const failable<bool, std::string> writeList(const list<value>& l, const xmlTextW
// Write its children
const failable<bool, std::string> w = writeList(elementChildren(token), xml);
- if (!hasValue(w))
+ if (!hasContent(w))
return w;
if (xmlTextWriterEndElement(xml) < 0)
@@ -302,7 +302,7 @@ const failable<bool, std::string> write(const list<value>& l, const xmlTextWrite
return mkfailure<bool, std::string>("xmlTextWriterStartDocument failed");
const failable<bool, std::string> w = writeList(l, xml);
- if (!hasValue(w))
+ if (!hasContent(w))
return w;
if (xmlTextWriterEndDocument(xml) < 0)
@@ -344,7 +344,7 @@ template<typename R> const failable<R, std::string> writeXML(const lambda<R(std:
const failable<bool, std::string> w = write(l, xml);
xmlFreeTextWriter(xml);
- if (!hasValue(w)) {
+ if (!hasContent(w)) {
return mkfailure<R, std::string>(reason(w));
}
return cx.accum;
@@ -355,9 +355,9 @@ template<typename R> const failable<R, std::string> writeXML(const lambda<R(std:
*/
const failable<list<std::string>, std::string> writeXML(const list<value>& l) {
const failable<list<std::string>, std::string> ls = writeXML<list<std::string> >(rcons<std::string>, list<std::string>(), l);
- if (!hasValue(ls))
+ if (!hasContent(ls))
return ls;
- return reverse(list<std::string>(ls));
+ return reverse(list<std::string>(content(ls)));
}
}
diff --git a/sca-cpp/trunk/modules/atom/atom-test.cpp b/sca-cpp/trunk/modules/atom/atom-test.cpp
index 7c14b954a0..ba651e8eb2 100644
--- a/sca-cpp/trunk/modules/atom/atom-test.cpp
+++ b/sca-cpp/trunk/modules/atom/atom-test.cpp
@@ -82,13 +82,13 @@ bool testEntry() {
assert(os.str() == itemEntry);
}
{
- const list<value> a = readEntry(mklist(itemEntry));
+ const list<value> a = content(readEntry(mklist(itemEntry)));
std::ostringstream os;
writeATOMEntry<std::ostringstream*>(writer, &os, a);
assert(os.str() == itemEntry);
}
{
- const list<value> a = readEntry(mklist(incompleteEntry));
+ const list<value> a = content(readEntry(mklist(incompleteEntry)));
std::ostringstream os;
writeATOMEntry<std::ostringstream*>(writer, &os, a);
assert(os.str() == completedEntry);
@@ -135,7 +135,7 @@ bool testFeed() {
assert(os.str() == emptyFeed);
}
{
- const list<value> a = readFeed(mklist(emptyFeed));
+ const list<value> a = content(readFeed(mklist(emptyFeed)));
std::ostringstream os;
writeATOMFeed<std::ostringstream*>(writer, &os, a);
assert(os.str() == emptyFeed);
@@ -171,7 +171,7 @@ bool testFeed() {
assert(os.str() == itemFeed);
}
{
- const list<value> a = readFeed(mklist(itemFeed));
+ const list<value> a = content(readFeed(mklist(itemFeed)));
std::ostringstream os;
writeATOMFeed<std::ostringstream*>(writer, &os, a);
assert(os.str() == itemFeed);
diff --git a/sca-cpp/trunk/modules/atom/atom.hpp b/sca-cpp/trunk/modules/atom/atom.hpp
index 5054c635a0..ac19b93e38 100644
--- a/sca-cpp/trunk/modules/atom/atom.hpp
+++ b/sca-cpp/trunk/modules/atom/atom.hpp
@@ -113,9 +113,9 @@ template<typename R> const failable<R, std::string> writeATOMEntry(const lambda<
const failable<list<std::string>, std::string> writeATOMEntry(const list<value>& l) {
const failable<list<std::string>, std::string> ls = writeATOMEntry<list<std::string> >(rcons<std::string>, list<std::string>(), l);
- if (!hasValue(ls))
+ if (!hasContent(ls))
return ls;
- return reverse(list<std::string>(ls));
+ return reverse(list<std::string>(content(ls)));
}
/**
@@ -139,9 +139,9 @@ template<typename R> const failable<R, std::string> writeATOMFeed(const lambda<R
*/
const failable<list<std::string>, std::string> writeATOMFeed(const list<value>& l) {
const failable<list<std::string>, std::string> ls = writeATOMFeed<list<std::string> >(rcons<std::string>, list<std::string>(), l);
- if (!hasValue(ls))
+ if (!hasContent(ls))
return ls;
- return reverse(list<std::string>(ls));
+ return reverse(list<std::string>(content(ls)));
}
/**
diff --git a/sca-cpp/trunk/modules/http/curl-test.cpp b/sca-cpp/trunk/modules/http/curl-test.cpp
index 863aa98828..0a6fbcd8a6 100644
--- a/sca-cpp/trunk/modules/http/curl-test.cpp
+++ b/sca-cpp/trunk/modules/http/curl-test.cpp
@@ -53,16 +53,15 @@ const bool testGet() {
CURLHandle ch;
{
std::ostringstream os;
- const failable<list<std::ostringstream*>, std::string> r = get<std::ostringstream*>(curlWriter, &os, "http://localhost:8091", ch);
- assert(hasValue(r));
+ const failable<list<std::ostringstream*>, std::string> r = get<std::ostringstream*>(curlWriter, &os, "http://localhost:8090", ch);
+ assert(hasContent(r));
assert(contains(os.str(), "HTTP/1.1 200 OK"));
assert(contains(os.str(), "It works"));
}
{
- const failable<value, std::string> r = get("http://localhost:8091", ch);
- assert(hasValue(r));
- const value val = r;
- assert(contains(val, "It works"));
+ const failable<value, std::string> r = get("http://localhost:8090", ch);
+ assert(hasContent(r));
+ assert(contains(content(r), "It works"));
}
return true;
}
@@ -70,10 +69,9 @@ const bool testGet() {
const bool testGetLoop(const int count, CURLHandle& ch) {
if (count == 0)
return true;
- const failable<value, std::string> r = get("http://localhost:8091", ch);
- assert(hasValue(r));
- const value val = r;
- assert(contains(val, "It works"));
+ const failable<value, std::string> r = get("http://localhost:8090", ch);
+ assert(hasContent(r));
+ assert(contains(content(r), "It works"));
return testGetLoop(count - 1, ch);
}
@@ -95,142 +93,6 @@ const bool testGetPerf() {
return true;
}
-const bool testEval() {
- CURLHandle ch;
- const value val = evalExpr(mklist<value>(std::string("echo"), std::string("Hello")), "http://localhost:8091/test", ch);
- assert(val == std::string("Hello"));
- return true;
-}
-
-const bool testEvalLoop(const int count, CURLHandle& ch) {
- if (count == 0)
- return true;
- const value val = evalExpr(mklist<value>(std::string("echo"), std::string("Hello")), "http://localhost:8091/test", ch);
- assert(val == std::string("Hello"));
- return testEvalLoop(count - 1, ch);
-}
-
-const value blob(std::string(3000, 'A'));
-const list<value> blobs = mklist(blob, blob, blob, blob, blob);
-
-const bool testBlobEvalLoop(const int count, CURLHandle& ch) {
- if (count == 0)
- return true;
- const value val = evalExpr(mklist<value>(std::string("echo"), blobs), "http://localhost:8091/test", ch);
- assert(val == blobs);
- return testBlobEvalLoop(count - 1, ch);
-}
-
-const bool testEvalPerf() {
- const int count = 50;
- CURLHandle ch;
- struct timeval start;
- struct timeval end;
- {
- testEvalLoop(5, ch);
-
- gettimeofday(&start, NULL);
-
- testEvalLoop(count, ch);
-
- gettimeofday(&end, NULL);
- std::cout << "JSON-RPC eval echo test " << duration(start, end, count) << " ms" << std::endl;
- }
- {
- testBlobEvalLoop(5, ch);
-
- gettimeofday(&start, NULL);
-
- testBlobEvalLoop(count, ch);
-
- gettimeofday(&end, NULL);
- std::cout << "JSON-RPC eval blob test " << duration(start, end, count) << " ms" << std::endl;
- }
- return true;
-}
-
-const bool testFeed() {
- return true;
-}
-
-bool testPost() {
- const list<value> i = list<value>()
- << (list<value>() << "name" << std::string("Apple"))
- << (list<value>() << "price" << std::string("$2.99"));
- const list<value> a = mklist<value>(std::string("item"), std::string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
- CURLHandle ch;
- value rc = post(a, "http://localhost:8091/test", ch);
- assert(rc == value(true));
- return true;
-}
-
-const bool testPostLoop(const int count, const value& val, CURLHandle& ch) {
- if (count == 0)
- return true;
- const value rc = post(val, "http://localhost:8091/test", ch);
- assert(rc == value(true));
- return testPostLoop(count - 1, val, ch);
-}
-
-const bool testPostPerf() {
- const int count = 50;
- CURLHandle ch;
- struct timeval start;
- struct timeval end;
- {
- const list<value> i = list<value>()
- << (list<value>() << "name" << std::string("Apple"))
- << (list<value>() << "price" << std::string("$2.99"));
- const list<value> val = mklist<value>(std::string("item"), std::string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
- testPostLoop(5, val, ch);
-
- gettimeofday(&start, NULL);
-
- testPostLoop(count, val, ch);
-
- gettimeofday(&end, NULL);
- std::cout << "ATOMPub POST small test " << duration(start, end, count) << " ms" << std::endl;
- }
- {
- const list<value> i = list<value>()
- << (list<value>() << "name" << std::string("Apple"))
- << (list<value>() << "blob1" << blob)
- << (list<value>() << "blob2" << blob)
- << (list<value>() << "blob3" << blob)
- << (list<value>() << "blob4" << blob)
- << (list<value>() << "blob5" << blob)
- << (list<value>() << "price" << std::string("$2.99"));
- const list<value> val = mklist<value>(std::string("item"), std::string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
- testPostLoop(5, val, ch);
-
- gettimeofday(&start, NULL);
-
- testPostLoop(count, val, ch);
-
- gettimeofday(&end, NULL);
- std::cout << "ATOMPub POST blob test " << duration(start, end, count) << " ms" << std::endl;
- }
- return true;
-}
-
-const bool testPut() {
- const list<value> i = list<value>()
- << (list<value>() << "name" << std::string("Apple"))
- << (list<value>() << "price" << std::string("$2.99"));
- const list<value> a = mklist<value>(std::string("item"), std::string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
- CURLHandle ch;
- value rc = put(a, "http://localhost:8091/test/111", ch);
- assert(rc == value(true));
- return true;
-}
-
-const bool testDel() {
- CURLHandle ch;
- value rc = del("http://localhost:8091/test/123456789", ch);
- assert(rc == value(true));
- return true;
-}
-
}
}
@@ -239,13 +101,6 @@ int main() {
tuscany::http::testGet();
tuscany::http::testGetPerf();
- tuscany::http::testPost();
- tuscany::http::testPostPerf();
- tuscany::http::testEval();
- tuscany::http::testEvalPerf();
- tuscany::http::testFeed();
- tuscany::http::testPut();
- tuscany::http::testDel();
std::cout << "OK" << std::endl;
diff --git a/sca-cpp/trunk/modules/http/curl.hpp b/sca-cpp/trunk/modules/http/curl.hpp
index 5ee3a090b0..6c3a3a47dc 100644
--- a/sca-cpp/trunk/modules/http/curl.hpp
+++ b/sca-cpp/trunk/modules/http/curl.hpp
@@ -209,29 +209,29 @@ const failable<value, std::string> evalExpr(const value& expr, const std::string
// Convert expression to a JSON-RPC request
json::JSONContext cx;
const failable<list<std::string>, std::string> jsreq = jsonRequest(1, car<value>(expr), cdr<value>(expr), cx);
- if (!hasValue(jsreq))
+ if (!hasContent(jsreq))
return mkfailure<value, std::string>(reason(jsreq));
if (logContent) {
std::cout<< "content: " << std::endl;
- write(jsreq, std::cout);
+ write(content(jsreq), std::cout);
std::cout<< std::endl;
std::cout.flush();
}
// POST it to the URL
const list<std::string> h = mklist<std::string>("Content-Type: application/json-rpc");
- const failable<list<list<std::string> >, std::string> res = apply<list<std::string> >(mklist<list<std::string> >(h, jsreq), rcons<std::string>, list<std::string>(), url, "POST", ch);
- if (!hasValue(res))
+ const failable<list<list<std::string> >, std::string> res = apply<list<std::string> >(mklist<list<std::string> >(h, content(jsreq)), rcons<std::string>, list<std::string>(), url, "POST", ch);
+ if (!hasContent(res))
return mkfailure<value, std::string>(reason(res));
// Return result
if (logContent) {
std::cout << "content:" << std::endl;
- write(cadr<list<std::string> >(res), std::cout);
+ write(cadr<list<std::string> >(content(res)), std::cout);
std::cout << std::endl;
}
- const list<value> val = elementsToValues(json::readJSON(cadr<list<std::string> >(res), cx));
+ const list<value> val = elementsToValues(content(json::readJSON(cadr<list<std::string> >(content(res)), cx)));
return cadr<value>(cadr<value>(val));
}
@@ -250,9 +250,8 @@ const failable<value, std::string> get(const std::string& url, const CURLHandle&
// Get the contents of the resource at the given URL
const failable<list<list<std::string> >, std::string> res = get<list<std::string> >(rcons<std::string>, list<std::string>(), url, ch);
- if (!hasValue(res))
+ if (!hasContent(res))
return mkfailure<value, std::string>(reason(res));
- const list<list<std::string> > ls = res;
const std::string ct;
if (ct.find("application/atom+xml") != std::string::npos) {
@@ -261,7 +260,7 @@ const failable<value, std::string> get(const std::string& url, const CURLHandle&
// Return the content as a string value
std::ostringstream os;
- write(reverse(cadr(ls)), os);
+ write(reverse(cadr(content(res))), os);
return value(os.str());
}
@@ -272,19 +271,19 @@ const failable<value, std::string> post(const value& val, const std::string& url
// Convert value to an ATOM entry
const failable<list<std::string>, std::string> entry = atom::writeATOMEntry(atom::entryValuesToElements(val));
- if (!hasValue(entry))
+ if (!hasContent(entry))
return mkfailure<value, std::string>(reason(entry));
if (logContent) {
std::cout << "content:" << std::endl;
- write(list<std::string>(entry), std::cout);
+ write(list<std::string>(content(entry)), std::cout);
std::cout << std::endl;
}
// POST it to the URL
const list<std::string> h = mklist<std::string>("Content-Type: application/atom+xml");
- const list<list<std::string> > req = mklist<list<std::string> >(h, entry);
+ const list<list<std::string> > req = mklist<list<std::string> >(h, content(entry));
const failable<list<list<std::string> >, std::string> res = apply<list<std::string> >(req, rcons<std::string>, list<std::string>(), url, "POST", ch);
- if (!hasValue(res))
+ if (!hasContent(res))
return mkfailure<value, std::string>(reason(res));
return value(true);
}
@@ -296,19 +295,19 @@ const failable<value, std::string> put(const value& val, const std::string& url,
// Convert value to an ATOM entry
const failable<list<std::string>, std::string> entry = atom::writeATOMEntry(atom::entryValuesToElements(val));
- if (!hasValue(entry))
+ if (!hasContent(entry))
return mkfailure<value, std::string>(reason(entry));
if (logContent) {
std::cout << "content:" << std::endl;
- write(list<std::string>(entry), std::cout);
+ write(list<std::string>(content(entry)), std::cout);
std::cout << std::endl;
}
// PUT it to the URL
const list<std::string> h = mklist<std::string>("Content-Type: application/atom+xml");
- const list<list<std::string> > req = mklist<list<std::string> >(h, entry);
+ const list<list<std::string> > req = mklist<list<std::string> >(h, content(entry));
const failable<list<list<std::string> >, std::string> res = apply<list<std::string> >(req, rcons<std::string>, list<std::string>(), url, "PUT", ch);
- if (!hasValue(res))
+ if (!hasContent(res))
return mkfailure<value, std::string>(reason(res));
return value(true);
}
@@ -319,7 +318,7 @@ const failable<value, std::string> put(const value& val, const std::string& url,
const failable<value, std::string> del(const std::string& url, const CURLHandle& ch) {
const list<list<std::string> > req = mklist(list<std::string>(), list<std::string>());
const failable<list<list<std::string> >, std::string> res = apply<list<std::string> >(req, rcons<std::string>, list<std::string>(), url, "DELETE", ch);
- if (!hasValue(res))
+ if (!hasContent(res))
return mkfailure<value, std::string>(reason(res));
return value(true);
}
@@ -333,9 +332,9 @@ struct proxy {
const value operator()(const list<value>& args) const {
failable<value, std::string> val = evalExpr(args, url, ch);
- if (!hasValue(val))
+ if (!hasContent(val))
return value();
- return val;
+ return content(val);
}
const std::string url;
diff --git a/sca-cpp/trunk/modules/http/http-test b/sca-cpp/trunk/modules/http/http-test
index d70db8d469..1ab0da64b9 100755
--- a/sca-cpp/trunk/modules/http/http-test
+++ b/sca-cpp/trunk/modules/http/http-test
@@ -18,17 +18,7 @@
# under the License.
# Setup
-./httpd-conf tmp 8091 htdocs
-cat >>tmp/conf/httpd.conf <<EOF
-
-<Location /test>
-SetHandler mod_tuscany_eval
-SCAContribution `pwd`/
-SCAComposite httpd-test.composite
-SCAComponent httpd-test
-</Location>
-EOF
-
+./httpd-conf tmp 8090 htdocs
apachectl -k start -d `pwd`/tmp
sleep 1
diff --git a/sca-cpp/trunk/modules/http/httpd-conf b/sca-cpp/trunk/modules/http/httpd-conf
index 10a5b47ac2..b00ee06ed3 100755
--- a/sca-cpp/trunk/modules/http/httpd-conf
+++ b/sca-cpp/trunk/modules/http/httpd-conf
@@ -31,7 +31,5 @@ ServerName 127.0.0.1
Listen $port
DocumentRoot $htdocs
TypesConfig $here/conf/mime.types
-LoadModule mod_tuscany_eval $here/.libs/libmod_tuscany_eval.so
-LoadModule mod_tuscany_wiring $here/.libs/libmod_tuscany_wiring.so
EOF
diff --git a/sca-cpp/trunk/modules/http/httpd-test b/sca-cpp/trunk/modules/http/httpd-test
index 1d9b3cb34d..57c35c5cc9 100755
--- a/sca-cpp/trunk/modules/http/httpd-test
+++ b/sca-cpp/trunk/modules/http/httpd-test
@@ -21,16 +21,6 @@ echo "Testing..."
# Setup
./httpd-conf tmp 8090 htdocs
-cat >>tmp/conf/httpd.conf <<EOF
-
-<Location /test>
-SetHandler mod_tuscany_eval
-SCAContribution `pwd`/
-SCAComposite httpd-test.composite
-SCAComponent httpd-test
-</Location>
-EOF
-
apachectl -k start -d `pwd`/tmp
sleep 1
@@ -39,37 +29,6 @@ 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
apachectl -k stop -d `pwd`/tmp
sleep 2
diff --git a/sca-cpp/trunk/modules/http/httpd.hpp b/sca-cpp/trunk/modules/http/httpd.hpp
index 1271afc03c..a9ced05208 100644
--- a/sca-cpp/trunk/modules/http/httpd.hpp
+++ b/sca-cpp/trunk/modules/http/httpd.hpp
@@ -23,7 +23,7 @@
#define tuscany_httpd_hpp
/**
- * HTTPD module utility functions.
+ * HTTPD module implementation functions.
*/
#include <string>
@@ -62,6 +62,32 @@ bool logRequests = false;
bool logContent = false;
/**
+ * Returns a server-scoped module configuration.
+ */
+template<typename C> void* makeServerConf(apr_pool_t *p, server_rec *s) {
+ C* c = new (apr_palloc(p, sizeof(C))) C(s);
+ apr_pool_cleanup_register(p, c, gc_pool_cleanupCallback<C>, apr_pool_cleanup_null) ;
+ return c;
+}
+
+template<typename C> const C& serverConf(const request_rec* r, const module* mod) {
+ return *(C*)ap_get_module_config(r->server->module_config, mod);
+}
+
+/**
+ * Returns a directory-scoped module configuration.
+ */
+template<typename C> void *makeDirConf(apr_pool_t *p, char *dirspec) {
+ C* c = new (apr_palloc(p, sizeof(C))) C(dirspec);
+ apr_pool_cleanup_register(p, c, gc_pool_cleanupCallback<C>, apr_pool_cleanup_null) ;
+ return c;
+}
+
+template<typename C> C& dirConf(const request_rec* r, const module* mod) {
+ return *(C*)ap_get_module_config(r->per_dir_config, mod);
+}
+
+/**
* Convert a path string to a list of values.
*/
const list<std::string> pathTokens(const char* p) {
@@ -111,6 +137,8 @@ int logHeader(void* r, const char* key, const char* value) {
}
const bool logRequest(request_rec* r, const std::string& msg) {
+ if (!logRequests)
+ return true;
std::cout << msg << std::endl;
std::cout << "protocol: " << optional(r->protocol) << std::endl;
std::cout << "method: " << optional(r->method) << std::endl;
@@ -128,6 +156,32 @@ const bool logRequest(request_rec* r, const std::string& msg) {
return true;
}
+const bool logValue(const value& v, const std::string& msg) {
+ if (!logContent)
+ return true;
+ std::cout<< msg << ": " << v << std::endl;
+ std::cout.flush();
+ return true;
+}
+
+const bool logValue(const failable<value, std::string>& v, const std::string& msg) {
+ if (!logContent)
+ return true;
+ std::cout<< msg << ": " << v << std::endl;
+ std::cout.flush();
+ return true;
+}
+
+const bool logStrings(const list<std::string>& ls, const std::string& msg) {
+ if (!logContent)
+ return true;
+ std::cout<< msg << ": " << std::endl;
+ write(ls, std::cout);
+ std::cout<< std::endl;
+ std::cout.flush();
+ return true;
+}
+
/**
* Returns a list of key value pairs from the args in a query string.
*/
@@ -144,6 +198,19 @@ const list<list<value> > queryArgs(const request_rec* r) {
}
/**
+ * Returns a list of param values other than the id and method args from a list
+ * of key value pairs.
+ */
+const list<value> queryParams(const list<list<value> >& a) {
+ if (isNil(a))
+ return list<value>();
+ const list<value> p = car(a);
+ if (car(p) == value("id") || car(p) == value("method"))
+ return queryParams(cdr(a));
+ return cons(cadr(p), queryParams(cdr(a)));
+}
+
+/**
* Converts the args received in a POST to a list of key value pairs.
*/
const list<list<value> > postArgs(const list<value>& a) {
@@ -153,6 +220,83 @@ const list<list<value> > postArgs(const list<value>& a) {
return cons(l, postArgs(cdr(a)));
}
+/**
+ * Setup the HTTP read policy.
+ */
+const int setupReadPolicy(request_rec* r) {
+ const int rc = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK);
+ if(rc != OK)
+ return rc;
+ ap_should_client_block(r);
+ if(r->read_chunked == true && r->remaining == 0)
+ r->chunked = true;
+ //apr_table_setn(r->headers_out, "Connection", "close");
+ return OK;
+}
+
+/**
+ * Read the content of a POST or PUT.
+ */
+const list<std::string> read(request_rec* r) {
+ char b[2048];
+ const int n = ap_get_client_block(r, b, 2048);
+ if (n <= 0)
+ return list<std::string>();
+ return cons(std::string(b, n), read(r));
+}
+
+/**
+ * Convert a URI value to an absolute URL.
+ */
+const char* url(const value& v, request_rec* r) {
+ std::string u = r->uri;
+ u.append("/");
+ u.append(v);
+ return ap_construct_url(r->pool, u.c_str(), r);
+}
+
+/**
+ * Convert an ATOM entry to a value.
+ */
+const value feedEntry(const list<value>& e) {
+ const list<value> v = elementsToValues(mklist<value>(caddr(e)));
+ return cons(car(e), mklist<value>(cadr(e), cdr<value>(car(v))));
+}
+
+/**
+ * Write an HTTP result.
+ */
+const failable<int, std::string> writeResult(const failable<list<std::string>, std::string>& ls, const std::string& ct, request_rec* r) {
+ if (!hasContent(ls))
+ return mkfailure<int, std::string>(reason(ls));
+ std::ostringstream os;
+ write(content(ls), os);
+ if (logContent) {
+ std::cout<< "content: " << std::endl << os.str() << std::endl;
+ std::cout.flush();
+ }
+
+ const std::string etag(ap_md5(r->pool, (const unsigned char*)std::string(os.str()).c_str()));
+ const char* match = apr_table_get(r->headers_in, "If-None-Match");
+ apr_table_setn(r->headers_out, "ETag", apr_pstrdup(r->pool, etag.c_str()));
+ if (match != NULL && etag == match) {
+ r->status = HTTP_NOT_MODIFIED;
+ return OK;
+ }
+ ap_set_content_type(r, ct.c_str());
+ ap_rputs(std::string(os.str()).c_str(), r);
+ return OK;
+}
+
+/**
+ * Report request execution status.
+ */
+const int reportStatus(const failable<int, std::string>& rc) {
+ if (!hasContent(rc))
+ return HTTP_INTERNAL_SERVER_ERROR;
+ return content(rc);
+}
+
}
}
diff --git a/sca-cpp/trunk/modules/http/mod-eval.cpp b/sca-cpp/trunk/modules/http/mod-eval.cpp
deleted file mode 100644
index 6fef2be2cb..0000000000
--- a/sca-cpp/trunk/modules/http/mod-eval.cpp
+++ /dev/null
@@ -1,532 +0,0 @@
-/*
- * 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 component implementations.
- */
-
-#include <sys/stat.h>
-
-#include <string>
-#include <iostream>
-#include <sstream>
-#include <fstream>
-
-#include "list.hpp"
-#include "slist.hpp"
-#include "value.hpp"
-#include "element.hpp"
-#include "monad.hpp"
-#include "../atom/atom.hpp"
-#include "../json/json.hpp"
-#include "../eval/driver.hpp"
-#include "../scdl/scdl.hpp"
-#include "../cache/cache.hpp"
-#include "curl.hpp"
-#include "httpd.hpp"
-
-extern "C" {
-extern module AP_MODULE_DECLARE_DATA mod_tuscany_eval;
-}
-
-namespace tuscany {
-namespace httpd {
-namespace modeval {
-
-/**
- * Server configuration.
- */
-class ServerConf {
-public:
- ServerConf() : home("") {
- }
- std::string home;
-};
-
-const ServerConf& serverConf(const request_rec* r) {
- return *(ServerConf*)ap_get_module_config(r->server->module_config, &mod_tuscany_eval);
-}
-
-/**
- * Port number used for wiring requests. Set it to zero to use the current
- * server port number, set it to a port number to direct wiring requests
- * to that port, for debugging or tracing for example.
- */
-int debugWiringPort = 0;
-
-/**
- * Directory configuration.
- */
-class DirConf {
-public:
- DirConf() : contributionPath(""), compositeName(""), componentName(""), implementationPath("") {
- }
- std::string contributionPath;
- std::string compositeName;
- std::string componentName;
- std::string implementationPath;
- cache::cached<failable<value, std::string> > component;
- cache::cached<failable<value, std::string> > implementation;
-};
-
-DirConf& dirConf(const request_rec* r) {
- return *(DirConf*)ap_get_module_config(r->per_dir_config, &mod_tuscany_eval);
-}
-
-/**
- * Evaluate an expression against a component implementation.
- */
-const failable<value, std::string> evalExpr(const value& expr, const value& impl) {
- gc_pool pool;
- eval::Env globalEnv = eval::setupEnvironment(pool);
- if (logContent) {
- std::cout<< "expr: " << expr << std::endl;
- std::cout.flush();
- }
- const value val = eval::evalScript(expr, impl, globalEnv, pool);
- if (logContent) {
- std::cout<< "val: " << val << std::endl;
- std::cout.flush();
- }
-
- if (isNil(val))
- return mkfailure<value, std::string>("Could not evaluate expression");
- return val;
-}
-
-/**
- * Returns a list of param values other than the id and method args from a list
- * of key value pairs.
- */
-const list<value> queryParams(const list<list<value> >& a) {
- if (isNil(a))
- return list<value>();
- const list<value> p = car(a);
- if (car(p) == value("id") || car(p) == value("method"))
- return queryParams(cdr(a));
- return cons(cadr(p), queryParams(cdr(a)));
-}
-
-/**
- * Write an HTTP result.
- */
-const failable<int, std::string> writeResult(const failable<list<std::string>, std::string>& ls, const std::string& ct, request_rec* r) {
- if (!hasValue(ls))
- return mkfailure<int, std::string>(reason(ls));
- std::ostringstream os;
- write(ls, os);
- if (logContent) {
- std::cout<< "content: " << std::endl << os.str() << std::endl;
- std::cout.flush();
- }
-
- const std::string etag(ap_md5(r->pool, (const unsigned char*)std::string(os.str()).c_str()));
- const char* match = apr_table_get(r->headers_in, "If-None-Match");
- apr_table_setn(r->headers_out, "ETag", apr_pstrdup(r->pool, etag.c_str()));
- if (match != NULL && etag == match) {
- r->status = HTTP_NOT_MODIFIED;
- return OK;
- }
- ap_set_content_type(r, ct.c_str());
- ap_rputs(std::string(os.str()).c_str(), r);
- return OK;
-}
-
-/**
- * Handle an HTTP GET.
- */
-const failable<int, std::string> get(request_rec* r, const value& impl, const list<value>& px) {
-
- // Inspect the query string
- const list<list<value> > args = 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 = std::string(cadr(ma)).c_str();
- const list<value> params = queryParams(args);
-
- // Evaluate the request expression
- const failable<value, std::string> val = evalExpr(cons<value>(func, eval::quotedParameters(append(params, px))), impl);
- if (!hasValue(val))
- return mkfailure<int, std::string>(reason(val));
-
- // Return JSON result
- json::JSONContext cx;
- return writeResult(json::jsonResult(id, val, cx), "application/json-rpc", r);
- }
-
- // Evaluate an ATOM GET request and return an ATOM feed
- const list<value> id(path(r->path_info));
- if (isNil(id)) {
- const failable<value, std::string> val = evalExpr(cons<value>("getall", eval::quotedParameters(px)), impl);
- if (!hasValue(val))
- return mkfailure<int, std::string>(reason(val));
- const value feed = val;
- return writeResult(atom::writeATOMFeed(atom::feedValuesToElements(feed)), "application/atom+xml;type=feed", r);
- }
-
- // Evaluate an ATOM GET and return an ATOM entry
- const failable<value, std::string> val = evalExpr(cons<value>("get", eval::quotedParameters(cons<value>(car(id), px))), impl);
- if (!hasValue(val))
- return mkfailure<int, std::string>(reason(val));
- const value entry = val;
- return writeResult(atom::writeATOMEntry(atom::entryValuesToElements(entry)), "application/atom+xml;type=entry", r);
-
-}
-
-/**
- * Read the content of a POST.
- */
-const list<std::string> read(request_rec* r) {
- char b[2048];
- const int n = ap_get_client_block(r, b, 2048);
- if (n <= 0)
- return list<std::string>();
- return cons(std::string(b, n), read(r));
-}
-
-/**
- * Convert a URI value to an absolute URL.
- */
-const char* url(const value& v, request_rec* r) {
- std::string u = r->uri;
- u.append("/");
- u.append(v);
- return ap_construct_url(r->pool, u.c_str(), r);
-}
-
-/**
- * Convert an ATOM entry to a value.
- */
-const value feedEntry(const list<value>& e) {
- const list<value> v = elementsToValues(mklist<value>(caddr(e)));
- return cons(car(e), mklist<value>(cadr(e), cdr<value>(car(v))));
-}
-
-/**
- * Handle an HTTP POST.
- */
-const failable<int, std::string> post(request_rec* r, const value& impl, const list<value>& px) {
- const list<std::string> ls = read(r);
- if (logContent) {
- std::cout<< "content: " << std::endl;
- write(ls, std::cout);
- std::cout<< std::endl;
- std::cout.flush();
- }
-
- // Evaluate a JSON-RPC request and return a JSON result
- const std::string ct = contentType(r);
- if (ct.find("application/json-rpc") != std::string::npos || ct.find("text/plain") != std::string::npos) {
- json::JSONContext cx;
- const list<value> json = elementsToValues(json::readJSON(ls, cx));
- const list<list<value> > args = postArgs(json);
-
- // Extract the request id, method and params
- const value id = cadr(assoc(value("id"), args));
- const value func = std::string(cadr(assoc(value("method"), args))).c_str();
- const list<value> params = (list<value>)cadr(assoc(value("params"), args));
-
- // Evaluate the request expression
- const failable<value, std::string> val = evalExpr(cons<value>(func, eval::quotedParameters(append(params, px))), impl);
- if (!hasValue(val))
- return mkfailure<int, std::string>(reason(val));
-
- // Return JSON result
- return writeResult(json::jsonResult(id, val, cx), "application/json-rpc", r);
- }
-
- // Evaluate an ATOM POST request and return the created resource location
- if (ct.find("application/atom+xml") != std::string::npos) {
-
- // Evaluate the request expression
- const value entry = feedEntry(atom::readEntry(ls));
- const failable<value, std::string> val = evalExpr(cons<value>("post", eval::quotedParameters(cons<value>(entry, px))), impl);
- if (!hasValue(val))
- return mkfailure<int, std::string>(reason(val));
-
- // Return the created resource location
- apr_table_setn(r->headers_out, "Location", apr_pstrdup(r->pool, url(val, r)));
- r->status = HTTP_CREATED;
- return OK;
- }
-
- return HTTP_NOT_IMPLEMENTED;
-}
-
-/**
- * Handle an HTTP PUT.
- */
-const failable<int, std::string> put(request_rec* r, const value& impl, const list<value>& px) {
- const list<std::string> ls = read(r);
- if (logContent) {
- std::cout<< "content: " << std::endl;
- write(ls, std::cout);
- std::cout<< std::endl;
- std::cout.flush();
- }
-
- // Evaluate an ATOM PUT request
- const list<value> id(path(r->path_info));
- const value entry = feedEntry(atom::readEntry(ls));
- const failable<value, std::string> val = evalExpr(cons<value>("put", eval::quotedParameters(append(mklist<value>(entry, car(id)), px))), impl);
- if (!hasValue(val))
- return mkfailure<int, std::string>(reason(val));
- if (val == value(false))
- return HTTP_NOT_FOUND;
- return OK;
-}
-
-/**
- * Handle an HTTP DELETE.
- */
-const failable<int, std::string> del(request_rec* r, const value& impl, const list<value>& px) {
-
- // Evaluate an ATOM delete request
- const list<value> id(path(r->path_info));
- const failable<value, std::string> val = evalExpr(cons<value>("delete", eval::quotedParameters(cons<value>(car(id), px))), impl);
- if (!hasValue(val))
- return mkfailure<int, std::string>(reason(val));
- if (val == value(false))
- return HTTP_NOT_FOUND;
- return OK;
-}
-
-/**
- * Report request execution status.
- */
-const int reportStatus(const failable<int, std::string>& rc) {
- if (!hasValue(rc))
- return HTTP_INTERNAL_SERVER_ERROR;
- return rc;
-}
-
-/**
- * Read the SCDL configuration of a component.
- */
-const failable<value, std::string> readComponent(const std::string& path, const std::string& name) {
-
- // Read composite
- std::ifstream is(path);
- if (is.fail() || is.bad())
- return mkfailure<value, std::string>("Could not read composite: " + path);
-
- // Return the component
- const list<value> c = scdl::components(readXML(streamList(is)));
- const value comp = scdl::named(name, c);
- if (isNil(comp))
- return mkfailure<value, std::string>("Could not find component: " + name);
- return comp;
-}
-
-const cache::cached<failable<value, std::string> > component(DirConf* conf) {
- const std::string path(conf->contributionPath + conf->compositeName);
- const lambda<failable<value, std::string>(std::string, std::string)> rc(readComponent);
- const lambda<unsigned long(std::string)> ft(cache::latestFileTime);
- return cache::cached<failable<value, std::string> >(curry(rc, path, conf->componentName), curry(ft, path));
-}
-
-/**
- * Read a component implementation.
- */
-const failable<value, std::string> readImplementation(const std::string path) {
- std::ifstream is(path.c_str(), std::ios_base::in);
- if (is.fail() || is.bad())
- return mkfailure<value, std::string>("Could not read implementation: " + path);
- const value impl = eval::readScript(is);
- if (isNil(impl))
- return mkfailure<value, std::string>("Could not read implementation: " + path);
- return impl;
-}
-
-const cache::cached<failable<value, std::string> > implementation(const std::string& path) {
- const lambda<failable<value, std::string>(std::string)> ri(readImplementation);
- const lambda<unsigned long(std::string)> ft(cache::latestFileTime);
- return cache::cached<failable<value, std::string> >(curry(ri, path), curry(ft, path));
-}
-
-/**
- * Convert a list of component references to a list of HTTP proxy lambdas.
- */
-const value mkproxy(const value& ref, const std::string& base, const http::CURLHandle& ch) {
- return eval::primitiveProcedure(http::proxy(base + std::string(scdl::name(ref)), ch));
-}
-
-const list<value> proxies(const list<value>& refs, const std::string& base, const http::CURLHandle& ch) {
- if (isNil(refs))
- return refs;
- return cons(mkproxy(car(refs), base, ch), proxies(cdr(refs), base, ch));
-}
-
-/**
- * HTTP request handler.
- */
-int handler(request_rec *r) {
- if(strcmp(r->handler, "mod_tuscany_eval"))
- return DECLINED;
-
- // Log the request
- if(logRequests)
- logRequest(r, "mod_tuscany_eval::handler");
-
- // Set up the read policy
- const int rc = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK);
- if(rc != OK)
- return rc;
- ap_should_client_block(r);
- if(r->read_chunked == true && r->remaining == 0)
- r->chunked = true;
- //apr_table_setn(r->headers_out, "Connection", "close");
-
- // Retrieve the latest component configuration
- DirConf& conf = dirConf(r);
- conf.component = cache::latest(conf.component);
- const failable<value, std::string> comp(conf.component);
- if (!hasValue(comp))
- return HTTP_NOT_FOUND;
-
- // Retrieve the latest implementation
- const std::string path = conf.contributionPath + std::string(scdl::uri(scdl::implementation(comp)));
- if (path != conf.implementationPath) {
- conf.implementationPath = path;
- conf.implementation = cache::latest(implementation(path));
- }
- else
- conf.implementation = cache::latest(conf.implementation);
- const failable<value, std::string> impl(conf.implementation);
- if (!hasValue(impl))
- return HTTP_NOT_FOUND;
-
- // Convert component references to configured proxy lambdas
- std::ostringstream base;
- base << "http://localhost:" << (debugWiringPort == 0? ap_get_server_port(r) : debugWiringPort) << "/references/" << std::string(scdl::name(comp)) << "/";
- http::CURLHandle ch;
- const list<value> px(proxies(scdl::references(comp), base.str(), ch));
-
- // Handle HTTP method
- if (r->header_only)
- return OK;
- if(r->method_number == M_GET)
- return reportStatus(get(r, impl, px));
- if(r->method_number == M_POST)
- return reportStatus(post(r, impl, px));
- if(r->method_number == M_PUT)
- return reportStatus(put(r, impl, px));
- if(r->method_number == M_DELETE)
- return reportStatus(del(r, impl, px));
- return HTTP_NOT_IMPLEMENTED;
-}
-
-/**
- * Configuration commands.
- */
-const char *confHome(cmd_parms *cmd, void *dummy, const char *arg) {
- ServerConf *c = (ServerConf*)ap_get_module_config(cmd->server->module_config, &mod_tuscany_eval);
- c->home = arg;
- return NULL;
-}
-const char *confContribution(cmd_parms *cmd, void *c, const char *arg) {
- DirConf* conf = (DirConf*)c;
- conf->contributionPath = arg;
- conf->component = component(conf);
- return NULL;
-}
-const char *confComposite(cmd_parms *cmd, void *c, const char *arg) {
- DirConf* conf = (DirConf*)c;
- conf->compositeName = arg;
- conf->component = component(conf);
- return NULL;
-}
-const char *confComponent(cmd_parms *cmd, void *c, const char *arg) {
- DirConf* conf = (DirConf*)c;
- conf->componentName = arg;
- conf->component = component(conf);
- return NULL;
-}
-
-void *makeDirConf(apr_pool_t *p, char *dirspec) {
- DirConf* c = new (apr_palloc(p, sizeof(DirConf))) DirConf();
- apr_pool_cleanup_register(p, c, gc_pool_cleanupCallback<DirConf>, apr_pool_cleanup_null) ;
- return c;
-}
-void* makeServerConf(apr_pool_t *p, server_rec *s) {
- ServerConf* c = new (apr_palloc(p, sizeof(ServerConf))) ServerConf();
- apr_pool_cleanup_register(p, c, gc_pool_cleanupCallback<ServerConf>, apr_pool_cleanup_null) ;
- return c;
-}
-
-/**
- * HTTP server module declaration.
- */
-const command_rec commands[] = {
- AP_INIT_TAKE1("TuscanyHome", (const char*(*)())confHome, NULL, RSRC_CONF, "Tuscany home directory"),
- AP_INIT_TAKE1("SCAContribution", (const char*(*)())confContribution, NULL, ACCESS_CONF, "SCA contribution location"),
- AP_INIT_TAKE1("SCAComposite", (const char*(*)())confComposite, NULL, ACCESS_CONF, "SCA composite location"),
- AP_INIT_TAKE1("SCAComponent", (const char*(*)())confComponent, NULL, ACCESS_CONF, "SCA component name"),
- {NULL}
-};
-
-int postConfig(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) {
- return OK;
-}
-
-void childInit(apr_pool_t* p, server_rec* svr_rec) {
- ServerConf *c = (ServerConf*)ap_get_module_config(svr_rec->module_config, &mod_tuscany_eval);
- if(c == NULL) {
- std::cerr << "[Tuscany] Due to one or more errors mod_tuscany_eval loading failed. Causing apache to stop loading." << std::endl;
- exit(APEXIT_CHILDFATAL);
- }
-}
-
-void registerHooks(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);
-}
-
-}
-}
-}
-
-extern "C" {
-
-module AP_MODULE_DECLARE_DATA mod_tuscany_eval = {
- STANDARD20_MODULE_STUFF,
- // dir config
- tuscany::httpd::modeval::makeDirConf,
- // dir merger, default is to override
- NULL,
- // server config
- tuscany::httpd::modeval::makeServerConf,
- // merge server config
- NULL,
- // command table
- tuscany::httpd::modeval::commands,
- // register hooks
- tuscany::httpd::modeval::registerHooks
-};
-
-}
diff --git a/sca-cpp/trunk/modules/json/json-test.cpp b/sca-cpp/trunk/modules/json/json-test.cpp
index fd506cea65..4d1bbffd5a 100644
--- a/sca-cpp/trunk/modules/json/json-test.cpp
+++ b/sca-cpp/trunk/modules/json/json-test.cpp
@@ -70,11 +70,11 @@ bool testJSON() {
std::istringstream is(os.str());
const list<std::string> il = streamList(is);
- const list<value> r = readJSON(il, cx);
+ const list<value> r = content(readJSON(il, cx));
assert(r == l);
std::ostringstream wos;
- write(writeJSON(r, cx), wos);
+ write(content(writeJSON(r, cx)), wos);
assert(wos.str() == os.str());
}
return true;
@@ -84,7 +84,7 @@ bool testJSONRPC() {
JSONContext cx;
{
const std::string lm("{\"id\": 1, \"method\": \"system.listMethods\", \"params\": []}");
- const list<value> e = readJSON(mklist(lm), cx);
+ const list<value> e = content(readJSON(mklist(lm), cx));
const list<value> v = elementsToValues(e);
assert(assoc<value>("id", v) == mklist<value>("id", 1));
assert(assoc<value>("method", v) == mklist<value>("method", std::string("system.listMethods")));
@@ -92,16 +92,16 @@ bool testJSONRPC() {
}
{
const std::string i("{\"id\":3,\"result\":[{\"price\":\"$2.99\",\"name\":\"Apple\"},{\"price\":\"$3.55\",\"name\":\"Orange\"},{\"price\":\"$1.55\",\"name\":\"Pear\"}]}");
- const list<value> e = readJSON(mklist(i), cx);
+ const list<value> e = content(readJSON(mklist(i), cx));
const std::string i2("{\"id\":3,\"result\":{\"0\":{\"price\":\"$2.99\",\"name\":\"Apple\"},\"1\":{\"price\":\"$3.55\",\"name\":\"Orange\"},\"2\":{\"price\":\"$1.55\",\"name\":\"Pear\"}}}");
- const list<value> e2 = readJSON(mklist(i), cx);
+ const list<value> e2 = content(readJSON(mklist(i), cx));
assert(e == e2);
}
{
const std::string i("{\"id\":3,\"result\":[{\"price\":\"$2.99\",\"name\":\"Apple\"},{\"price\":\"$3.55\",\"name\":\"Orange\"},{\"price\":\"$1.55\",\"name\":\"Pear\"}]}");
- const list<value> e = readJSON(mklist(i), cx);
+ const list<value> e = content(readJSON(mklist(i), cx));
std::ostringstream os;
- write(writeJSON(e, cx), os);
+ write(content(writeJSON(e, cx)), os);
assert(os.str() == i);
const list<value> v = elementsToValues(e);
const list<value> r = valuesToElements(v);
@@ -111,16 +111,16 @@ bool testJSONRPC() {
const list<value> r = mklist<value>(mklist<value>("id", 1), mklist<value>("result", mklist<value>(std::string("Service.get"), std::string("Service.getTotal"))));
const list<value> e = valuesToElements(r);
std::ostringstream os;
- write(writeJSON(e, cx), os);
+ write(content(writeJSON(e, cx)), os);
assert(os.str() == "{\"id\":1,\"result\":[\"Service.get\",\"Service.getTotal\"]}");
}
{
const std::string f("{\"id\":1,\"result\":[\"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}]]}");
- const list<value> r = readJSON(mklist(f), cx);
+ const list<value> r = content(readJSON(mklist(f), cx));
const list<value> v = elementsToValues(r);
const list<value> e = valuesToElements(v);
std::ostringstream os;
- write(writeJSON(e, cx), os);
+ write(content(writeJSON(e, cx)), os);
assert(os.str() == f);
}
return true;
diff --git a/sca-cpp/trunk/modules/json/json.hpp b/sca-cpp/trunk/modules/json/json.hpp
index f6c8eb5fe8..7b18d237ec 100644
--- a/sca-cpp/trunk/modules/json/json.hpp
+++ b/sca-cpp/trunk/modules/json/json.hpp
@@ -217,7 +217,7 @@ const failable<list<value>, std::string> readJSON(const list<std::string>& ilist
if(!JS_FinishJSONParse(cx, parser, JSVAL_NULL))
return mkfailure<list<value>, std::string>("JS_FinishJSONParse failed");
- if(!hasValue(consumed))
+ if(!hasContent(consumed))
return mkfailure<list<value>, std::string>(reason(consumed));
return list<value>(jsValToValue(val, cx));
@@ -318,7 +318,7 @@ const failable<bool, std::string> writeList(const list<value>& l, JSObject* o, c
// Write its children
const failable<bool, std::string> w = writeList(elementChildren(token), child, cx);
- if (!hasValue(w))
+ if (!hasContent(w))
return w;
}
}
@@ -356,7 +356,7 @@ template<typename R> const failable<R, std::string> writeJSON(const lambda<R(std
JSObject* o = JS_NewObject(cx, NULL, NULL, NULL);
jsval val = OBJECT_TO_JSVAL(o);
const failable<bool, std::string> w = writeList(l, o, cx);
- if (!hasValue(w))
+ if (!hasContent(w))
return mkfailure<R, std::string>(reason(w));
WriteContext<R> wcx(reduce, initial, cx);
@@ -370,9 +370,9 @@ template<typename R> const failable<R, std::string> writeJSON(const lambda<R(std
*/
const failable<list<std::string>, std::string> writeJSON(const list<value>& l, const JSONContext& cx) {
const failable<list<std::string>, std::string> ls = writeJSON<list<std::string> >(rcons<std::string>, list<std::string>(), l, cx);
- if (!hasValue(ls))
+ if (!hasContent(ls))
return ls;
- return reverse(list<std::string>(ls));
+ return reverse(list<std::string>(content(ls)));
}
/**
diff --git a/sca-cpp/trunk/modules/scdl/scdl-test b/sca-cpp/trunk/modules/scdl/scdl-test
deleted file mode 100755
index acef45d225..0000000000
--- a/sca-cpp/trunk/modules/scdl/scdl-test
+++ /dev/null
Binary files differ
diff --git a/sca-cpp/trunk/modules/server/Makefile.am b/sca-cpp/trunk/modules/server/Makefile.am
new file mode 100644
index 0000000000..204c8e4ae4
--- /dev/null
+++ b/sca-cpp/trunk/modules/server/Makefile.am
@@ -0,0 +1,36 @@
+# 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. -I$(top_builddir)/kernel -I${LIBXML2_INCLUDE} -I${HTTPD_INCLUDE} -I${APR_INCLUDE} -I${JS_INCLUDE} -I${CURL_INCLUDE}
+
+libmod_tuscany_eval_la_SOURCES = mod-eval.cpp
+libmod_tuscany_eval_la_LIBADD = -lpthread -L${LIBXML2_LIB} -lxml2 -L${APR_LIB} -lapr-1 -laprutil-1 -L${CURL_LIB} -lcurl -L${JS_LIB} -lmozjs
+
+libmod_tuscany_wiring_la_SOURCES = mod-wiring.cpp
+libmod_tuscany_wiring_la_LIBADD = -lpthread -L${LIBXML2_LIB} -lxml2 -L${APR_LIB} -lapr-1 -laprutil-1 -L${CURL_LIB} -lcurl -L${JS_LIB} -lmozjs
+
+client_test_SOURCES = client-test.cpp
+client_test_LDADD = -lpthread -L${LIBXML2_LIB} -lxml2 -L${APR_LIB} -lapr-1 -laprutil-1 -L${CURL_LIB} -lcurl -L${JS_LIB} -lmozjs
+
+TESTS = httpd-test http-test wiring-test
+
+
diff --git a/sca-cpp/trunk/modules/server/client-test.cpp b/sca-cpp/trunk/modules/server/client-test.cpp
new file mode 100644
index 0000000000..b43cb92c52
--- /dev/null
+++ b/sca-cpp/trunk/modules/server/client-test.cpp
@@ -0,0 +1,251 @@
+/*
+ * 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 <assert.h>
+#include <sys/time.h>
+#include <time.h>
+#include <iostream>
+#include <sstream>
+#include <string>
+#include "slist.hpp"
+#include "../http/curl.hpp"
+
+namespace tuscany {
+namespace server {
+
+const bool contains(const std::string& str, const std::string& pattern) {
+ return str.find(pattern) != str.npos;
+}
+
+const double duration(struct timeval start, struct timeval end, int count) {
+ long t = (end.tv_sec * 1000 + end.tv_usec / 1000) - (start.tv_sec * 1000 + start.tv_usec / 1000);
+ return (double)t / (double)count;
+}
+
+std::ostringstream* curlWriter(const std::string& s, std::ostringstream* os) {
+ (*os) << s;
+ return os;
+}
+
+const bool testGet() {
+ http::CURLHandle ch;
+ {
+ std::ostringstream os;
+ const failable<list<std::ostringstream*>, std::string> r = http::get<std::ostringstream*>(curlWriter, &os, "http://localhost:8090", ch);
+ assert(hasContent(r));
+ assert(contains(os.str(), "HTTP/1.1 200 OK"));
+ assert(contains(os.str(), "It works"));
+ }
+ {
+ const failable<value, std::string> r = http::get("http://localhost:8090", ch);
+ assert(hasContent(r));
+ assert(contains(content(r), "It works"));
+ }
+ return true;
+}
+
+const bool testGetLoop(const int count, http::CURLHandle& ch) {
+ if (count == 0)
+ return true;
+ const failable<value, std::string> r = get("http://localhost:8090", ch);
+ assert(hasContent(r));
+ assert(contains(content(r), "It works"));
+ return testGetLoop(count - 1, ch);
+}
+
+const bool testGetPerf() {
+ const int count = 50;
+ http::CURLHandle ch;
+ struct timeval start;
+ struct timeval end;
+ {
+ testGetLoop(5, ch);
+
+ gettimeofday(&start, NULL);
+
+ testGetLoop(count, ch);
+
+ gettimeofday(&end, NULL);
+ std::cout << "Static GET test " << duration(start, end, count) << " ms" << std::endl;
+ }
+ return true;
+}
+
+const bool testEval() {
+ http::CURLHandle ch;
+ const value val = content(http::evalExpr(mklist<value>(std::string("echo"), std::string("Hello")), "http://localhost:8090/test", ch));
+ assert(val == std::string("Hello"));
+ return true;
+}
+
+const bool testEvalLoop(const int count, http::CURLHandle& ch) {
+ if (count == 0)
+ return true;
+ const value val = content(http::evalExpr(mklist<value>(std::string("echo"), std::string("Hello")), "http://localhost:8090/test", ch));
+ assert(val == std::string("Hello"));
+ return testEvalLoop(count - 1, ch);
+}
+
+const value blob(std::string(3000, 'A'));
+const list<value> blobs = mklist(blob, blob, blob, blob, blob);
+
+const bool testBlobEvalLoop(const int count, http::CURLHandle& ch) {
+ if (count == 0)
+ return true;
+ const value val = content(http::evalExpr(mklist<value>(std::string("echo"), blobs), "http://localhost:8090/test", ch));
+ assert(val == blobs);
+ return testBlobEvalLoop(count - 1, ch);
+}
+
+const bool testEvalPerf() {
+ const int count = 50;
+ http::CURLHandle ch;
+ struct timeval start;
+ struct timeval end;
+ {
+ testEvalLoop(5, ch);
+
+ gettimeofday(&start, NULL);
+
+ testEvalLoop(count, ch);
+
+ gettimeofday(&end, NULL);
+ std::cout << "JSON-RPC eval echo test " << duration(start, end, count) << " ms" << std::endl;
+ }
+ {
+ testBlobEvalLoop(5, ch);
+
+ gettimeofday(&start, NULL);
+
+ testBlobEvalLoop(count, ch);
+
+ gettimeofday(&end, NULL);
+ std::cout << "JSON-RPC eval blob test " << duration(start, end, count) << " ms" << std::endl;
+ }
+ return true;
+}
+
+const bool testFeed() {
+ return true;
+}
+
+bool testPost() {
+ const list<value> i = list<value>()
+ << (list<value>() << "name" << std::string("Apple"))
+ << (list<value>() << "price" << std::string("$2.99"));
+ const list<value> a = mklist<value>(std::string("item"), std::string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
+ http::CURLHandle ch;
+ value rc = content(http::post(a, "http://localhost:8090/test", ch));
+ assert(rc == value(true));
+ return true;
+}
+
+const bool testPostLoop(const int count, const value& val, http::CURLHandle& ch) {
+ if (count == 0)
+ return true;
+ const value rc = content(http::post(val, "http://localhost:8090/test", ch));
+ assert(rc == value(true));
+ return testPostLoop(count - 1, val, ch);
+}
+
+const bool testPostPerf() {
+ const int count = 50;
+ http::CURLHandle ch;
+ struct timeval start;
+ struct timeval end;
+ {
+ const list<value> i = list<value>()
+ << (list<value>() << "name" << std::string("Apple"))
+ << (list<value>() << "price" << std::string("$2.99"));
+ const list<value> val = mklist<value>(std::string("item"), std::string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
+ testPostLoop(5, val, ch);
+
+ gettimeofday(&start, NULL);
+
+ testPostLoop(count, val, ch);
+
+ gettimeofday(&end, NULL);
+ std::cout << "ATOMPub POST small test " << duration(start, end, count) << " ms" << std::endl;
+ }
+ {
+ const list<value> i = list<value>()
+ << (list<value>() << "name" << std::string("Apple"))
+ << (list<value>() << "blob1" << blob)
+ << (list<value>() << "blob2" << blob)
+ << (list<value>() << "blob3" << blob)
+ << (list<value>() << "blob4" << blob)
+ << (list<value>() << "blob5" << blob)
+ << (list<value>() << "price" << std::string("$2.99"));
+ const list<value> val = mklist<value>(std::string("item"), std::string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
+ testPostLoop(5, val, ch);
+
+ gettimeofday(&start, NULL);
+
+ testPostLoop(count, val, ch);
+
+ gettimeofday(&end, NULL);
+ std::cout << "ATOMPub POST blob test " << duration(start, end, count) << " ms" << std::endl;
+ }
+ return true;
+}
+
+const bool testPut() {
+ const list<value> i = list<value>()
+ << (list<value>() << "name" << std::string("Apple"))
+ << (list<value>() << "price" << std::string("$2.99"));
+ const list<value> a = mklist<value>(std::string("item"), std::string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"), i);
+ http::CURLHandle ch;
+ value rc = content(http::put(a, "http://localhost:8090/test/111", ch));
+ assert(rc == value(true));
+ return true;
+}
+
+const bool testDel() {
+ http::CURLHandle ch;
+ value rc = content(http::del("http://localhost:8090/test/123456789", ch));
+ assert(rc == value(true));
+ return true;
+}
+
+}
+}
+
+int main() {
+ std::cout << "Testing..." << std::endl;
+
+ tuscany::server::testGet();
+ tuscany::server::testGetPerf();
+ tuscany::server::testPost();
+ tuscany::server::testPostPerf();
+ tuscany::server::testEval();
+ tuscany::server::testEvalPerf();
+ tuscany::server::testFeed();
+ tuscany::server::testPut();
+ tuscany::server::testDel();
+
+ std::cout << "OK" << std::endl;
+
+ return 0;
+}
diff --git a/sca-cpp/trunk/modules/http/htdocs/entry.xml b/sca-cpp/trunk/modules/server/htdocs/entry.xml
index 86b8a10547..86b8a10547 100644
--- a/sca-cpp/trunk/modules/http/htdocs/entry.xml
+++ b/sca-cpp/trunk/modules/server/htdocs/entry.xml
diff --git a/sca-cpp/trunk/modules/http/htdocs/feed.xml b/sca-cpp/trunk/modules/server/htdocs/feed.xml
index 5e37de6580..5e37de6580 100644
--- a/sca-cpp/trunk/modules/http/htdocs/feed.xml
+++ b/sca-cpp/trunk/modules/server/htdocs/feed.xml
diff --git a/sca-cpp/trunk/modules/server/htdocs/index.html b/sca-cpp/trunk/modules/server/htdocs/index.html
new file mode 100644
index 0000000000..1bfb3e30c2
--- /dev/null
+++ b/sca-cpp/trunk/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/trunk/modules/http/htdocs/json-request.txt b/sca-cpp/trunk/modules/server/htdocs/json-request.txt
index b4bd07fc46..b4bd07fc46 100644
--- a/sca-cpp/trunk/modules/http/htdocs/json-request.txt
+++ b/sca-cpp/trunk/modules/server/htdocs/json-request.txt
diff --git a/sca-cpp/trunk/modules/http/htdocs/json-result.txt b/sca-cpp/trunk/modules/server/htdocs/json-result.txt
index 121bf74902..121bf74902 100644
--- a/sca-cpp/trunk/modules/http/htdocs/json-result.txt
+++ b/sca-cpp/trunk/modules/server/htdocs/json-result.txt
diff --git a/sca-cpp/trunk/modules/server/http-test b/sca-cpp/trunk/modules/server/http-test
new file mode 100755
index 0000000000..6d23911c31
--- /dev/null
+++ b/sca-cpp/trunk/modules/server/http-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
+../http/httpd-conf tmp 8090 htdocs
+./server-conf tmp
+cat >>tmp/conf/httpd.conf <<EOF
+
+<Location /test>
+SetHandler mod_tuscany_eval
+SCAContribution `pwd`/
+SCAComposite httpd-test.composite
+SCAComponent httpd-test
+</Location>
+EOF
+
+apachectl -k start -d `pwd`/tmp
+sleep 1
+
+# Test
+./client-test
+rc=$?
+
+# Cleanup
+apachectl -k stop -d `pwd`/tmp
+sleep 2
+return $rc
diff --git a/sca-cpp/trunk/modules/http/httpd-client.scm b/sca-cpp/trunk/modules/server/httpd-client.scm
index 12275693f4..12275693f4 100644
--- a/sca-cpp/trunk/modules/http/httpd-client.scm
+++ b/sca-cpp/trunk/modules/server/httpd-client.scm
diff --git a/sca-cpp/trunk/modules/server/httpd-test b/sca-cpp/trunk/modules/server/httpd-test
new file mode 100755
index 0000000000..7fa2112f75
--- /dev/null
+++ b/sca-cpp/trunk/modules/server/httpd-test
@@ -0,0 +1,80 @@
+#!/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
+cat >>tmp/conf/httpd.conf <<EOF
+
+<Location /test>
+SetHandler mod_tuscany_eval
+SCAContribution `pwd`/
+SCAComposite httpd-test.composite
+SCAComponent httpd-test
+</Location>
+EOF
+
+apachectl -k start -d `pwd`/tmp
+sleep 1
+
+# 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
+apachectl -k stop -d `pwd`/tmp
+sleep 2
+if [ "$rc" = "0" ]; then
+ echo "OK"
+fi
+return $rc
diff --git a/sca-cpp/trunk/modules/http/httpd-test.composite b/sca-cpp/trunk/modules/server/httpd-test.composite
index 875d26ae1b..875d26ae1b 100644
--- a/sca-cpp/trunk/modules/http/httpd-test.composite
+++ b/sca-cpp/trunk/modules/server/httpd-test.composite
diff --git a/sca-cpp/trunk/modules/http/httpd-test.scm b/sca-cpp/trunk/modules/server/httpd-test.scm
index 0566eaf36f..0566eaf36f 100644
--- a/sca-cpp/trunk/modules/http/httpd-test.scm
+++ b/sca-cpp/trunk/modules/server/httpd-test.scm
diff --git a/sca-cpp/trunk/modules/server/mod-cpp.hpp b/sca-cpp/trunk/modules/server/mod-cpp.hpp
new file mode 100644
index 0000000000..cb24b76f6c
--- /dev/null
+++ b/sca-cpp/trunk/modules/server/mod-cpp.hpp
@@ -0,0 +1,91 @@
+/*
+ * 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 implementation.cpp
+ * component implementations.
+ */
+
+#include <string>
+#include <iostream>
+#include <fstream>
+
+#include "function.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "dynlib.hpp"
+#include "cache.hpp"
+#include "../eval/driver.hpp"
+#include "../http/httpd.hpp"
+#include "mod-eval.hpp"
+
+namespace tuscany {
+namespace server {
+namespace modeval {
+namespace cpp {
+
+/**
+ * Evaluate a C++ component implementation function.
+ */
+struct evalImplementation {
+ const lib ilib;
+ const ilambda impl;
+ evalImplementation(const lib& ilib, const ilambda& impl) : ilib(ilib), impl(impl) {
+ }
+ const failable<value, std::string> operator()(const value& func, const list<value>& params) const {
+ httpd::logValue(cons<value>(func, params), "expr");
+ const failable<value, std::string> val = impl(func, params);
+ httpd::logValue(content(val), "val");
+ return val;
+ }
+};
+
+/**
+ * Read a C++ component implementation.
+ */
+const failable<ilambda, std::string> readLatestImplementation(const std::string path) {
+ const failable<lib, std::string> ilib(dynlib(path));
+ if (!hasContent(ilib))
+ return mkfailure<ilambda, std::string>(reason(ilib));
+
+ const failable<ilambda, std::string> impl(dynlambda<failable<value, std::string>(value, list<value>)>("eval", content(ilib)));
+ if (!hasContent(impl))
+ return impl;
+ return ilambda(evalImplementation(content(ilib), content(impl)));
+}
+
+const cached<failable<ilambda, std::string> > readImplementation(const std::string& path) {
+ const lambda<failable<ilambda, std::string>(std::string)> ri(readLatestImplementation);
+ const lambda<unsigned long(std::string)> ft(latestFileTime);
+ const std::string p(path + dynlibExt);
+ return cached<failable<ilambda, std::string> >(curry(ri, p), curry(ft, p));
+}
+
+}
+}
+}
+}
+
+#endif /* tuscany_modcpp_hpp */
diff --git a/sca-cpp/trunk/modules/server/mod-eval.cpp b/sca-cpp/trunk/modules/server/mod-eval.cpp
new file mode 100644
index 0000000000..f843b9bdc5
--- /dev/null
+++ b/sca-cpp/trunk/modules/server/mod-eval.cpp
@@ -0,0 +1,387 @@
+/*
+ * 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 component implementations.
+ */
+
+#include <string>
+#include <iostream>
+#include <sstream>
+#include <fstream>
+
+#include "function.hpp"
+#include "list.hpp"
+#include "slist.hpp"
+#include "value.hpp"
+#include "element.hpp"
+#include "monad.hpp"
+#include "cache.hpp"
+#include "../atom/atom.hpp"
+#include "../json/json.hpp"
+#include "../scdl/scdl.hpp"
+#include "../http/curl.hpp"
+#include "../http/httpd.hpp"
+#include "mod-eval.hpp"
+#include "mod-scm.hpp"
+#include "mod-cpp.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("") {
+ }
+ server_rec* s;
+ std::string home;
+};
+
+/**
+ * Port number used for wiring requests. Set it to zero to use the current
+ * server port number, set it to a port number to direct wiring requests
+ * to that port, for debugging or tracing for example.
+ */
+int debugWiringPort = 0;
+
+/**
+ * Directory configuration.
+ */
+class DirConf {
+public:
+ DirConf(char* dirspec) : dirspec(dirspec), contributionPath(""), compositeName(""), componentName(""), implementationPath("") {
+ }
+ char* dirspec;
+ std::string contributionPath;
+ std::string compositeName;
+ std::string componentName;
+ std::string implementationPath;
+ cached<failable<value, std::string> > component;
+ cached<failable<ilambda, std::string> > implementation;
+};
+
+/**
+ * Handle an HTTP GET.
+ */
+const failable<int, std::string> get(request_rec* r, const ilambda& impl, const list<value>& px) {
+
+ // 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 = std::string(cadr(ma)).c_str();
+ const list<value> params = httpd::queryParams(args);
+
+ // Apply the requested function
+ const failable<value, std::string> val = impl(func, append(params, px));
+ if (!hasContent(val))
+ return mkfailure<int, std::string>(reason(val));
+
+ // Return JSON result
+ json::JSONContext cx;
+ return httpd::writeResult(json::jsonResult(id, content(val), cx), "application/json-rpc", r);
+ }
+
+ // Evaluate an ATOM GET request and return an ATOM feed
+ const list<value> id(httpd::path(r->path_info));
+ if (isNil(id)) {
+ const failable<value, std::string> val = impl("getall", px);
+ if (!hasContent(val))
+ return mkfailure<int, std::string>(reason(val));
+ return httpd::writeResult(atom::writeATOMFeed(atom::feedValuesToElements(content(val))), "application/atom+xml;type=feed", r);
+ }
+
+ // Evaluate an ATOM GET and return an ATOM entry
+ const failable<value, std::string> val = impl("get", cons<value>(car(id), px));
+ if (!hasContent(val))
+ return mkfailure<int, std::string>(reason(val));
+ return httpd::writeResult(atom::writeATOMEntry(atom::entryValuesToElements(content(val))), "application/atom+xml;type=entry", r);
+}
+
+/**
+ * Handle an HTTP POST.
+ */
+const failable<int, std::string> post(request_rec* r, const ilambda& impl, const list<value>& px) {
+ const list<std::string> ls = httpd::read(r);
+ httpd::logStrings(ls, "content");
+
+ // Evaluate a JSON-RPC request and return a JSON result
+ const std::string ct = httpd::contentType(r);
+ if (ct.find("application/json-rpc") != std::string::npos || ct.find("text/plain") != std::string::npos) {
+ 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 = std::string(cadr(assoc(value("method"), args))).c_str();
+ const list<value> params = (list<value>)cadr(assoc(value("params"), args));
+
+ // Evaluate the request expression
+ const failable<value, std::string> val = impl(func, append(params, px));
+ if (!hasContent(val))
+ return mkfailure<int, std::string>(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 created resource location
+ if (ct.find("application/atom+xml") != std::string::npos) {
+
+ // Evaluate the request expression
+ const value entry = httpd::feedEntry(content(atom::readEntry(ls)));
+ const failable<value, std::string> val = impl("post", cons<value>(entry, px));
+ if (!hasContent(val))
+ return mkfailure<int, std::string>(reason(val));
+
+ // Return the created resource location
+ apr_table_setn(r->headers_out, "Location", apr_pstrdup(r->pool, httpd::url(content(val), r)));
+ r->status = HTTP_CREATED;
+ return OK;
+ }
+
+ return HTTP_NOT_IMPLEMENTED;
+}
+
+/**
+ * Handle an HTTP PUT.
+ */
+const failable<int, std::string> put(request_rec* r, const ilambda& impl, const list<value>& px) {
+ const list<std::string> ls = httpd::read(r);
+ httpd::logStrings(ls, "content");
+
+ // Evaluate an ATOM PUT request
+ const list<value> id(httpd::path(r->path_info));
+ const value entry = httpd::feedEntry(content(atom::readEntry(ls)));
+ const failable<value, std::string> val = impl("put", append(mklist<value>(entry, car(id)), px));
+ if (!hasContent(val))
+ return mkfailure<int, std::string>(reason(val));
+ if (val == value(false))
+ return HTTP_NOT_FOUND;
+ return OK;
+}
+
+/**
+ * Handle an HTTP DELETE.
+ */
+const failable<int, std::string> del(request_rec* r, const ilambda& impl, const list<value>& px) {
+
+ // Evaluate an ATOM delete request
+ const list<value> id(httpd::path(r->path_info));
+ const failable<value, std::string> val = impl("delete", cons<value>(car(id), px));
+ if (!hasContent(val))
+ return mkfailure<int, std::string>(reason(val));
+ if (val == value(false))
+ return HTTP_NOT_FOUND;
+ return OK;
+}
+
+/**
+ * Read the SCDL configuration of a component.
+ */
+const failable<value, std::string> readComponent(const std::string& path, const std::string& name) {
+
+ // Read composite
+ std::ifstream is(path);
+ if (is.fail() || is.bad())
+ return mkfailure<value, std::string>("Could not read composite: " + path);
+
+ // Return the component
+ const list<value> c = scdl::components(readXML(streamList(is)));
+ const value comp = scdl::named(name, c);
+ if (isNil(comp))
+ return mkfailure<value, std::string>("Could not find component: " + name);
+ return comp;
+}
+
+const cached<failable<value, std::string> > component(DirConf* conf) {
+ const std::string path(conf->contributionPath + conf->compositeName);
+ const lambda<failable<value, std::string>(std::string, std::string)> rc(readComponent);
+ const lambda<unsigned long(std::string)> ft(latestFileTime);
+ return cached<failable<value, std::string> >(curry(rc, path, conf->componentName), curry(ft, path));
+}
+
+/**
+ * Convert a list of component references to a list of HTTP proxy lambdas.
+ */
+const value mkproxy(const value& ref, const std::string& base, const http::CURLHandle& ch) {
+ return eval::primitiveProcedure(http::proxy(base + std::string(scdl::name(ref)), ch));
+}
+
+const list<value> proxies(const list<value>& refs, const std::string& base, const http::CURLHandle& ch) {
+ if (isNil(refs))
+ return refs;
+ return cons(mkproxy(car(refs), base, ch), proxies(cdr(refs), base, ch));
+}
+
+/**
+ * Returns the component implementation with the given implementation type and path.
+ * For now only Scheme and C++ implementations are supported.
+ */
+const cached<failable<ilambda, std::string> > implementation(const std::string& itype, const std::string& path) {
+ if (itype.find(".scheme") != std::string::npos)
+ return latest(scm::readImplementation(path));
+ if (itype.find(".cpp") != std::string::npos)
+ return latest(cpp::readImplementation(path));
+ return cached<failable<ilambda, std::string> >();
+}
+
+/**
+ * HTTP request handler.
+ */
+int handler(request_rec *r) {
+ if(strcmp(r->handler, "mod_tuscany_eval"))
+ return DECLINED;
+ httpd::logRequest(r, "mod_tuscany_eval::handler");
+
+ // Set up the read policy
+ const int rc = httpd::setupReadPolicy(r);
+ if(rc != OK)
+ return rc;
+
+ // Retrieve the latest component configuration
+ DirConf& conf = httpd::dirConf<DirConf>(r, &mod_tuscany_eval);
+ conf.component = latest(conf.component);
+ const failable<value, std::string> comp(content(conf.component));
+ if (!hasContent(comp))
+ return HTTP_NOT_FOUND;
+
+ // Retrieve the latest implementation
+ const value ielement= scdl::implementation(content(comp));
+ const std::string path = conf.contributionPath + std::string(scdl::uri(ielement));
+ if (path != conf.implementationPath) {
+ conf.implementationPath = path;
+ conf.implementation = implementation(elementName(ielement), path);
+ }
+ else
+ conf.implementation = latest(conf.implementation);
+ const failable<ilambda, std::string> impl(content(conf.implementation));
+ if (!hasContent(impl))
+ return HTTP_NOT_FOUND;
+
+ // Convert component references to configured proxy lambdas
+ std::ostringstream base;
+ base << "http://localhost:" << (debugWiringPort == 0? ap_get_server_port(r) : debugWiringPort) << "/references/" << std::string(scdl::name(content(comp))) << "/";
+ http::CURLHandle ch;
+ const list<value> px(proxies(scdl::references(content(comp)), base.str(), ch));
+
+ // Handle HTTP method
+ if (r->header_only)
+ return OK;
+ if(r->method_number == M_GET)
+ return httpd::reportStatus(get(r, content(impl), px));
+ if(r->method_number == M_POST)
+ return httpd::reportStatus(post(r, content(impl), px));
+ if(r->method_number == M_PUT)
+ return httpd::reportStatus(put(r, content(impl), px));
+ if(r->method_number == M_DELETE)
+ return httpd::reportStatus(del(r, content(impl), px));
+ return HTTP_NOT_IMPLEMENTED;
+}
+
+/**
+ * Configuration commands.
+ */
+const char *confHome(cmd_parms *cmd, void *dummy, const char *arg) {
+ ServerConf *c = (ServerConf*)ap_get_module_config(cmd->server->module_config, &mod_tuscany_eval);
+ c->home = arg;
+ return NULL;
+}
+const char *confContribution(cmd_parms *cmd, void *c, const char *arg) {
+ DirConf* conf = (DirConf*)c;
+ conf->contributionPath = arg;
+ conf->component = component(conf);
+ return NULL;
+}
+const char *confComposite(cmd_parms *cmd, void *c, const char *arg) {
+ DirConf* conf = (DirConf*)c;
+ conf->compositeName = arg;
+ conf->component = component(conf);
+ return NULL;
+}
+const char *confComponent(cmd_parms *cmd, void *c, const char *arg) {
+ DirConf* conf = (DirConf*)c;
+ conf->componentName = arg;
+ conf->component = component(conf);
+ 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("SCAContribution", (const char*(*)())confContribution, NULL, ACCESS_CONF, "SCA contribution location"),
+ AP_INIT_TAKE1("SCAComposite", (const char*(*)())confComposite, NULL, ACCESS_CONF, "SCA composite location"),
+ AP_INIT_TAKE1("SCAComponent", (const char*(*)())confComponent, NULL, ACCESS_CONF, "SCA component name"),
+ {NULL}
+};
+
+int postConfig(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) {
+ return OK;
+}
+
+void childInit(apr_pool_t* p, server_rec* svr_rec) {
+ ServerConf *c = (ServerConf*)ap_get_module_config(svr_rec->module_config, &mod_tuscany_eval);
+ if(c == NULL) {
+ std::cerr << "[Tuscany] Due to one or more errors mod_tuscany_eval loading failed. Causing apache to stop loading." << std::endl;
+ exit(APEXIT_CHILDFATAL);
+ }
+}
+
+void registerHooks(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);
+}
+
+}
+}
+}
+
+extern "C" {
+
+module AP_MODULE_DECLARE_DATA mod_tuscany_eval = {
+ STANDARD20_MODULE_STUFF,
+ // dir config and merger
+ tuscany::httpd::makeDirConf<tuscany::server::modeval::DirConf>, NULL,
+ // server config and merger
+ tuscany::httpd::makeServerConf<tuscany::server::modeval::ServerConf>, NULL,
+ // commands and hooks
+ tuscany::server::modeval::commands, tuscany::server::modeval::registerHooks
+};
+
+}
diff --git a/sca-cpp/trunk/modules/server/mod-eval.hpp b/sca-cpp/trunk/modules/server/mod-eval.hpp
new file mode 100644
index 0000000000..a350538956
--- /dev/null
+++ b/sca-cpp/trunk/modules/server/mod-eval.hpp
@@ -0,0 +1,50 @@
+/*
+ * 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
+
+/**
+ * Defines the signature of component implementation lambdas
+ * expected by mod-eval.
+ */
+
+#include <string>
+
+#include "function.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+
+namespace tuscany {
+namespace server {
+namespace modeval {
+
+/**
+ * Represents a component implementation lambda function.
+ */
+typedef lambda<failable<value, std::string>(value, list<value>)> ilambda;
+
+}
+}
+}
+
+#endif /* tuscany_modeval_hpp */
diff --git a/sca-cpp/trunk/modules/server/mod-scm.hpp b/sca-cpp/trunk/modules/server/mod-scm.hpp
new file mode 100644
index 0000000000..386d032695
--- /dev/null
+++ b/sca-cpp/trunk/modules/server/mod-scm.hpp
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/* $Rev$ $Date$ */
+
+#ifndef tuscany_modscm_hpp
+#define tuscany_modscm_hpp
+
+/**
+ * Evaluation functions used by mod-eval to evaluate implementation.scheme
+ * component implementations.
+ */
+
+#include <string>
+#include <iostream>
+#include <fstream>
+
+#include "function.hpp"
+#include "list.hpp"
+#include "value.hpp"
+#include "monad.hpp"
+#include "cache.hpp"
+#include "../eval/driver.hpp"
+#include "../http/httpd.hpp"
+#include "mod-eval.hpp"
+
+namespace tuscany {
+namespace server {
+namespace modeval {
+namespace scm {
+
+/**
+ * Evaluate a script component implementation function.
+ */
+struct evalImplementation {
+ const value impl;
+ evalImplementation(const value& impl) : impl(impl) {
+ }
+ const failable<value, std::string> operator()(const value& func, const list<value>& params) const {
+ const value expr = cons<value>(func, eval::quotedParameters(params));
+ httpd::logValue(expr, "expr");
+ gc_pool pool;
+ eval::Env globalEnv = eval::setupEnvironment(pool);
+ const value val = eval::evalScript(expr, impl, globalEnv, pool);
+ httpd::logValue(val, "val");
+ if (isNil(val))
+ return mkfailure<value, std::string>("Could not evaluate expression");
+ return val;
+ }
+};
+
+/**
+ * Read a script component implementation.
+ */
+const failable<ilambda, std::string> readLatestImplementation(const std::string path) {
+ std::ifstream is(path.c_str(), std::ios_base::in);
+ if (is.fail() || is.bad())
+ return mkfailure<ilambda, std::string>("Could not read implementation: " + path);
+ const value impl = eval::readScript(is);
+ if (isNil(impl))
+ return mkfailure<ilambda, std::string>("Could not read implementation: " + path);
+ return ilambda(evalImplementation(impl));
+}
+
+const cached<failable<ilambda, std::string> > readImplementation(const std::string& path) {
+ const lambda<failable<ilambda, std::string>(std::string)> ri(readLatestImplementation);
+ const lambda<unsigned long(std::string)> ft(latestFileTime);
+ return cached<failable<ilambda, std::string> >(curry(ri, path), curry(ft, path));
+}
+
+}
+}
+}
+}
+
+#endif /* tuscany_modscm_hpp */
diff --git a/sca-cpp/trunk/modules/http/mod-wiring.cpp b/sca-cpp/trunk/modules/server/mod-wiring.cpp
index 965d5a87fb..2d3c8ce045 100644
--- a/sca-cpp/trunk/modules/http/mod-wiring.cpp
+++ b/sca-cpp/trunk/modules/server/mod-wiring.cpp
@@ -20,7 +20,7 @@
/* $Rev$ $Date$ */
/**
- * HTTPD module used to wire components.
+ * HTTPD module used to wire component references.
*/
#include <sys/stat.h>
@@ -34,16 +34,16 @@
#include "slist.hpp"
#include "value.hpp"
#include "monad.hpp"
+#include "cache.hpp"
#include "../scdl/scdl.hpp"
-#include "../cache/cache.hpp"
-#include "httpd.hpp"
+#include "../http/httpd.hpp"
extern "C" {
extern module AP_MODULE_DECLARE_DATA mod_tuscany_wiring;
}
namespace tuscany {
-namespace httpd {
+namespace server {
namespace modwiring {
/**
@@ -51,15 +51,12 @@ namespace modwiring {
*/
class ServerConf {
public:
- std::string home;
- ServerConf() : home("") {
+ ServerConf(server_rec* s) : home("") {
}
+ server_rec* s;
+ std::string home;
};
-const ServerConf& serverConf(const request_rec* r) {
- return *(ServerConf*)ap_get_module_config(r->server->module_config, &mod_tuscany_wiring);
-}
-
/**
* Set to true to wire using mod_proxy, false to wire using HTTP client redirects.
*/
@@ -70,17 +67,14 @@ const bool useModProxy = true;
*/
class DirConf {
public:
- DirConf() : contributionPath(""), compositeName("") {
+ DirConf(char* dirspec) : contributionPath(""), compositeName("") {
}
+ char* dirspec;
std::string contributionPath;
std::string compositeName;
- cache::cached<failable<list<value>, std::string> > components;
+ cached<failable<list<value>, std::string> > components;
};
-DirConf& dirConf(const request_rec* r) {
- return *(DirConf*)ap_get_module_config(r->per_dir_config, &mod_tuscany_wiring);
-}
-
/**
* Read the SCDL configuration of the deployed components.
*/
@@ -91,11 +85,11 @@ const failable<list<value>, std::string> readComponents(const std::string& path)
return scdl::components(readXML(streamList(is)));
}
-const cache::cached<failable<list<value>, std::string> > components(DirConf* conf) {
+const cached<failable<list<value>, std::string> > components(DirConf* conf) {
const std::string path(conf->contributionPath + conf->compositeName);
const lambda<failable<list<value>, std::string>(std::string)> rc(readComponents);
- const lambda<unsigned long(std::string)> ft(cache::latestFileTime);
- return cache::cached<failable<list<value>, std::string> >(curry(rc, path), curry(ft, path));
+ const lambda<unsigned long(std::string)> ft(latestFileTime);
+ return cached<failable<list<value>, std::string> >(curry(rc, path), curry(ft, path));
}
/**
@@ -112,19 +106,16 @@ const bool isAbsolute(const std::string& uri) {
int translate(request_rec *r) {
if (strncmp(r->uri, "/references/", 12) != 0)
return DECLINED;
- const list<value> rpath(path(r->uri));
-
- // Log the request
- if(logRequests)
- logRequest(r, "mod_tuscany_wiring::translate");
+ httpd::logRequest(r, "mod_tuscany_wiring::translate");
// Find the requested component, reference and its target configuration
- DirConf& conf = dirConf(r);
- conf.components = cache::latest(conf.components);
- const failable<list<value>, std::string> comps(conf.components);
- if (!hasValue(comps))
+ DirConf& conf = httpd::dirConf<DirConf>(r, &mod_tuscany_wiring);
+ conf.components = latest(conf.components);
+ const failable<list<value>, std::string> comps(content(conf.components));
+ if (!hasContent(comps))
return HTTP_INTERNAL_SERVER_ERROR;
- const value comp(scdl::named(cadr(rpath), list<value>(comps)));
+ const list<value> rpath(httpd::path(r->uri));
+ const value comp(scdl::named(cadr(rpath), list<value>(content(comps))));
if (isNil(comp))
return HTTP_NOT_FOUND;
const value ref(scdl::named(caddr(rpath), scdl::references(comp)));
@@ -174,10 +165,7 @@ const std::string redirect(const std::string& file, const std::string& pi, const
int handler(request_rec *r) {
if(strcmp(r->handler, "mod_tuscany_wiring"))
return DECLINED;
-
- // Log the request
- if(logRequests)
- logRequest(r, "mod_tuscany_wiring::handler");
+ httpd::logRequest(r, "mod_tuscany_wiring::handler");
// Do an internal redirect
if (r->filename == NULL || strncmp(r->filename, "/redirect:", 10) != 0)
@@ -211,17 +199,6 @@ const char *confComposite(cmd_parms *cmd, void *c, const char *arg) {
return NULL;
}
-void *makeDirConf(apr_pool_t *p, char *dirspec) {
- DirConf* c = new (apr_palloc(p, sizeof(DirConf))) DirConf();
- apr_pool_cleanup_register(p, c, gc_pool_cleanupCallback<DirConf>, apr_pool_cleanup_null) ;
- return c;
-}
-void* makeServerConf(apr_pool_t *p, server_rec *s) {
- ServerConf* c = new (apr_palloc(p, sizeof(ServerConf))) ServerConf();
- apr_pool_cleanup_register(p, c, gc_pool_cleanupCallback<ServerConf>, apr_pool_cleanup_null) ;
- return c;
-}
-
/**
* HTTP server module declaration.
*/
@@ -259,18 +236,12 @@ extern "C" {
module AP_MODULE_DECLARE_DATA mod_tuscany_wiring = {
STANDARD20_MODULE_STUFF,
- // dir config
- tuscany::httpd::modwiring::makeDirConf,
- // dir merger, default is to override
- NULL,
- // server config
- tuscany::httpd::modwiring::makeServerConf,
- // merge server config
- NULL,
- // command table
- tuscany::httpd::modwiring::commands,
- // register hooks
- tuscany::httpd::modwiring::registerHooks
+ // dir config and merger
+ tuscany::httpd::makeDirConf<tuscany::server::modwiring::DirConf>, 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/trunk/modules/server/server-conf b/sca-cpp/trunk/modules/server/server-conf
new file mode 100755
index 0000000000..dfe4265bae
--- /dev/null
+++ b/sca-cpp/trunk/modules/server/server-conf
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# 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_eval $here/.libs/libmod_tuscany_eval.so
+LoadModule mod_tuscany_wiring $here/.libs/libmod_tuscany_wiring.so
+LoadModule mod_tuscany_cache $here/.libs/libmod_tuscany_cache.so
+EOF
+
diff --git a/sca-cpp/trunk/modules/http/wiring-test b/sca-cpp/trunk/modules/server/wiring-test
index 0c3f36b513..c50732ddb2 100755
--- a/sca-cpp/trunk/modules/http/wiring-test
+++ b/sca-cpp/trunk/modules/server/wiring-test
@@ -20,7 +20,8 @@
echo "Testing..."
# Setup
-./httpd-conf tmp 8092 htdocs
+../http/httpd-conf tmp 8090 htdocs
+./server-conf tmp
cat >>tmp/conf/httpd.conf <<EOF
<Location /test>
@@ -48,37 +49,37 @@ apachectl -k start -d `pwd`/tmp
sleep 1
# Test HTTP GET
-curl http://localhost:8092/index.html 2>/dev/null >tmp/index.html
+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:8092/client/ >tmp/feed.xml 2>/dev/null
+ 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:8092/client/111 >tmp/entry.xml 2>/dev/null
+ 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:8092/client/ -X POST -H "Content-type: application/atom+xml" --data @htdocs/entry.xml 2>/dev/null
+ 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:8092/client/111 -X PUT -H "Content-type: application/atom+xml" --data @htdocs/entry.xml 2>/dev/null
+ 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:8092/client/111 -X DELETE 2>/dev/null
+ curl http://localhost:8090/client/111 -X DELETE 2>/dev/null
rc=$?
fi
# Test JSON-RPC
if [ "$rc" = "0" ]; then
- curl http://localhost:8092/client/ -X POST -H "Content-type: application/json-rpc" --data @htdocs/json-request.txt >tmp/json-result.txt 2>/dev/null
+ 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
diff --git a/sca-cpp/trunk/test/store-script/store-http-test b/sca-cpp/trunk/test/store-script/store-http-test
index 551731e856..d04eab8a6c 100755
--- a/sca-cpp/trunk/test/store-script/store-http-test
+++ b/sca-cpp/trunk/test/store-script/store-http-test
@@ -20,7 +20,8 @@
echo "Testing..."
# Setup
-../../modules/http/httpd-conf tmp 8093 htdocs
+../../modules/http/httpd-conf tmp 8090 htdocs
+../../modules/server/server-conf tmp
cat >>tmp/conf/httpd.conf <<EOF
<Location /Catalog>
@@ -62,7 +63,7 @@ apachectl -k start -d `pwd`/tmp
sleep 1
# Test HTTP GET
-curl http://localhost:8093/store.html 2>/dev/null >tmp/store.html
+curl http://localhost:8090/store.html 2>/dev/null >tmp/store.html
diff tmp/store.html htdocs/store.html
rc=$?