summaryrefslogtreecommitdiffstats
path: root/sandbox/sebastien/cpp/apr-2/modules/wsgi/scdl.py
diff options
context:
space:
mode:
Diffstat (limited to 'sandbox/sebastien/cpp/apr-2/modules/wsgi/scdl.py')
-rw-r--r--sandbox/sebastien/cpp/apr-2/modules/wsgi/scdl.py272
1 files changed, 272 insertions, 0 deletions
diff --git a/sandbox/sebastien/cpp/apr-2/modules/wsgi/scdl.py b/sandbox/sebastien/cpp/apr-2/modules/wsgi/scdl.py
new file mode 100644
index 0000000000..97c2f7dd69
--- /dev/null
+++ b/sandbox/sebastien/cpp/apr-2/modules/wsgi/scdl.py
@@ -0,0 +1,272 @@
+# 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 xml.etree.cElementTree import iterparse
+from sys import stderr
+from os import environ
+from util import *
+from httputil 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 text(e):
+ return elt(e).text
+
+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, props):
+ self.name = name
+ self.impl = impl
+ self.mod = None
+ self.svcs = svcs
+ self.refs = refs
+ self.props = props
+ self.proxies = ()
+
+ def __call__(self, func, *args):
+ return self.mod.__getattribute__(func)(*(args + self.proxies))
+
+ def __getattr__(self, name):
+ if name[0] == '_':
+ raise AttributeError()
+ if name == "eval":
+ return self
+ l = lambda *args: self.__call__(name, *args)
+ self.__dict__[name] = l
+ return l
+
+ def __repr__(self):
+ return repr((self.name, self.impl, self.mod, self.svcs, self.refs, self.props, self.proxies))
+
+def mkcomponent(name, impl, svcs, refs, props):
+ return component(name, impl, svcs, refs, props)
+
+# Return the Python module name of a component implementation
+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
+
+# 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 ()
+ if match(car(e), "start", "binding.") == False:
+ return binding(cdr(e))
+ return 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 ()
+ if match(car(e), "start", "reference") == False:
+ return references(cdr(e))
+ if "target" in att(car(e)):
+ return cons((att(car(e))["name"], car(tokens(att(car(e))["target"]))), references(cdr(e)))
+ return cons((att(car(e))["name"], binding(e)), references(cdr(e)))
+
+# Return the list of properties under a SCDL component element
+def properties(e):
+ if len(e) == 0 or match(car(e), "end", "component") == True:
+ return ()
+ if match(car(e), "start", "property") == False:
+ return properties(cdr(e))
+ return cons((att(car(e))["name"], text(car(e))), properties(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 ()
+ if match(car(e), "start", "service") == False:
+ return services(cdr(e))
+ return cons(tokens(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 ()
+ if match(car(e), "start", "component") == False:
+ return components(cdr(e))
+ n = name(e)
+ return cons(mkcomponent(n, implementation(e), services(e), references(e), properties(e)), components(cdr(e)))
+
+# Find a component with a given name
+def nameToComponent(name, comps):
+ if comps == ():
+ return None
+ if car(comps).name == name:
+ return car(comps)
+ return nameToComponent(name, cdr(comps))
+
+# Find the URI matching a given URI in a list of service URIs
+def matchingURI(u, svcs):
+ if svcs == ():
+ return None
+ if car(svcs) == u[0:len(car(svcs))]:
+ return car(svcs)
+ return matchingURI(u, cdr(svcs))
+
+# Return the (service URI, component) pair matching a given URI
+def uriToComponent(u, comps):
+ if car(u) == "components":
+ return componentURIToComponent(u, comps)
+ if car(u) == "references":
+ return referenceURIToComponent(u, comps)
+ return serviceURIToComponent(u, comps)
+
+def serviceURIToComponent(u, comps):
+ if comps == ():
+ return (None, None)
+ m = matchingURI(u, car(comps).svcs)
+ if m != None:
+ return (m, car(comps))
+ return serviceURIToComponent(u, cdr(comps))
+
+def componentURIToComponent(u, comps):
+ comp = nameToComponent(cadr(u), comps)
+ if comps == None:
+ return (None, None)
+ return (u[0:2], comp)
+
+def referenceURIToComponent(u, comps):
+ sc = nameToComponent(cadr(u), comps)
+ if sc == None:
+ return (None, None)
+
+ def referenceToComponent(r, refs):
+ if refs == ():
+ return None
+ if r == car(car(refs)):
+ return cadr(car(refs))
+ return referenceToComponent(r, cdr(refs))
+
+ tn = referenceToComponent(caddr(u), sc.refs)
+ if tn == None:
+ return (None, None)
+ tc = nameToComponent(tn, comps)
+ if tc == None:
+ return (None, None)
+ return (u[0:3], tc)
+
+# Evaluate a reference, return a proxy to the resolved component or an
+# HTTP client configured with the reference target uri
+def evalReference(r, comps):
+ t = cadr(r)
+ if t.startswith("http://") or t.startswith("https://"):
+ return mkclient(t)
+ return nameToComponent(t, comps)
+
+# Make a callable property
+class property:
+ def __init__(self, name, l):
+ self.name = name
+ self.l = l
+
+ def __call__(self, *args):
+ return self.l(*args)
+
+ def __getattr__(self, name):
+ if name == "eval":
+ return self
+ raise AttributeError()
+
+ def __repr__(self):
+ return repr((self.name, self.l()))
+
+def mkproperty(name, l):
+ return property(name, l)
+
+# Evaluate a property, return a lambda function returning the property
+# value. The host, user, realm, nickname and email properties are configured
+# with the values from the HTTP request, if any.
+def evalProperty(p):
+ if car(p) == "host":
+ return mkproperty(car(p), lambda: hostProperty(cadr(p), environ))
+ if car(p) == "user":
+ return mkproperty(car(p), lambda: userProperty(cadr(p)))
+ if car(p) == "realm":
+ return mkproperty(car(p), lambda: hostProperty(cadr(p), environ))
+ if car(p) == "nickname":
+ return mkproperty(car(p), lambda: nicknameProperty(cadr(p)))
+ if car(p) == "email":
+ return mkproperty(car(p), lambda: emailProperty(cadr(p)))
+ return mkproperty(car(p), lambda: cadr(p))
+
+def currentUser():
+ try:
+ from google.appengine.api import users
+ return users.get_current_user()
+ except:
+ return None
+
+def userProperty(v):
+ user = currentUser()
+ return user.federated_identity() if user else v
+
+def nicknameProperty(v):
+ user = currentUser()
+ return user.nickname() if user else v
+
+def hostProperty(v, e):
+ return e.get("HTTP_HOST", e.get("SERVER_NAME", v)).split(":")[0]
+
+def emailProperty(v):
+ user = currentUser()
+ return user.email() if user else v
+
+# Evaluate a component, resolve its implementation, references and
+# properties
+def evalComponent(comp, comps):
+ comp.mod = __import__(comp.impl)
+
+ # Make a list of proxy lambda functions for the component references and properties
+ # A reference proxy is the callable lambda function of the component wired to the reference
+ # A property proxy is a lambda function that returns the value of the property
+ print >> stderr, "evalComponent", comp.impl, comp.svcs, comp.refs, comp.props
+ comp.proxies = tuple(map(lambda r: evalReference(r, comps), comp.refs)) + tuple(map(lambda p: evalProperty(p), comp.props))
+
+ return comp
+
+# Evaluate a list of components
+def evalComponents(comps):
+ return tuple(map(lambda c: evalComponent(c, comps), comps))
+