diff options
Diffstat (limited to 'sandbox/sebastien/cpp/apr-2/modules/wsgi/scdl.py')
-rw-r--r-- | sandbox/sebastien/cpp/apr-2/modules/wsgi/scdl.py | 272 |
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)) + |