summaryrefslogtreecommitdiffstats
path: root/sca-cpp/trunk/modules/wsgi
diff options
context:
space:
mode:
authorjsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68>2010-02-28 20:01:44 +0000
committerjsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68>2010-02-28 20:01:44 +0000
commit8720acd237f415983c5ca2acd4b5135415114758 (patch)
tree9d736e5fcca561b60e66e5a5e0a59f924326e0c8 /sca-cpp/trunk/modules/wsgi
parent4a56fb45307de579bf3ee88935c5c22a75c03512 (diff)
Strawman WSGI integration, allowing Python components to run in a Python WSGI server.
git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@917286 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'sca-cpp/trunk/modules/wsgi')
-rw-r--r--sca-cpp/trunk/modules/wsgi/Makefile.am33
-rw-r--r--sca-cpp/trunk/modules/wsgi/app.yaml25
-rw-r--r--sca-cpp/trunk/modules/wsgi/client-test.cpp46
-rw-r--r--sca-cpp/trunk/modules/wsgi/client-test.py35
-rwxr-xr-xsca-cpp/trunk/modules/wsgi/composite.py103
-rw-r--r--sca-cpp/trunk/modules/wsgi/domain-test.composite42
-rw-r--r--sca-cpp/trunk/modules/wsgi/runtime.py30
-rw-r--r--sca-cpp/trunk/modules/wsgi/scdl.py89
-rwxr-xr-xsca-cpp/trunk/modules/wsgi/server-test30
-rw-r--r--sca-cpp/trunk/modules/wsgi/server-test.py44
-rw-r--r--sca-cpp/trunk/modules/wsgi/util.py74
-rwxr-xr-xsca-cpp/trunk/modules/wsgi/wiring-test69
-rwxr-xr-xsca-cpp/trunk/modules/wsgi/wsgi-start26
-rwxr-xr-xsca-cpp/trunk/modules/wsgi/wsgi-stop27
14 files changed, 673 insertions, 0 deletions
diff --git a/sca-cpp/trunk/modules/wsgi/Makefile.am b/sca-cpp/trunk/modules/wsgi/Makefile.am
new file mode 100644
index 0000000000..24769eb222
--- /dev/null
+++ b/sca-cpp/trunk/modules/wsgi/Makefile.am
@@ -0,0 +1,33 @@
+# 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.
+
+datadir=$(prefix)/modules/wsgi
+
+if WANT_PYTHON
+
+noinst_PROGRAMS = client-test
+
+nobase_data_DATA = *.yaml
+
+INCLUDES = -I${PYTHON_INCLUDE}
+
+client_test_SOURCES = client-test.cpp
+client_test_LDFLAGS = -lxml2 -lcurl -lmozjs
+
+TESTS = server-test
+
+endif
diff --git a/sca-cpp/trunk/modules/wsgi/app.yaml b/sca-cpp/trunk/modules/wsgi/app.yaml
new file mode 100644
index 0000000000..dc9ad1bdf7
--- /dev/null
+++ b/sca-cpp/trunk/modules/wsgi/app.yaml
@@ -0,0 +1,25 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+application: wsgi-app
+version: 1
+runtime: python
+api_version: 1
+
+handlers:
+- url: /.*
+ script: composite.py
diff --git a/sca-cpp/trunk/modules/wsgi/client-test.cpp b/sca-cpp/trunk/modules/wsgi/client-test.cpp
new file mode 100644
index 0000000000..325223d9ee
--- /dev/null
+++ b/sca-cpp/trunk/modules/wsgi/client-test.cpp
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/* $Rev$ $Date$ */
+
+/**
+ * Test HTTP client functions.
+ */
+
+#include "stream.hpp"
+#include "string.hpp"
+#include "../server/client-test.hpp"
+
+namespace tuscany {
+namespace server {
+
+string testURI = "http://localhost:8090/wsgi";
+
+}
+}
+
+int main() {
+ tuscany::cout << "Testing..." << tuscany::endl;
+
+ tuscany::server::testServer();
+
+ tuscany::cout << "OK" << tuscany::endl;
+
+ return 0;
+}
diff --git a/sca-cpp/trunk/modules/wsgi/client-test.py b/sca-cpp/trunk/modules/wsgi/client-test.py
new file mode 100644
index 0000000000..47e6cf4bda
--- /dev/null
+++ b/sca-cpp/trunk/modules/wsgi/client-test.py
@@ -0,0 +1,35 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# JSON-RPC test case
+
+def echo(x, ref):
+ return ref("echo", x)
+
+# ATOMPub test case
+
+def get(id, ref):
+ return ref("get", id)
+
+def post(collection, item, ref):
+ return ref("post", collection, item)
+
+def put(id, item, ref):
+ return ref("put", id, item)
+
+def delete(id, ref):
+ return ref("delete", id)
diff --git a/sca-cpp/trunk/modules/wsgi/composite.py b/sca-cpp/trunk/modules/wsgi/composite.py
new file mode 100755
index 0000000000..3d55aeb0ab
--- /dev/null
+++ b/sca-cpp/trunk/modules/wsgi/composite.py
@@ -0,0 +1,103 @@
+#!/usr/bin/python
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# Composite deployment and integration with WSGI
+
+from wsgiref.simple_server import make_server
+from wsgiref.handlers import CGIHandler
+from os import environ
+from sys import stderr, argv
+from util import *
+from scdl import *
+
+def requestPath(e):
+ return e.get("PATH_INFO", "")
+
+def requestMethod(e):
+ return e.get("REQUEST_METHOD", "")
+
+def contentType(ct):
+ if ct == None:
+ return []
+ return [("Content-type", ct)]
+
+def status(st):
+ if st == 200:
+ return "200 OK"
+ if st == 404:
+ return "404 Not Found"
+ if st == 201:
+ return "201 Created"
+ return "500 Internal Server Error"
+
+def result(r, st, ct = None, b = ()):
+ r(status(st), contentType(ct))
+ return b
+
+# WSGI application function
+def application(e, r):
+
+ # Read the deployed composite
+ comps = components(parse("domain-test.composite"))
+ print >> stderr, comps
+
+ # Find the requested component
+ path = tokens(requestPath(e))
+ uc = uriToComponent(path, comps)
+ uri = car(uc)
+ if uri == None:
+ return result(r, 404)
+ comp = cadr(uc)
+ mod = __import__(cadr(comp))
+
+ # Call the requested component function
+ id = path[len(uri):]
+ print >> stderr, id
+ m = requestMethod(e)
+ if (m == "GET"):
+ v = mod.get(id)
+ print >> stderr, v
+
+ # write returned content-type / content pair
+ if not isinstance(cadr(v), basestring):
+ return result(r, 200, car(v), cadr(v))
+
+ # TODO write an ATOM feed or entry
+ if nil(id):
+ return result(r, 200, "application/atom+xml;type=feed", ("Atom feed"))
+ return result(r, 200, "application/atom+xml;type=entry", ("Atom entry"))
+
+ if m == "DELETE":
+ v = mod.delete(id)
+ if v == False:
+ return result(r, 404)
+ return result(r, 200)
+
+ # TODO implement POST and PUT methods
+ return result(r, 500)
+
+def serverType(e):
+ return e.get("SERVER_SOFTWARE", "")
+
+# Run the WSGI application
+if __name__ == "__main__":
+ st = serverType(environ)
+ if st == "":
+ make_server("", int(argv[1]), application).serve_forever()
+ else:
+ CGIHandler().run(application)
diff --git a/sca-cpp/trunk/modules/wsgi/domain-test.composite b/sca-cpp/trunk/modules/wsgi/domain-test.composite
new file mode 100644
index 0000000000..9c44ebf5d8
--- /dev/null
+++ b/sca-cpp/trunk/modules/wsgi/domain-test.composite
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+-->
+<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912"
+ xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"
+ targetNamespace="http://domain/test"
+ name="domain-test">
+
+ <component name="wsgi-test">
+ <t:implementation.python script="server-test.py"/>
+ <service name="test">
+ <t:binding.http uri="wsgi"/>
+ </service>
+ </component>
+
+ <component name="client-test">
+ <t:implementation.python script="client-test.py"/>
+ <service name="client">
+ <t:binding.http uri="client"/>
+ </service>
+ <reference name="ref" target="wsgi-test">
+ <t:binding.http/>
+ </reference>
+ </component>
+
+</composite>
diff --git a/sca-cpp/trunk/modules/wsgi/runtime.py b/sca-cpp/trunk/modules/wsgi/runtime.py
new file mode 100644
index 0000000000..930351ac3e
--- /dev/null
+++ b/sca-cpp/trunk/modules/wsgi/runtime.py
@@ -0,0 +1,30 @@
+# 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.
+
+# Component invocation functions
+
+from util import *
+
+def apply(impl, refs, func, params):
+ m = __import__(impl)
+ f = m.__getattribute__(func)
+ p = refs + params
+ return f(*p)
+
+def refapply(comps, target):
+ return comps["target"]
+
diff --git a/sca-cpp/trunk/modules/wsgi/scdl.py b/sca-cpp/trunk/modules/wsgi/scdl.py
new file mode 100644
index 0000000000..a6bb48bc65
--- /dev/null
+++ b/sca-cpp/trunk/modules/wsgi/scdl.py
@@ -0,0 +1,89 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# SCDL parsing functions
+
+from util import *
+
+def mkcomponent(name, impl, svcs, refs):
+ return (name, impl, svcs, refs)
+
+def implementation(e):
+ if len(e) == 0 or match(car(e), "end", "component") == True:
+ return ""
+ if match(car(e), "start", "implementation.python") == False:
+ return implementation(cdr(e))
+ if "script" in att(car(e)):
+ s = att(car(e))["script"]
+ return s[0:len(s) - 3]
+ return None
+
+def binding(e):
+ if len(e) == 0 or match(car(e), "end", "reference") == True or match(car(e), "end", "service") == True:
+ return ()
+ if match(car(e), "start", "binding.") == False:
+ return binding(cdr(e))
+ return tokens(att(car(e))["uri"])
+
+def references(e):
+ if len(e) == 0 or match(car(e), "end", "component") == True:
+ return ()
+ if match(car(e), "start", "reference") == False:
+ return references(cdr(e))
+ if "target" in att(car(e)):
+ return (att(car(e))["target"],) + references(cdr(e))
+ return cons(binding(e), references(cdr(e)))
+
+def services(e):
+ if len(e) == 0 or match(car(e), "end", "component") == True:
+ return ()
+ if match(car(e), "start", "service") == False:
+ return services(cdr(e))
+ return cons(binding(e), services(cdr(e)))
+
+def name(e):
+ return att(car(e))["name"]
+
+def components(e):
+ if len(e) == 0:
+ return ()
+ if match(car(e), "start", "component") == False:
+ return components(cdr(e))
+ n = name(e)
+ return cons(mkcomponent(n, implementation(e), cons(("components", n), services(e)), references(e)), components(cdr(e)))
+
+def nameToComponent(n, c):
+ if c == ():
+ return None
+ if car(car(c)) == n:
+ return car(c)
+ return nameToComponent(n, cdr(c))
+
+def matchingURI(u, s):
+ if s == ():
+ return None
+ if car(s) == u[0:len(car(s))]:
+ return car(s)
+ return matchingURI(u, cdr(s))
+
+def uriToComponent(u, c):
+ if c == ():
+ return (None, None)
+ m = matchingURI(u, caddr(car(c)))
+ if m != None:
+ return (m, car(c))
+ return uriToComponent(u, cdr(c))
diff --git a/sca-cpp/trunk/modules/wsgi/server-test b/sca-cpp/trunk/modules/wsgi/server-test
new file mode 100755
index 0000000000..6cbe9a9864
--- /dev/null
+++ b/sca-cpp/trunk/modules/wsgi/server-test
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# Setup
+./wsgi-start 8090
+sleep 2
+
+# Test
+./client-test 2>/dev/null
+rc=$?
+
+# Cleanup
+./wsgi-stop 8090
+return $rc
diff --git a/sca-cpp/trunk/modules/wsgi/server-test.py b/sca-cpp/trunk/modules/wsgi/server-test.py
new file mode 100644
index 0000000000..624deb8148
--- /dev/null
+++ b/sca-cpp/trunk/modules/wsgi/server-test.py
@@ -0,0 +1,44 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# JSON-RPC test case
+
+def echo(x):
+ return x
+
+# ATOMPub test case
+
+def get(id):
+ if id == ("index.html",):
+ return ("text/plain", ("It works!",))
+ if id == ():
+ return ("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))))
+
+ entry = (("'javaClass", "services.Item"), ("'name", "Apple"), ("'currencyCode", "USD"), ("'currencySymbol", "$"), ("'price", 2.99))
+ return ("Item", id[0], entry)
+
+def post(collection, item):
+ return ("123456789",)
+
+def put(id, item):
+ return true
+
+def delete(id):
+ return true
diff --git a/sca-cpp/trunk/modules/wsgi/util.py b/sca-cpp/trunk/modules/wsgi/util.py
new file mode 100644
index 0000000000..e6319b1ec2
--- /dev/null
+++ b/sca-cpp/trunk/modules/wsgi/util.py
@@ -0,0 +1,74 @@
+# 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.
+
+# Simple utility functions
+
+from xml.etree.cElementTree import iterparse
+
+# Scheme-like lists
+def cons(a, b):
+ return (a,) + b
+
+def car(l):
+ return l[0]
+
+def cdr(l):
+ return l[1:]
+
+def cadr(l):
+ return car(cdr(l))
+
+def cddr(l):
+ return cdr(cdr(l))
+
+def caddr(l):
+ return car(cddr(l))
+
+def nil(l):
+ return l == ()
+
+# Scheme-like associations
+def assoc(k, l):
+ if l == ():
+ return None
+ if k == car(car(l)):
+ return car(l)
+ return assoc(k, cdr(l))
+
+# Currying / partial function application
+def curry(f, *args):
+ return lambda *a: f(*(args + a))
+
+# Element tree utility functions
+def parse(file):
+ return map(lambda x: x, iterparse(file, events=("start", "end")))
+
+def evt(e):
+ return car(e)
+
+def elt(e):
+ return cadr(e)
+
+def att(e):
+ return elt(e).attrib
+
+def match(e, ev, tag):
+ return evt(e) == ev and elt(e).tag.find("}" + tag) != -1
+
+# Split a path
+def tokens(path):
+ return tuple(filter(lambda s: len(s) != 0, path.split("/")))
diff --git a/sca-cpp/trunk/modules/wsgi/wiring-test b/sca-cpp/trunk/modules/wsgi/wiring-test
new file mode 100755
index 0000000000..5db99641ce
--- /dev/null
+++ b/sca-cpp/trunk/modules/wsgi/wiring-test
@@ -0,0 +1,69 @@
+#!/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
+./wsgi-start 8090
+sleep 2
+
+# Test HTTP GET
+#curl http://localhost:8090/index.html 2>/dev/null >tmp/index.html
+#diff tmp/index.html ../server/htdocs/index.html
+#rc=$?
+rc="0"
+
+# Test ATOMPub
+if [ "$rc" = "0" ]; then
+ curl http://localhost:8090/client/ >tmp/feed.xml 2>/dev/null
+ diff tmp/feed.xml ../server/htdocs/feed.xml
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ curl http://localhost:8090/client/111 >tmp/entry.xml 2>/dev/null
+ diff tmp/entry.xml ../server/htdocs/entry.xml
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ curl http://localhost:8090/client/ -X POST -H "Content-type: application/atom+xml" --data @../server/htdocs/entry.xml 2>/dev/null
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ curl http://localhost:8090/client/111 -X PUT -H "Content-type: application/atom+xml" --data @../server/htdocs/entry.xml 2>/dev/null
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ curl http://localhost:8090/client/111 -X DELETE 2>/dev/null
+ rc=$?
+fi
+
+# Test JSON-RPC
+if [ "$rc" = "0" ]; then
+ curl http://localhost:8090/client/ -X POST -H "Content-type: application/json-rpc" --data @../server/htdocs/json-request.txt >tmp/json-result.txt 2>/dev/null
+ diff tmp/json-result.txt ../server/htdocs/json-result.txt
+ rc=$?
+fi
+
+# Cleanup
+./wsgi-stop 8090
+sleep 2
+if [ "$rc" = "0" ]; then
+ echo "OK"
+fi
+return $rc
diff --git a/sca-cpp/trunk/modules/wsgi/wsgi-start b/sca-cpp/trunk/modules/wsgi/wsgi-start
new file mode 100755
index 0000000000..92606d5094
--- /dev/null
+++ b/sca-cpp/trunk/modules/wsgi/wsgi-start
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# Start WSGI server
+here=`readlink -f $0`; here=`dirname $here`
+port=$1
+
+python_prefix=`cat $here/../python/python.prefix`
+$python_prefix/bin/python composite.py $port &
+
diff --git a/sca-cpp/trunk/modules/wsgi/wsgi-stop b/sca-cpp/trunk/modules/wsgi/wsgi-stop
new file mode 100755
index 0000000000..fa6f42d643
--- /dev/null
+++ b/sca-cpp/trunk/modules/wsgi/wsgi-stop
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# Stop WSGI server
+here=`readlink -f $0`; here=`dirname $here`
+port=$1
+
+python_prefix=`cat $here/../python/python.prefix`
+py="$python_prefix/bin/python composite.py $port"
+
+kill `ps -f | grep -v grep | grep "${py}" | awk '{ print $2 }'`