summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68>2010-03-06 09:23:34 +0000
committerjsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68>2010-03-06 09:23:34 +0000
commitcaf895ebaddcba6b09bbe29eee23862ba1ca0126 (patch)
treee74213a0662dd47d616f56b488f4b6fff8fb3513
parenta84a0e4d169efbc78b169aea3ab422182f156a41 (diff)
Translated XML, ATOM and JSON conversion functions from C++ to Python. Added support for JSON-RPC and ATOM to the WSGI integration. Adjusted server module test cases to help test the WSGI server.
git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@919721 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--sca-cpp/trunk/etc/git-exclude1
-rw-r--r--sca-cpp/trunk/modules/python/server-test.py4
-rw-r--r--sca-cpp/trunk/modules/wsgi/Makefile.am4
-rw-r--r--sca-cpp/trunk/modules/wsgi/app.yaml22
-rwxr-xr-xsca-cpp/trunk/modules/wsgi/atom-test.py153
-rw-r--r--sca-cpp/trunk/modules/wsgi/atomutil.py103
-rw-r--r--sca-cpp/trunk/modules/wsgi/client-test.cpp4
-rwxr-xr-xsca-cpp/trunk/modules/wsgi/composite.py123
-rw-r--r--sca-cpp/trunk/modules/wsgi/elemutil.py168
-rw-r--r--sca-cpp/trunk/modules/wsgi/htdocs/entry.xml2
-rw-r--r--sca-cpp/trunk/modules/wsgi/htdocs/feed.xml2
-rw-r--r--sca-cpp/trunk/modules/wsgi/htdocs/index.html1
-rw-r--r--sca-cpp/trunk/modules/wsgi/htdocs/json-request.txt1
-rw-r--r--sca-cpp/trunk/modules/wsgi/htdocs/json-result.txt1
-rwxr-xr-xsca-cpp/trunk/modules/wsgi/json-test.py59
-rw-r--r--sca-cpp/trunk/modules/wsgi/jsonutil.py140
-rw-r--r--sca-cpp/trunk/modules/wsgi/scdl.py85
-rwxr-xr-xsca-cpp/trunk/modules/wsgi/server-test2
-rw-r--r--sca-cpp/trunk/modules/wsgi/server-test.py4
-rwxr-xr-x[-rw-r--r--]sca-cpp/trunk/modules/wsgi/util-test (renamed from sca-cpp/trunk/modules/wsgi/runtime.py)19
-rw-r--r--sca-cpp/trunk/modules/wsgi/util.py49
-rwxr-xr-xsca-cpp/trunk/modules/wsgi/wiring-test32
-rwxr-xr-xsca-cpp/trunk/modules/wsgi/wsgi-test69
-rwxr-xr-xsca-cpp/trunk/modules/wsgi/xml-test.py74
-rw-r--r--sca-cpp/trunk/modules/wsgi/xmlutil.py114
-rw-r--r--sca-cpp/trunk/test/store-python/shopping-cart.py2
26 files changed, 1137 insertions, 101 deletions
diff --git a/sca-cpp/trunk/etc/git-exclude b/sca-cpp/trunk/etc/git-exclude
index 113a953648..9b81c5e267 100644
--- a/sca-cpp/trunk/etc/git-exclude
+++ b/sca-cpp/trunk/etc/git-exclude
@@ -66,6 +66,7 @@ doxygen
*.stamp
*.jar
*.prefix
+index.yaml
# Specific ignores
kernel-test
diff --git a/sca-cpp/trunk/modules/python/server-test.py b/sca-cpp/trunk/modules/python/server-test.py
index 8e6b79b56a..dcda763043 100644
--- a/sca-cpp/trunk/modules/python/server-test.py
+++ b/sca-cpp/trunk/modules/python/server-test.py
@@ -36,7 +36,7 @@ def post(collection, item):
return ("123456789",)
def put(id, item):
- return true
+ return True
def delete(id):
- return true
+ return True
diff --git a/sca-cpp/trunk/modules/wsgi/Makefile.am b/sca-cpp/trunk/modules/wsgi/Makefile.am
index d6e2a6f957..9df8135ab2 100644
--- a/sca-cpp/trunk/modules/wsgi/Makefile.am
+++ b/sca-cpp/trunk/modules/wsgi/Makefile.am
@@ -19,13 +19,13 @@ if WANT_PYTHON
INCLUDES = -I${PYTHON_INCLUDE}
-mod_SCRIPTS = composite.py runtime.py scdl.py util.py wsgi-start wsgi-stop
+mod_SCRIPTS = composite.py scdl.py util.py elemutil.py xmlutil.py atomutil.py jsonutil.py wsgi-start wsgi-stop
moddir = $(prefix)/modules/wsgi
client_test_SOURCES = client-test.cpp
client_test_LDFLAGS = -lxml2 -lcurl -lmozjs
noinst_PROGRAMS = client-test
-#TESTS = server-test
+TESTS = util-test wsgi-test wiring-test server-test
endif
diff --git a/sca-cpp/trunk/modules/wsgi/app.yaml b/sca-cpp/trunk/modules/wsgi/app.yaml
index dc9ad1bdf7..40addef28f 100644
--- a/sca-cpp/trunk/modules/wsgi/app.yaml
+++ b/sca-cpp/trunk/modules/wsgi/app.yaml
@@ -15,10 +15,30 @@
# specific language governing permissions and limitations
# under the License.
-application: wsgi-app
+application: sca-wsgi
version: 1
runtime: python
api_version: 1
+skip_files:
+- ^(.*/)?app\.yaml
+- ^(.*/)?app\.yml
+- ^(.*/)?index\.yaml
+- ^(.*/)?index\.yml
+- ^(.*/)?#.*#
+- ^(.*/)?.*~
+- ^(.*/)?.*\.py[co]
+- ^(.*/)?.*/RCS/.*
+- ^(.*/)?\..*
+- ^(.*/)?.*-test$
+- ^(.*/)?.*\.cpp$
+- ^(.*/)?.*\.o$
+- ^(.*/)?core$
+- ^(.*/)?.*\.out$
+- ^(.*/)?.*\.log$
+- ^(.*/)?Makefile.*
+- ^(.*/)?tmp/.*
+- ^(.*/)?wsgi-start
+- ^(.*/)?wsgi-stop
handlers:
- url: /.*
diff --git a/sca-cpp/trunk/modules/wsgi/atom-test.py b/sca-cpp/trunk/modules/wsgi/atom-test.py
new file mode 100755
index 0000000000..61435bf438
--- /dev/null
+++ b/sca-cpp/trunk/modules/wsgi/atom-test.py
@@ -0,0 +1,153 @@
+#!/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.
+
+# Test ATOM data conversion functions
+
+import unittest
+from elemutil import *
+from atomutil import *
+
+itemEntry = \
+ "<?xml version=\'1.0\' encoding=\'UTF-8\'?>\n" \
+ "<entry xmlns=\"http://www.w3.org/2005/Atom\">" \
+ "<title type=\"text\">item</title>" \
+ "<id>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b</id>" \
+ "<content type=\"application/xml\">" \
+ "<item>" \
+ "<name>Apple</name><price>$2.99</price>" \
+ "</item>" \
+ "</content>" \
+ "<link href=\"cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b\" />" \
+ "</entry>\n"
+
+incompleteEntry = \
+ "<entry xmlns=\"http://www.w3.org/2005/Atom\">" \
+ "<title>item</title><content type=\"text/xml\">" \
+ "<Item xmlns=\"http://services/\">" \
+ "<name xmlns=\"\">Orange</name>" \
+ "<price xmlns=\"\">3.55</price>" \
+ "</Item>" \
+ "</content>" \
+ "</entry>"
+
+completedEntry = \
+ "<?xml version=\'1.0\' encoding=\'UTF-8\'?>\n" \
+ "<entry xmlns=\"http://www.w3.org/2005/Atom\">" \
+ "<title type=\"text\">item</title>" \
+ "<id />" \
+ "<content type=\"application/xml\">" \
+ "<Item xmlns=\"http://services/\">" \
+ "<name xmlns=\"\">Orange</name>" \
+ "<price xmlns=\"\">3.55</price>" \
+ "</Item>" \
+ "</content><link href=\"\" />" \
+ "</entry>\n"
+
+def testEntry():
+ i = (element, "'item", (element, "'name", "Apple"), (element, "'price", "$2.99"))
+ a = ("item", "cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b", i)
+ s = writeATOMEntry(a);
+ assert car(s) == itemEntry
+
+ a2 = readATOMEntry((itemEntry,))
+ s2 = writeATOMEntry(a2)
+ assert car(s2) == itemEntry
+
+ a3 = readATOMEntry((incompleteEntry,))
+ s3 = writeATOMEntry(a3)
+ assert car(s3) == completedEntry
+ return True
+
+emptyFeed = \
+ "<?xml version=\'1.0\' encoding=\'UTF-8\'?>\n" \
+ "<feed xmlns=\"http://www.w3.org/2005/Atom\">" \
+ "<title type=\"text\">Feed</title>" \
+ "<id>1234</id>" \
+ "</feed>\n"
+
+itemFeed = \
+ "<?xml version=\'1.0\' encoding=\'UTF-8\'?>\n" \
+ "<feed xmlns=\"http://www.w3.org/2005/Atom\">" \
+ "<title type=\"text\">Feed</title>" \
+ "<id>1234</id>" \
+ "<entry xmlns=\"http://www.w3.org/2005/Atom\">" \
+ "<title type=\"text\">item</title>" \
+ "<id>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b</id>" \
+ "<content type=\"application/xml\">" \
+ "<item>" \
+ "<name>Apple</name><price>$2.99</price>" \
+ "</item>" \
+ "</content>" \
+ "<link href=\"cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b\" />" \
+ "</entry>" \
+ "<entry xmlns=\"http://www.w3.org/2005/Atom\">" \
+ "<title type=\"text\">item</title>" \
+ "<id>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83c</id>" \
+ "<content type=\"application/xml\">" \
+ "<item>" \
+ "<name>Orange</name><price>$3.55</price>" \
+ "</item>" \
+ "</content>" \
+ "<link href=\"cart-53d67a61-aa5e-4e5e-8401-39edeba8b83c\" />" \
+ "</entry>" \
+ "</feed>\n"
+
+def testFeed():
+ s = writeATOMFeed(("Feed", "1234"))
+ assert car(s) == emptyFeed
+
+ a2 = readATOMFeed((emptyFeed,))
+ s2 = writeATOMFeed(a2)
+ assert car(s2) == emptyFeed
+
+ i3 = (("item", "cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b",
+ (element, "'item", (element, "'name", "Apple"), (element, "'price", "$2.99"))),
+ ("item", "cart-53d67a61-aa5e-4e5e-8401-39edeba8b83c",
+ (element, "'item", (element, "'name", "Orange"), (element, "'price", "$3.55"))))
+ a3 = cons("Feed", cons("1234", i3))
+ s3 = writeATOMFeed(a3)
+ assert car(s3) == itemFeed
+
+ i4 = (("item", "cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b",
+ valueToElement(("'item", ("'name", "Apple"), ("'price", "$2.99")))),
+ ("item", "cart-53d67a61-aa5e-4e5e-8401-39edeba8b83c",
+ valueToElement(("'item", ("'name", "Orange"), ("'price", "$3.55")))))
+ a4 = cons("Feed", cons("1234", i4))
+ s4 = writeATOMFeed(a4)
+ assert car(s4) == itemFeed
+
+ a5 = readATOMFeed((itemFeed,));
+ s5 = writeATOMFeed(a5);
+ assert car(s5) == itemFeed
+
+ i6 = (("item", "cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b",
+ (("'name", "Apple"), ("'price", "$2.99"))),
+ ("item", "cart-53d67a61-aa5e-4e5e-8401-39edeba8b83c",
+ (("'name", "Orange"), ("'price", "$3.55"))))
+ a6 = cons("Feed", cons("1234", i6))
+ s6 = writeATOMFeed(feedValuesToElements(a6))
+ assert car(s6) == itemFeed
+
+ return True
+
+if __name__ == "__main__":
+ print "Testing..."
+ testEntry()
+ testFeed()
+ print "OK"
+
diff --git a/sca-cpp/trunk/modules/wsgi/atomutil.py b/sca-cpp/trunk/modules/wsgi/atomutil.py
new file mode 100644
index 0000000000..3e3e08b27e
--- /dev/null
+++ b/sca-cpp/trunk/modules/wsgi/atomutil.py
@@ -0,0 +1,103 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# ATOM data conversion functions
+
+from util import *
+from elemutil import *
+from xmlutil import *
+
+# Convert a list of elements to a list of values representing an ATOM entry
+def entryElementsToValues(e):
+ lt = filter(selector((element, "'title")), e)
+ t = "" if isNil(lt) else elementValue(car(lt))
+ li = filter(selector((element, "'id")), e)
+ i = "" if isNil(li) else elementValue(car(li))
+ lc = filter(selector((element, "'content")), e)
+ return (t, i, cadr(elementChildren(car(lc))))
+
+# Convert a list of elements to a list of values representing ATOM entries
+def entriesElementsToValues(e):
+ if isNil(e):
+ return e
+ return cons(entryElementsToValues(car(e)), entriesElementsToValues(cdr(e)))
+
+# Convert a list of strings to a list of values representing an ATOM entry
+def readATOMEntry(l):
+ e = readXML(l)
+ if isNil(e):
+ return ()
+ return entryElementsToValues(car(e))
+
+# Convert a list of values representy an ATOM entry to a value
+def entryValue(e):
+ v = elementsToValues((caddr(e)))
+ return cons(car(e), (cadr(e), cdr(car(v))))
+
+# Convert a list of strings to a list of values representing an ATOM feed
+def readATOMFeed(l):
+ f = readXML(l)
+ if isNil(f):
+ return ()
+ t = filter(selector((element, "'title")), car(f))
+ i = filter(selector((element, "'id")), car(f))
+ e = filter(selector((element, "'entry")), car(f))
+ if isNil(e):
+ return (elementValue(car(t)), elementValue(car(i)))
+ return cons(elementValue(car(t)), cons(elementValue(car(i)), entriesElementsToValues(e)))
+
+# Convert a list of values representy an ATOM entry to a list of elements
+def entryElement(l):
+ return (element, "'entry", (attribute, "'xmlns", "http://www.w3.org/2005/Atom"),
+ (element, "'title", (attribute, "'type", "text"), car(l)),
+ (element, "'id", cadr(l)),
+ (element, "'content", (attribute, "'type", "application/xml"), caddr(l)),
+ (element, "'link", (attribute, "'href", cadr(l))))
+
+# Convert a list of values representing ATOM entries to a list of elements
+def entriesElements(l):
+ if isNil(l):
+ return l
+ return cons(entryElement(car(l)), entriesElements(cdr(l)))
+
+# Convert a list of values representing an ATOM entry to an ATOM entry
+def writeATOMEntry(l):
+ return writeXML((entryElement(l),), True)
+
+# Convert a list of values representing an ATOM feed to an ATOM feed
+def writeATOMFeed(l):
+ f = (element, "'feed", (attribute, "'xmlns", "http://www.w3.org/2005/Atom"),
+ (element, "'title", (attribute, "'type", "text"), car(l)),
+ (element, "'id", cadr(l)))
+ if isNil(cddr(l)):
+ return writeXML((f,), True)
+ fe = f + entriesElements(cddr(l))
+ return writeXML((fe,), True)
+
+# Convert an ATOM entry containing a value to an ATOM entry containing an item element
+def entryValuesToElements(v):
+ return cons(car(v), cons(cadr(v), valuesToElements((cons("'item", caddr(v)),))))
+
+# Convert an ATOM feed containing values to an ATOM feed containing elements
+def feedValuesToElementsLoop(v):
+ if isNil(v):
+ return v
+ return cons(entryValuesToElements(car(v)), feedValuesToElementsLoop(cdr(v)))
+
+def feedValuesToElements(v):
+ return cons(car(v), cons(cadr(v), feedValuesToElementsLoop(cddr(v))))
+
diff --git a/sca-cpp/trunk/modules/wsgi/client-test.cpp b/sca-cpp/trunk/modules/wsgi/client-test.cpp
index 60241991a5..da4fff973b 100644
--- a/sca-cpp/trunk/modules/wsgi/client-test.cpp
+++ b/sca-cpp/trunk/modules/wsgi/client-test.cpp
@@ -27,9 +27,9 @@
#include "string.hpp"
#include "../server/client-test.hpp"
-int main() {
+int main(const int argc, const char** argv) {
tuscany::cout << "Testing..." << tuscany::endl;
- tuscany::server::testURI = "http://localhost:8090/wsgi";
+ tuscany::server::testURI = argc < 2? "http://localhost:8090/wsgi" : argv[1];
tuscany::server::testBlobs = false;
tuscany::server::testServer();
diff --git a/sca-cpp/trunk/modules/wsgi/composite.py b/sca-cpp/trunk/modules/wsgi/composite.py
index 3d55aeb0ab..3cccaa4ae4 100755
--- a/sca-cpp/trunk/modules/wsgi/composite.py
+++ b/sca-cpp/trunk/modules/wsgi/composite.py
@@ -20,70 +20,130 @@
from wsgiref.simple_server import make_server
from wsgiref.handlers import CGIHandler
+from wsgiref.util import request_uri
from os import environ
from sys import stderr, argv
from util import *
from scdl import *
+from atomutil import *
+from jsonutil import *
+# Return the path of an HTTP request
def requestPath(e):
return e.get("PATH_INFO", "")
+# Return the method of an HTTP request
def requestMethod(e):
return e.get("REQUEST_METHOD", "")
-def contentType(ct):
- if ct == None:
- return []
- return [("Content-type", ct)]
+# Return the method of an HTTP request
+def requestContentType(e):
+ return e.get("CONTENT_TYPE", "")
-def status(st):
+# Return the request body input stream
+def requestBody(e):
+ i = e.get("wsgi.input", None)
+ if i == None:
+ return ()
+ l = int(e.get("CONTENT_LENGTH", "0"))
+ return (i.read(l),)
+
+# Return an HTTP status
+def errstatus(st):
+ return (st, "<html><head><title>"+ st + "</title></head><body><h1>" + st[4:] + "</h1></body></html>")
+
+def status(st, b):
if st == 200:
- return "200 OK"
+ return cons("200 OK", b)
if st == 404:
- return "404 Not Found"
+ return errstatus("404 Not Found")
if st == 201:
- return "201 Created"
- return "500 Internal Server Error"
+ return cons("201 Created", b)
+ return errstatus("500 Internal Server Error")
+
+# Return an HTTP result
+def result(r, st, h = (), b = ()):
+ s = status(st, b)
+ r(car(s), list(h))
+ return cdr(s)
-def result(r, st, ct = None, b = ()):
- r(status(st), contentType(ct))
- return b
+
+# Converts the args received in a POST to a list of key value pairs
+def postArgs(a):
+ if isNil(a):
+ return ((),)
+ l = car(a);
+ return cons(l, postArgs(cdr(a)))
# WSGI application function
def application(e, r):
# Read the deployed composite
- comps = components(parse("domain-test.composite"))
- print >> stderr, comps
+ compos = components(parse("domain-test.composite"))
+ #print >> stderr, compos
+
+ # Evaluate the deployed components
+ comps = evalComponents(compos)
- # Find the requested component
+ # Get the request path and method
path = tokens(requestPath(e))
+ m = requestMethod(e)
+ if (isNil(path) or path == ("index.html",)) and m == "GET":
+ return result(r, 200, (("Content-type", "text/html"),), ("<html><body><h1>It works!</h1></body></html>",))
+
+ # Find the requested component
uc = uriToComponent(path, comps)
uri = car(uc)
if uri == None:
return result(r, 404)
- comp = cadr(uc)
- mod = __import__(cadr(comp))
-
+ comp = cadr(uc)
+
# 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
+ v = comp("get", id)
- # write returned content-type / content pair
+ # Write returned content-type / content pair
if not isinstance(cadr(v), basestring):
- return result(r, 200, car(v), cadr(v))
+ return result(r, 200, (("Content-type", 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"))
+ # Write an ATOM feed or entry
+ if isNil(id):
+ return result(r, 200, (("Content-type", "application/atom+xml;type=feed"),), writeATOMFeed(feedValuesToElements(v)))
+ return result(r, 200, (("Content-type", "application/atom+xml;type=entry"),), writeATOMEntry(entryValuesToElements(v)))
+
+ if m == "POST":
+ ct = requestContentType(e)
+ # Handle a JSON-RPC function call
+ if ct.find("application/json-rpc") != -1 or ct.find("text/plain") != -1:
+ json = elementsToValues(readJSON(requestBody(e)))
+ args = postArgs(json)
+ jid = cadr(assoc("'id", args))
+ func = funcName(cadr(assoc("'method", args)))
+ params = cadr(assoc("'params", args))
+ v = comp(func, *params)
+ return result(r, 200, (("Content-type", "application/json-rpc"),), jsonResult(jid, v))
+
+ # Handle an ATOM entry POST
+ if ct.find("application/atom+xml") != -1:
+ ae = entryValue(readATOMEntry(requestBody(e)))
+ v = comp("post", id, ae)
+ if isNil(v):
+ return result(r, 500)
+ return result(r, 201, (("Location", request_uri(e) + "/" + "/".join(v)),))
+ return result(r, 500)
+
+ if m == "PUT":
+ # Handle an ATOM entry PUT
+ ae = entryValue(readATOMEntry(requestBody(e)))
+ v = comp("put", id, ae)
+ if v == False:
+ return result(r, 404)
+ return result(r, 200)
+
if m == "DELETE":
- v = mod.delete(id)
+ v = comp("delete", id)
if v == False:
return result(r, 404)
return result(r, 200)
@@ -91,6 +151,7 @@ def application(e, r):
# TODO implement POST and PUT methods
return result(r, 500)
+# Return the WSGI server type
def serverType(e):
return e.get("SERVER_SOFTWARE", "")
@@ -99,5 +160,9 @@ if __name__ == "__main__":
st = serverType(environ)
if st == "":
make_server("", int(argv[1]), application).serve_forever()
+ elif st == "Development/1.0":
+ from google.appengine.ext.webapp.util import run_wsgi_app
+ run_wsgi_app(application)
else:
CGIHandler().run(application)
+
diff --git a/sca-cpp/trunk/modules/wsgi/elemutil.py b/sca-cpp/trunk/modules/wsgi/elemutil.py
new file mode 100644
index 0000000000..ad971ba6ba
--- /dev/null
+++ b/sca-cpp/trunk/modules/wsgi/elemutil.py
@@ -0,0 +1,168 @@
+# 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.
+
+# Functions to help represent data as lists of elements and attributes
+
+from util import *
+
+element = "'element"
+attribute = "'attribute"
+atsign = "'@"
+
+# Return true if a value is an element
+def isElement(v):
+ if not isList(v) or isNil(v) or v == None or car(v) != element:
+ return False
+ return True
+
+# Return true if a value is an attribute
+def isAttribute(v):
+ if not isList(v) or isNil(v) or v == None or car(v) != attribute:
+ return False
+ return True
+
+# Return the name of attribute
+def attributeName(l):
+ return cadr(l)
+
+# Return the value of attribute
+def attributeValue(l):
+ return caddr(l)
+
+# Return the name of an element
+def elementName(l):
+ return cadr(l)
+
+# Return true if an element has children
+def elementHasChildren(l):
+ return not isNil(cddr(l))
+
+# Return the children of an element
+def elementChildren(l):
+ return cddr(l)
+
+# Return true if an element has a value
+def elementHasValue(l):
+ r = reverse(l)
+ if isSymbol(car(r)):
+ return False
+ if isList(car(r)) and not isNil(car(r)) and isSymbol(car(car(r))):
+ return False
+ return True
+
+# Return the value of an element
+def elementValue(l):
+ return car(reverse(l))
+
+# Convert an element to a value
+def elementToValueIsList(v):
+ if not isList(v):
+ return False
+ return isNil(v) or not isSymbol(car(v))
+
+def elementToValue(t):
+ if isTaggedList(t, attribute):
+ return (atsign + attributeName(t)[1:], attributeValue(t))
+ if isTaggedList(t, element):
+ if elementHasValue(t):
+ if not elementToValueIsList(elementValue(t)):
+ return (elementName(t), elementValue(t))
+ return cons(elementName(t), (elementsToValues(elementValue(t)),))
+ return cons(elementName(t), elementsToValues(elementChildren(t)))
+ if not isList(t):
+ return t
+ return elementsToValues(t)
+
+# Convert a list of elements to a list of values
+def elementToValueIsSymbol(v):
+ if not isList(v):
+ return False
+ if (isNil(v)):
+ return False
+ if not isSymbol(car(v)):
+ return False
+ return True
+
+def elementToValueGroupValues(v, l):
+ if isNil(l) or not elementToValueIsSymbol(v) or not elementToValueIsSymbol(car(l)):
+ return cons(v, l)
+ if car(car(l)) != car(v):
+ return cons(v, l)
+ if not elementToValueIsList(cadr(car(l))):
+ g = (car(v), (cdr(v), cdr(car(l))))
+ return elementToValueGroupValues(g, cdr(l))
+ g = (car(v), cons(cdr(v), cadr(car(l))))
+ return elementToValueGroupValues(g, cdr(l))
+
+def elementsToValues(e):
+ if isNil(e):
+ return e
+ return elementToValueGroupValues(elementToValue(car(e)), elementsToValues(cdr(e)))
+
+# Convert a value to an element
+def valueToElement(t):
+ if isList(t) and not isNil(t) and isSymbol(car(t)):
+ n = car(t)
+ v = cadr(t)
+ if not isList(v):
+ if n[0:2] == atsign:
+ return (attribute, n[1:], v)
+ return (element, n, v)
+ if isNil(v) or not isSymbol(car(v)):
+ return cons(element, cons(n, (valuesToElements(v),)))
+ return cons(element, cons(n, valuesToElements(cdr(t))))
+ if not isList(t):
+ return t
+ return valuesToElements(t)
+
+# Convert a list of values to a list of elements
+def valuesToElements(l):
+ if isNil(l):
+ return l
+ return cons(valueToElement(car(l)), valuesToElements(cdr(l)))
+
+# Return a selector lambda function which can be used to filter elements
+def evalSelect(s, v):
+ if isNil(s):
+ return True
+ if isNil(v):
+ return False
+ if car(s) != car(v):
+ return False
+ return evalSelect(cdr(s), cdr(v))
+
+def selector(s):
+ return lambda v: evalSelect(s, v)
+
+# Return the value of the attribute with the given name
+def namedAttributeValue(name, l):
+ f = filter(lambda v: isAttribute(v) and attributeName(v) == name, l)
+ if isNil(f):
+ return None
+ return caddr(car(f))
+
+# Return child elements with the given name
+def namedElementChildren(name, l):
+ return filter(lambda v: isElement(v) and elementName(v) == name, l)
+
+# Return the child element with the given name
+def namedElementChild(name, l):
+ f = namedElementChildren(name, l)
+ if isNil(f):
+ return None
+ return car(f)
+
diff --git a/sca-cpp/trunk/modules/wsgi/htdocs/entry.xml b/sca-cpp/trunk/modules/wsgi/htdocs/entry.xml
new file mode 100644
index 0000000000..5796cd655f
--- /dev/null
+++ b/sca-cpp/trunk/modules/wsgi/htdocs/entry.xml
@@ -0,0 +1,2 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<entry xmlns="http://www.w3.org/2005/Atom"><title type="text">Item</title><id>111</id><content type="application/xml"><item><javaClass>services.Item</javaClass><name>Apple</name><currencyCode>USD</currencyCode><currencySymbol>$</currencySymbol><price>2.99</price></item></content><link href="111" /></entry>
diff --git a/sca-cpp/trunk/modules/wsgi/htdocs/feed.xml b/sca-cpp/trunk/modules/wsgi/htdocs/feed.xml
new file mode 100644
index 0000000000..d15b265f15
--- /dev/null
+++ b/sca-cpp/trunk/modules/wsgi/htdocs/feed.xml
@@ -0,0 +1,2 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<feed xmlns="http://www.w3.org/2005/Atom"><title type="text">Sample Feed</title><id>123456789</id><entry xmlns="http://www.w3.org/2005/Atom"><title type="text">Item</title><id>111</id><content type="application/xml"><item><javaClass>services.Item</javaClass><name>Apple</name><currencyCode>USD</currencyCode><currencySymbol>$</currencySymbol><price>2.99</price></item></content><link href="111" /></entry><entry xmlns="http://www.w3.org/2005/Atom"><title type="text">Item</title><id>222</id><content type="application/xml"><item><javaClass>services.Item</javaClass><name>Orange</name><currencyCode>USD</currencyCode><currencySymbol>$</currencySymbol><price>3.55</price></item></content><link href="222" /></entry><entry xmlns="http://www.w3.org/2005/Atom"><title type="text">Item</title><id>333</id><content type="application/xml"><item>('name', 'Pear')<javaClass>services.Item</javaClass><currencyCode>USD</currencyCode><currencySymbol>$</currencySymbol><price>1.55</price></item></content><link href="333" /></entry></feed>
diff --git a/sca-cpp/trunk/modules/wsgi/htdocs/index.html b/sca-cpp/trunk/modules/wsgi/htdocs/index.html
new file mode 100644
index 0000000000..cd25bf17b3
--- /dev/null
+++ b/sca-cpp/trunk/modules/wsgi/htdocs/index.html
@@ -0,0 +1 @@
+<html><body><h1>It works!</h1></body></html> \ No newline at end of file
diff --git a/sca-cpp/trunk/modules/wsgi/htdocs/json-request.txt b/sca-cpp/trunk/modules/wsgi/htdocs/json-request.txt
new file mode 100644
index 0000000000..b4bd07fc46
--- /dev/null
+++ b/sca-cpp/trunk/modules/wsgi/htdocs/json-request.txt
@@ -0,0 +1 @@
+{"id":1,"method":"echo","params":["Hello"]}
diff --git a/sca-cpp/trunk/modules/wsgi/htdocs/json-result.txt b/sca-cpp/trunk/modules/wsgi/htdocs/json-result.txt
new file mode 100644
index 0000000000..121bf74902
--- /dev/null
+++ b/sca-cpp/trunk/modules/wsgi/htdocs/json-result.txt
@@ -0,0 +1 @@
+{"id":1,"result":"Hello"} \ No newline at end of file
diff --git a/sca-cpp/trunk/modules/wsgi/json-test.py b/sca-cpp/trunk/modules/wsgi/json-test.py
new file mode 100755
index 0000000000..2f2a755bff
--- /dev/null
+++ b/sca-cpp/trunk/modules/wsgi/json-test.py
@@ -0,0 +1,59 @@
+#!/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.
+
+# Test JSON data conversion functions
+
+import unittest
+from elemutil import *
+from jsonutil import *
+
+def testJSON():
+ ad = ((attribute, "'city", "san francisco"), (attribute, "'state", "ca"))
+ ac = ((element, "'id", "1234"), (attribute, "'balance", 1000))
+ cr = ((attribute, "'name", "jdoe"), cons(element, cons("'address", ad)), cons(element, cons("'account", ac)))
+ c = (cons(element, cons("'customer", cr)),)
+ s = writeJSON(c);
+ assert car(s) == "{\"customer\":{\"account\":{\"@balance\":1000,\"id\":\"1234\"},\"@name\":\"jdoe\",\"address\":{\"@city\":\"san francisco\",\"@state\":\"ca\"}}}"
+
+ phones = ("408-1234", "650-1234")
+ l = ((element, "'phones", phones), (element, "'lastName", "test\ttab"), (attribute, "'firstName", "test1"))
+ s2 = writeJSON(l);
+ assert car(s2) == "{\"phones\":[\"408-1234\",\"650-1234\"],\"@firstName\":\"test1\",\"lastName\":\"test\\ttab\"}"
+
+ r = readJSON(s2)
+ assert r == ((element, "'lastName", "test\ttab"), (attribute, "'firstName", "test1"), (element, "'phones", phones))
+ w = writeJSON(r)
+ assert car(w) == "{\"lastName\":\"test\\ttab\",\"@firstName\":\"test1\",\"phones\":[\"408-1234\",\"650-1234\"]}"
+
+ l4 = (("'ns1:echoString", ("'@xmlns:ns1", "http://ws.apache.org/axis2/services/echo"), ("'text", "Hello World!")),)
+ s4 = writeJSON(valuesToElements(l4))
+ assert car(s4) == "{\"ns1:echoString\":{\"@xmlns:ns1\":\"http://ws.apache.org/axis2/services/echo\",\"text\":\"Hello World!\"}}"
+
+ r4 = elementsToValues(readJSON(s4))
+ assert r4 == (("'ns1:echoString", ("'text", 'Hello World!'), ("'@xmlns:ns1", 'http://ws.apache.org/axis2/services/echo')),)
+ return True
+
+def testJSONRPC():
+ return True
+
+if __name__ == "__main__":
+ print "Testing..."
+ testJSON()
+ testJSONRPC()
+ print "OK"
+
diff --git a/sca-cpp/trunk/modules/wsgi/jsonutil.py b/sca-cpp/trunk/modules/wsgi/jsonutil.py
new file mode 100644
index 0000000000..ad34d785bf
--- /dev/null
+++ b/sca-cpp/trunk/modules/wsgi/jsonutil.py
@@ -0,0 +1,140 @@
+# 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 data conversion functions
+
+try:
+ import json
+except:
+ from django.utils import simplejson as json
+
+from StringIO import StringIO
+from util import *
+from elemutil import *
+
+# Return true if a list represents a JS array
+def isJSArray(l):
+ if isNil(l):
+ return True
+ v = car(l)
+ if isSymbol(v):
+ return False
+ if isList(v):
+ if not isNil(v) and isSymbol(car(v)):
+ return False
+ return True
+
+# Converts JSON properties to values
+def jsPropertiesToValues(propertiesSoFar, o, i):
+ if isNil(i):
+ return propertiesSoFar
+ p = car(i)
+ jsv = o[p]
+ v = jsValToValue(jsv)
+
+ if isinstance(p, basestring):
+ n = str(p)
+ if n[0:1] == "@":
+ return jsPropertiesToValues(cons((attribute, "'" + n[1:], v), propertiesSoFar), o, cdr(i))
+ if isList(v) and not isJSArray(v):
+ return jsPropertiesToValues(cons(cons(element, cons("'" + n, v)), propertiesSoFar), o, cdr(i))
+ return jsPropertiesToValues(cons((element, "'" + n, v), propertiesSoFar), o, cdr(i))
+ return jsPropertiesToValues(cons(v, propertiesSoFar), o, cdr(i))
+
+# Converts a JSON val to a value
+def jsValToValue(jsv):
+ if isinstance(jsv, dict):
+ return jsPropertiesToValues((), jsv, tuple(jsv.keys()))
+ if isList(jsv):
+ return jsPropertiesToValues((), jsv, tuple(reversed(range(0, len(jsv)))))
+ if isinstance(jsv, basestring):
+ return str(jsv)
+ return jsv
+
+# Convert a list of strings representing a JSON document to a list of values
+def readJSON(l):
+ s = StringIO()
+ writeStrings(l, s)
+ val = json.loads(s.getvalue())
+ return jsValToValue(val)
+
+# Convert a list of values to JSON array elements
+def valuesToJSElements(a, l, i):
+ if isNil(l):
+ return a
+ pv = valueToJSVal(car(l))
+ a[i] = pv
+ return valuesToJSElements(a, cdr(l), i + 1)
+
+# Convert a value to a JSON value
+def valueToJSVal(v):
+ if not isList(v):
+ return v
+ if isJSArray(v):
+ return valuesToJSElements(list(range(0, len(v))), v, 0)
+ return valuesToJSProperties({}, v)
+
+# Convert a list of values to JSON properties
+def valuesToJSProperties(o, l):
+ if isNil(l):
+ return o
+ token = car(l)
+ if isTaggedList(token, attribute):
+ pv = valueToJSVal(attributeValue(token))
+ o["@" + attributeName(token)[1:]] = pv
+ elif isTaggedList(token, element):
+ if elementHasValue(token):
+ pv = valueToJSVal(elementValue(token))
+ o[elementName(token)[1:]] = pv
+ else:
+ child = {}
+ o[elementName(token)[1:]] = child
+ valuesToJSProperties(child, elementChildren(token))
+ return valuesToJSProperties(o, cdr(l))
+
+# Convert a list of values to a list of strings representing a JSON document
+def writeJSON(l):
+ jsv = valuesToJSProperties({}, l)
+ s = json.dumps(jsv, separators=(',',':'))
+ return (s,)
+
+# Convert a list + params to a JSON-RPC request
+def jsonRequest(id, func, params):
+ r = (("'id", id), ("'method", func), ("'params", params))
+ return writeJSON(valuesToElements(r))
+
+# Convert a value to a JSON-RPC result
+def jsonResult(id, val):
+ return writeJSON(valuesToElements((("'id", id), ("'result", val))))
+
+# Convert a JSON-RPC result to a value
+def jsonResultValue(s):
+ jsres = readJSON(s)
+ rval = cadr(elementsToValues(jsres))
+ val = cadr(rval)
+ if isList(val) and not isJSArray(val):
+ return (val,)
+ return val
+
+# Return a portalbe function name from a JSON-RPC function name
+def funcName(f):
+ if len(f) > 7 and f.find("system.") == 0:
+ return f[7:]
+ if len(f) > 8 and f.find("Service.") == 0:
+ return f[8:]
+ return f
+
diff --git a/sca-cpp/trunk/modules/wsgi/scdl.py b/sca-cpp/trunk/modules/wsgi/scdl.py
index a6bb48bc65..056523fb23 100644
--- a/sca-cpp/trunk/modules/wsgi/scdl.py
+++ b/sca-cpp/trunk/modules/wsgi/scdl.py
@@ -17,11 +17,45 @@
# SCDL parsing functions
+from xml.etree.cElementTree import iterparse
from util import *
+# Element tree utility functions, used to parse SCDL documents
+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
+
+# Make a callable component
+class component:
+ def __init__(self, name, impl, svcs, refs):
+ self.name = name
+ self.impl = impl
+ self.mod = None
+ self.svcs = svcs
+ self.refs = refs
+ self.proxies = ()
+
+ def __call__(self, func, *args):
+ return self.mod.__getattribute__(func)(*(args + self.proxies))
+
+ def __repr__(self):
+ return repr((self.name, self.impl, self.mod, self.svcs, self.refs, self.proxies))
+
def mkcomponent(name, impl, svcs, refs):
- return (name, impl, svcs, refs)
+ return component(name, impl, svcs, refs)
+# Return the Python module name of a component implementation
def implementation(e):
if len(e) == 0 or match(car(e), "end", "component") == True:
return ""
@@ -32,6 +66,7 @@ def implementation(e):
return s[0:len(s) - 3]
return None
+# Return the URI of a binding under a SCDL service or reference element
def binding(e):
if len(e) == 0 or match(car(e), "end", "reference") == True or match(car(e), "end", "service") == True:
return ()
@@ -39,6 +74,7 @@ def binding(e):
return binding(cdr(e))
return tokens(att(car(e))["uri"])
+# Return the list of references under a SCDL component element
def references(e):
if len(e) == 0 or match(car(e), "end", "component") == True:
return ()
@@ -48,6 +84,7 @@ def references(e):
return (att(car(e))["target"],) + references(cdr(e))
return cons(binding(e), references(cdr(e)))
+# Return the list of services under a SCDL component element
def services(e):
if len(e) == 0 or match(car(e), "end", "component") == True:
return ()
@@ -55,9 +92,11 @@ def services(e):
return services(cdr(e))
return cons(binding(e), services(cdr(e)))
+# Return the name attribute of a SCDL element
def name(e):
return att(car(e))["name"]
+# Return the list of components under a SCDL composite element
def components(e):
if len(e) == 0:
return ()
@@ -66,24 +105,38 @@ def components(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 == ():
+# Find a component with a given name
+def nameToComponent(name, comps):
+ if comps == ():
return None
- if car(car(c)) == n:
- return car(c)
- return nameToComponent(n, cdr(c))
+ if car(comps).name == name:
+ return car(comps)
+ return nameToComponent(name, cdr(comps))
-def matchingURI(u, s):
- if s == ():
+# Find the URI matching a given URI in a list of service URIs
+def matchingURI(u, svcs):
+ if svcs == ():
return None
- if car(s) == u[0:len(car(s))]:
- return car(s)
- return matchingURI(u, cdr(s))
+ if car(svcs) == u[0:len(car(svcs))]:
+ return car(svcs)
+ return matchingURI(u, cdr(svcs))
-def uriToComponent(u, c):
- if c == ():
+# Return the (service URI, component) pair matching a given URI
+def uriToComponent(u, comps):
+ if comps == ():
return (None, None)
- m = matchingURI(u, caddr(car(c)))
+ m = matchingURI(u, car(comps).svcs)
if m != None:
- return (m, car(c))
- return uriToComponent(u, cdr(c))
+ return (m, car(comps))
+ return uriToComponent(u, cdr(comps))
+
+# Evaluate a component, resolve its implementation and references
+def evalComponent(comp, comps):
+ comp.mod = __import__(comp.impl)
+ comp.proxies = tuple(map(lambda r: nameToComponent(r, comps), comp.refs))
+ return comp
+
+# Evaluate a list of components
+def evalComponents(comps):
+ return tuple(map(lambda c: evalComponent(c, comps), comps))
+
diff --git a/sca-cpp/trunk/modules/wsgi/server-test b/sca-cpp/trunk/modules/wsgi/server-test
index 6cbe9a9864..3220cd2d3e 100755
--- a/sca-cpp/trunk/modules/wsgi/server-test
+++ b/sca-cpp/trunk/modules/wsgi/server-test
@@ -18,7 +18,7 @@
# under the License.
# Setup
-./wsgi-start 8090
+./wsgi-start 8090 2>/dev/null
sleep 2
# Test
diff --git a/sca-cpp/trunk/modules/wsgi/server-test.py b/sca-cpp/trunk/modules/wsgi/server-test.py
index 624deb8148..9e084a3f92 100644
--- a/sca-cpp/trunk/modules/wsgi/server-test.py
+++ b/sca-cpp/trunk/modules/wsgi/server-test.py
@@ -38,7 +38,7 @@ def post(collection, item):
return ("123456789",)
def put(id, item):
- return true
+ return True
def delete(id):
- return true
+ return True
diff --git a/sca-cpp/trunk/modules/wsgi/runtime.py b/sca-cpp/trunk/modules/wsgi/util-test
index 930351ac3e..d7a6a34101 100644..100755
--- a/sca-cpp/trunk/modules/wsgi/runtime.py
+++ b/sca-cpp/trunk/modules/wsgi/util-test
@@ -1,3 +1,5 @@
+#!/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
@@ -15,16 +17,11 @@
# specific language governing permissions and limitations
# under the License.
-# Component invocation functions
-
-from util import *
+# Run Python util test cases
+here=`readlink -f $0`; here=`dirname $here`
+python_prefix=`cat $here/../python/python.prefix`
-def apply(impl, refs, func, params):
- m = __import__(impl)
- f = m.__getattribute__(func)
- p = refs + params
- return f(*p)
+$python_prefix/bin/python xml-test.py
+$python_prefix/bin/python atom-test.py
+$python_prefix/bin/python json-test.py
-def refapply(comps, target):
- return comps["target"]
-
diff --git a/sca-cpp/trunk/modules/wsgi/util.py b/sca-cpp/trunk/modules/wsgi/util.py
index e6319b1ec2..d945c7bdef 100644
--- a/sca-cpp/trunk/modules/wsgi/util.py
+++ b/sca-cpp/trunk/modules/wsgi/util.py
@@ -17,8 +17,6 @@
# Simple utility functions
-from xml.etree.cElementTree import iterparse
-
# Scheme-like lists
def cons(a, b):
return (a,) + b
@@ -38,13 +36,32 @@ def cddr(l):
def caddr(l):
return car(cddr(l))
-def nil(l):
+def reverse(l):
+ r = list(l)
+ r.reverse()
+ return tuple(r)
+
+def isNil(l):
return l == ()
+def isSymbol(v):
+ return isinstance(v, basestring) and v[0:1] == "'"
+
+def isList(v):
+ if getattr(v, '__iter__', False) == False:
+ return False
+ if isinstance(v, basestring) or isinstance(v, dict):
+ return False
+ return True
+
+def isTaggedList(v, t):
+ return isList(v) and not isNil(v) and car(v) == t
+
# Scheme-like associations
def assoc(k, l):
if l == ():
return None
+
if k == car(car(l)):
return car(l)
return assoc(k, cdr(l))
@@ -53,22 +70,14 @@ def assoc(k, l):
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
+# Split a path into a list of segments
def tokens(path):
return tuple(filter(lambda s: len(s) != 0, path.split("/")))
+
+# Write a list of strings to a stream
+def writeStrings(l, os):
+ if l == ():
+ return os
+ os.write(car(l))
+ return writeStrings(cdr(l), os)
+
diff --git a/sca-cpp/trunk/modules/wsgi/wiring-test b/sca-cpp/trunk/modules/wsgi/wiring-test
index 5db99641ce..c3a8d09ae7 100755
--- a/sca-cpp/trunk/modules/wsgi/wiring-test
+++ b/sca-cpp/trunk/modules/wsgi/wiring-test
@@ -18,45 +18,49 @@
# under the License.
echo "Testing..."
+uri=$1
+if [ "$uri" = "" ]; then
+ uri="http://localhost:8090"
+fi
# Setup
-./wsgi-start 8090
+mkdir -p tmp
+./wsgi-start 8090 2>/dev/null
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"
+curl $uri/index.html 2>/dev/null >tmp/index.html
+diff tmp/index.html htdocs/index.html
+rc=$?
# Test ATOMPub
if [ "$rc" = "0" ]; then
- curl http://localhost:8090/client/ >tmp/feed.xml 2>/dev/null
- diff tmp/feed.xml ../server/htdocs/feed.xml
+ curl $uri/client/ >tmp/feed.xml 2>/dev/null
+ diff tmp/feed.xml htdocs/feed.xml
rc=$?
fi
if [ "$rc" = "0" ]; then
- curl http://localhost:8090/client/111 >tmp/entry.xml 2>/dev/null
- diff tmp/entry.xml ../server/htdocs/entry.xml
+ curl $uri/client/111 >tmp/entry.xml 2>/dev/null
+ diff tmp/entry.xml htdocs/entry.xml
rc=$?
fi
if [ "$rc" = "0" ]; then
- curl http://localhost:8090/client/ -X POST -H "Content-type: application/atom+xml" --data @../server/htdocs/entry.xml 2>/dev/null
+ curl $uri/client/ -X POST -H "Content-type: application/atom+xml" --data @htdocs/entry.xml 2>/dev/null
rc=$?
fi
if [ "$rc" = "0" ]; then
- curl http://localhost:8090/client/111 -X PUT -H "Content-type: application/atom+xml" --data @../server/htdocs/entry.xml 2>/dev/null
+ curl $uri/client/111 -X PUT -H "Content-type: application/atom+xml" --data @htdocs/entry.xml 2>/dev/null
rc=$?
fi
if [ "$rc" = "0" ]; then
- curl http://localhost:8090/client/111 -X DELETE 2>/dev/null
+ curl $uri/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
+ curl $uri/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/modules/wsgi/wsgi-test b/sca-cpp/trunk/modules/wsgi/wsgi-test
new file mode 100755
index 0000000000..8b71f2e839
--- /dev/null
+++ b/sca-cpp/trunk/modules/wsgi/wsgi-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
+mkdir -p tmp
+./wsgi-start 8090 2>/dev/null
+sleep 2
+
+# Test HTTP GET
+curl http://localhost:8090/index.html 2>/dev/null >tmp/index.html
+diff tmp/index.html htdocs/index.html
+rc=$?
+
+# Test ATOMPub
+if [ "$rc" = "0" ]; then
+ curl http://localhost:8090/wsgi/ >tmp/feed.xml 2>/dev/null
+ diff tmp/feed.xml htdocs/feed.xml
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ curl http://localhost:8090/wsgi/111 >tmp/entry.xml 2>/dev/null
+ diff tmp/entry.xml htdocs/entry.xml
+ rc=$?
+fi
+if [ "$rc" = "0" ]; then
+ curl http://localhost:8090/wsgi/ -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/wsgi/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/wsgi/111 -X DELETE 2>/dev/null
+ rc=$?
+fi
+
+# Test JSON-RPC
+if [ "$rc" = "0" ]; then
+ curl http://localhost:8090/wsgi/ -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
+./wsgi-stop 8090
+sleep 2
+if [ "$rc" = "0" ]; then
+ echo "OK"
+fi
+return $rc
diff --git a/sca-cpp/trunk/modules/wsgi/xml-test.py b/sca-cpp/trunk/modules/wsgi/xml-test.py
new file mode 100755
index 0000000000..f60322bdc1
--- /dev/null
+++ b/sca-cpp/trunk/modules/wsgi/xml-test.py
@@ -0,0 +1,74 @@
+#!/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.
+
+# Test XML handling functions
+
+import unittest
+from elemutil import *
+from xmlutil import *
+
+customerXML = \
+ "<?xml version=\'1.0\' encoding=\'UTF-8\'?>\n" \
+ "<customer>" \
+ "<name>jdoe</name>" \
+ "<address><city>san francisco</city><state>ca</state></address>" \
+ "<account><id>1234</id><balance>1000</balance></account>" \
+ "<account><id>6789</id><balance>2000</balance></account>" \
+ "<account><id>4567</id><balance>3000</balance></account>" \
+ "</customer>\n"
+
+def testElements():
+ ad = (("'city", "san francisco"), ("'state", "ca"))
+ ac1 = (("'id", "1234"), ("'balance", 1000))
+ ac2 = (("'id", "6789"), ("'balance", 2000))
+ ac3 = (("'id", "4567"), ("'balance", 3000))
+ c = (("'customer", ("'name", "jdoe"), cons("'address", ad), ("'account", (ac1, ac2, ac3))),)
+ e = valuesToElements(c)
+ v = elementsToValues(e)
+ assert v == c
+ s = writeXML(e, True)
+ assert car(s) == customerXML
+
+ c2 = (("'customer", ("'name", "jdoe"), cons("'address", ad), cons("'account", ac1), cons("'account", ac2), cons("'account", ac3)),)
+ e2 = valuesToElements(c2);
+ v2 = elementsToValues(e2);
+ s2 = writeXML(e2, True)
+ assert car(s2) == customerXML
+
+ c3 = readXML((customerXML,))
+ v3 = elementsToValues(c3)
+ e3 = valuesToElements(v3)
+ s3 = writeXML(e3, True)
+ assert car(s3) == customerXML
+ return True
+
+def testValues():
+ l = (("'ns1:echoString", ("'@xmlns:ns1", "http://ws.apache.org/axis2/services/echo"), ("'text", "Hello World!")),)
+ e = valuesToElements(l)
+ lx = writeXML(e, True)
+ x = readXML(lx)
+ v = elementsToValues(x)
+ assert v == l
+ return True
+
+if __name__ == "__main__":
+ print "Testing..."
+ testElements()
+ testValues()
+ print "OK"
+
diff --git a/sca-cpp/trunk/modules/wsgi/xmlutil.py b/sca-cpp/trunk/modules/wsgi/xmlutil.py
new file mode 100644
index 0000000000..a1bc04629a
--- /dev/null
+++ b/sca-cpp/trunk/modules/wsgi/xmlutil.py
@@ -0,0 +1,114 @@
+# 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.
+
+# XML handling functions
+
+from StringIO import StringIO
+from xml.parsers import expat
+import xml.etree.ElementTree as et
+from util import *
+from elemutil import *
+
+# Read a list of XML attributes
+def readAttributes(a):
+ if a == ():
+ return a
+ return cons((attribute, "'" + car(car(a)), cadr(car(a))), readAttributes(cdr(a)))
+
+# Read an XML element
+def readElement(e):
+ l = (element, "'" + e.tag) + readAttributes(tuple(e.items())) + readElements(tuple(e.getchildren()))
+ if e.text == None:
+ return l
+ return l + (e.text,)
+
+# Read a list of XML elements
+def readElements(l):
+ if l == ():
+ return l
+ return cons(readElement(car(l)), readElements(cdr(l)))
+
+# Parse a list of strings representing an XML document
+class NamespaceParser(et.XMLTreeBuilder):
+ def __init__(self):
+ et.XMLTreeBuilder.__init__(self)
+ self._parser = parser = expat.ParserCreate(None)
+ parser.DefaultHandlerExpand = self._default
+ parser.StartElementHandler = self._start
+ parser.EndElementHandler = self._end
+ parser.CharacterDataHandler = self._data
+ try:
+ parser.buffer_text = 1
+ except AttributeError:
+ pass
+ try:
+ parser.ordered_attributes = 1
+ parser.specified_attributes = 1
+ parser.StartElementHandler = self._start_list
+ except AttributeError:
+ pass
+
+def parseXML(l):
+ s = StringIO()
+ writeStrings(l, s)
+ parser = NamespaceParser()
+ parser.feed(s.getvalue())
+ return parser.close()
+
+# Read a list of values from a list of strings representing an XML document
+def readXML(l):
+ e = parseXML(l)
+ return (readElement(e),)
+
+# Write a list of XML element and attribute tokens
+def expandElementValues(n, l):
+ if isNil(l):
+ return l
+ return cons(cons(element, cons(n, car(l))), expandElementValues(n, cdr(l)))
+
+def writeList(l, xml):
+ if isNil(l):
+ return xml
+ token = car(l)
+ if isTaggedList(token, attribute):
+ xml.attrib[attributeName(token)[1:]] = str(attributeValue(token))
+ elif isTaggedList(token, element):
+ if elementHasValue(token):
+ v = elementValue(token)
+ if isList(v):
+ e = expandElementValues(elementName(token), v)
+ writeList(e, xml)
+ else:
+ child = et.Element(elementName(token)[1:])
+ writeList(elementChildren(token), child)
+ xml.append(child)
+ else:
+ child = et.Element(elementName(token)[1:])
+ writeList(elementChildren(token), child)
+ xml.append(child)
+ else:
+ xml.text = str(token)
+ writeList(cdr(l), xml)
+ return xml
+
+# Convert a list of values to a list of strings representing an XML document
+def writeXML(l, xmlTag):
+ e = writeList(l, [])
+ if not xmlTag:
+ return (et.tostring(car(e)),)
+ return (et.tostring(car(e), "UTF-8") + "\n",)
+
diff --git a/sca-cpp/trunk/test/store-python/shopping-cart.py b/sca-cpp/trunk/test/store-python/shopping-cart.py
index 988fe7bea6..2cb6da140a 100644
--- a/sca-cpp/trunk/test/store-python/shopping-cart.py
+++ b/sca-cpp/trunk/test/store-python/shopping-cart.py
@@ -56,7 +56,7 @@ def get(id, cache):
def delete(id, cache):
if id == ():
return cache("delete", (cartId,))
- return true
+ return True
# Return the price of an item
def price(item):