It provides functions to retrieve the parts
"""
def __init__(self, url=None):
self.url = url
def server(self):
"""Extract the server's hostname/port from the url."""
return self.url.split("ldap://")[1].split("/")[0].split(":")
def base(self):
"""Extract the baseDN from the url."""
return self.url.split("ldap://")[1].split("/")[1]
class BindAuthenticator(object):
"""
This ldap authenticator uses binding to confirm the user's password. This means the password encoding
depends on the ldap library's API as well as the directory server; NOT Spring Python's password
hashing algorithms.
"""
def __init__(self, context_source=None, user_dn_patterns="uid={0},ou=people"):
self.context_source = context_source
self.user_dn_patterns = user_dn_patterns
self.logger = logging.getLogger("springpython.security.providers.Ldap.BindAuthenticator")
def authenticate(self, authentication):
"""Using the user_dn_patterns, find the user's entry, and then bind to the entry using supplied credentials."""
username = self.user_dn_patterns.replace("{0}", authentication.username)
baseDn = self.context_source.base()
parts = username.split(",")
if len(parts) > 1:
username = parts[0]
baseDn = ",".join(parts[1:]) + "," + baseDn
(host, port) = self.context_source.server()
self.logger.debug("Opening connection to server %s/%s" % (host, int(port)))
l = ldap.open(host, int(port))
self.logger.debug("Searching for %s in %s" % (username, baseDn))
result_set = l.search_s(baseDn, ldap.SCOPE_SUBTREE, username, None)
if len(result_set) != 1:
raise BadCredentialsException("Found %s entries at %s/%s. Should only be 1." % (len(result_set), baseDn, username))
dn = result_set[0][0]
self.logger.debug("Attempting to bind %s" % dn)
try:
l.simple_bind_s(dn, authentication.password)
self.logger.debug("Successfully bound to server!")
return (result_set[0],l)
except Exception, e:
self.logger.debug("Error %s" % e)
raise BadCredentialsException("Invalid password")
class PasswordComparisonAuthenticator(object):
"""
This ldap authenticator uses string comparison to confirm the user's password. This means a password encoder must
be provided, or the default LdapShaPasswordEncoder will be used. It searched for the user's entry, fetches the
password, and then does a string comparison to confirm the password.
"""
def __init__(self, context_source=None, user_dn_patterns="uid={0},ou=people", password_attr_name="userPassword"):
self.context_source = context_source
self.user_dn_patterns = user_dn_patterns
self.password_attr_name = password_attr_name
self.encoder = LdapShaPasswordEncoder()
self.logger = logging.getLogger("springpython.security.providers.Ldap.PasswordComparisonAuthenticator")
def authenticate(self, authentication):
"""
Using the user_dn_patterns, find the user's entry, and then retrieve the password field. Encode the supplied
password with the necessary hasher, and compare to the entry.
"""
username = self.user_dn_patterns.replace("{0}", authentication.username)
baseDn = self.context_source.base()
parts = username.split(",")
if len(parts) > 1:
username = parts[0]
baseDn = ",".join(parts[1:]) + "," + baseDn
(host, port) = self.context_source.server()
self.logger.debug("Opening connection to server %s/%s" % (host, int(port)))
l = ldap.open(host, int(port))
self.logger.debug("Searching for %s in %s" % (username, baseDn))
result_set = l.search_s(baseDn, ldap.SCOPE_SUBTREE, username, None)
if len(result_set) != 1:
raise BadCredentialsException("Found %s entries at %s/%s. Should only be 1." % (len(result_set), baseDn, username))
self.logger.debug("Looking for attributes...%s" % result_set[0][1])
stored_password = result_set[0][1][self.password_attr_name.lower()][0]
self.logger.debug("Comparing passwords...")
if self.encoder.isPasswordValid(stored_password, authentication.password, None):
self.logger.debug("Successfully matched passwords!")
return (result_set[0],l)
else:
raise BadCredentialsException("Invalid password")
class DefaultLdapAuthoritiesPopulator(object):
"""
This ldap authorities populator follows a standard convention, where groups are created, with a member attribute, pointing
at user entries in another part of the directory structure. It then combines ROLE_ with the name of the group, and names
that as a granted role.
"""
def __init__(self, context_source=None, group_search_base="ou=groups", group_search_filter="member={0}", group_role_attr="cn", role_prefix="ROLE_", convert_to_upper=True):
self.logger = logging.getLogger("springpython.security.providers.Ldap.DefaultLdapAuthoritiesPopulator")
self.context_source = context_source
self.group_search_base = group_search_base
self.group_search_filter = group_search_filter
self.group_role_attr = group_role_attr
self.role_prefix = role_prefix
self.convert_to_upper = convert_to_upper
def get_granted_auths(self, user_details, l):
group_filter = self.group_search_filter.replace("{0}", user_details[0])
baseDn = self.group_search_base + "," + self.context_source.base()
self.logger.debug("Searching for groups for %s" % str(user_details[0]))
result_set = l.search_s(baseDn, ldap.SCOPE_SUBTREE, group_filter, None)
auths = []
for row in result_set:
role = self.role_prefix + row[1][self.group_role_attr][0]
if self.convert_to_upper:
auths.append(role.upper())
else:
auths.append(role)
self.logger.debug("Authorities = %s" % auths)
return auths
class LdapAuthenticationProvider(AuthenticationProvider):
"""
This authenticator performs two steps:
1) Authenticate the user to confirm their credentials.
2) Lookup roles the user has stored in the directory server.
It is possible to inject any type of authenticator as well as roles populator.
Spring Python includes two authenticators that perform standard binding or password comparisons.
You are able to code your own and use it instead, especially if you are using a non-conventional mechanism.
Spring Python includes one role populator, based on the standard convention of defining groups elsewhere in
the directory server's hierarchy. However, you can inject your own if you have a non-convential structure,
such as storing the roles directly in the user's directory entry.
"""
def __init__(self, ldap_authenticator=None, ldap_authorities_populator=None):
AuthenticationProvider.__init__(self)
self.ldap_authenticator = ldap_authenticator
self.ldap_authorities_populator = ldap_authorities_populator
self.logger = logging.getLogger("springpython.security.providers.Ldap.LdapAuthenticationProvider")
def authenticate(self, authentication):
user_details, l = self.ldap_authenticator.authenticate(authentication)
from copy import deepcopy
results = deepcopy(authentication)
results.granted_auths = self.ldap_authorities_populator.get_granted_auths(user_details, l)
l.unbind()
return results
springpython-1.2.0+ds/springpython/security/providers/__init__.py 0000644 0000000 0000000 00000011743 11412453030 024116 0 ustar root root """
Copyright 2006-2008 SpringSource (http://springsource.com), All Rights Reserved
Licensed 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.
"""
import logging
from springpython.security import AuthenticationException
from springpython.security import BadCredentialsException
from springpython.security import DisabledException
class ProviderNotFoundException(AuthenticationException):
"""
An exception thrown when a list of providers are polled for a security decision,
and none of them supports the request.
"""
pass
class Authentication:
"""
Abstract representation of credential data. The premise is that username and password
are populated, and after authentication this record is returned with the third attribute,
granted authorities, populated.
"""
def __init__(self):
self.__authenticated = False
def isAuthenticated(self):
return self.__authenticated
def setAuthenticated(self, authenticated):
self.__authenticated = authenticated
def getCredentials(self):
raise NotImplementedError()
def __str__(self):
raise AuthenticationException("You should be using a concrete authentication object")
class UsernamePasswordAuthenticationToken(Authentication):
"""
A basic concrete version of authentication. Works for most scenarios.
"""
def __init__(self, username = None, password = None, granted_auths = None):
Authentication.__init__(self)
self.username = username
self.password = password
if granted_auths is None:
self.granted_auths = []
else:
self.granted_auths = granted_auths
def getCredentials(self):
return self.password
def __str__(self):
return "[UsernamePasswordAuthenticationToken] User: [%s] Password: [PROTECTED] GrantedAuthorities: %s Authenticated: %s" % \
(self.username, self.granted_auths, self.isAuthenticated())
class AuthenticationManager:
"""
Iterates an Authentication request through a list of AuthenticationProviders.
AuthenticationProviders are tried in order until one provides a non-null response.
A non-null response indicates the provider had authority to decide on the authentication
request and no further providers are tried. If an AuthenticationException is thrown by
a provider, it is retained until subsequent providers are tried. If a subsequent provider
successfully authenticates the request, the earlier authentication exception is disregarded
and the successful authentication will be used. If no subsequent provider provides a
non-null response, or a new AuthenticationException, the last AuthenticationException
received will be used. If no provider returns a non-null response, or indicates it can
even process an Authentication, the AuthenticationManager will throw a ProviderNotFoundException.
"""
def __init__(self, auth_providers = None):
if auth_providers is None:
self.auth_providers = []
else:
self.auth_providers = auth_providers
self.logger = logging.getLogger("springpython.security.providers.AuthenticationManager")
def authenticate(self, authentication):
"""
Attempts to authenticate the passed Authentication object, returning a fully
populated Authentication object (including granted authorities) if successful.
"""
authenticationException = ProviderNotFoundException()
for auth_provider in self.auth_providers:
try:
results = auth_provider.authenticate(authentication)
if results:
results.setAuthenticated(True)
return results
except DisabledException, e: # Disabled means account found, but invalid
raise e
except AuthenticationException, e:
authenticationException = e
raise authenticationException
class AuthenticationProvider(object):
"""
Indicates a class can process a specific Authentication implementation.
"""
def authenticate(self, authentication):
"""
Performs authentication with the same contract as AuthenticationManager.authenticate(Authentication).
"""
raise NotImplementedError()
def supports(self, authentication):
"""
Returns true if this AuthenticationProvider supports the indicated Authentication object.
"""
raise NotImplementedError()
springpython-1.2.0+ds/springpython/security/providers/encoding.py 0000644 0000000 0000000 00000016573 11412453030 024153 0 ustar root root """
Copyright 2006-2008 SpringSource (http://springsource.com), All Rights Reserved
Licensed 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.
"""
import logging
class PasswordEncoder(object):
"""Interface for performing authentication operations on a password."""
def encodePassword(self, rawPass, salt):
"""Encodes the specified raw password with an implementation specific algorithm."""
raise NotImplementedError()
def isPasswordValid(self, encPass, rawPass, salt):
"""Validates a specified "raw" password against an encoded password."""
raise NotImplementedError()
class BasePasswordEncoder(PasswordEncoder):
"""Convenience base for all password encoders."""
def __init__(self):
super(BasePasswordEncoder, self).__init__()
self.ignorePasswordCase = False
self.logger = logging.getLogger("springpython.security.providers.encoding.BasePasswordEncoder")
def mergePasswordAndSalt(self, password, salt, strict):
"""
Used by subclasses to generate a merged password and salt String.
The generated password will be in the form of 'password{salt}'.
A None can be passed to either parameter, and will be handled correctly. If the salt is None or empty,
the resulting generated password will simply be the passed password. The __str__ method of the salt will be used to represent the salt.
"""
if password is None:
password = ""
if strict and salt is not None:
if "{" in str(salt) or "}" in str(salt):
raise ValueError("Cannot use { or } in salt.__str__")
if salt is None or salt == "":
return password
else:
return password + "{" + str(salt) + "}"
class PlaintextPasswordEncoder(BasePasswordEncoder):
"""
Plaintext implementation of PasswordEncoder.
As callers may wish to extract the password and salts separately from the encoded password,
the salt must not contain reserved characters (specifically '{' and '}').
"""
def __init__(self):
super(PlaintextPasswordEncoder, self).__init__()
self.logger = logging.getLogger("springpython.security.providers.encoding.PlaintextPasswordEncoder")
def encodePassword(self, rawPass, salt):
"""Encodes the specified raw password with an implementation specific algorithm."""
return self.mergePasswordAndSalt(rawPass, salt, True)
def isPasswordValid(self, encPass, rawPass, salt):
"""Validates a specified "raw" password against an encoded password."""
pass1 = encPass + ""
# Strict delimiters is false because pass2 never persisted anywhere
# and we want to avoid unnecessary exceptions as a result (the
# authentication will fail as the encodePassword never allows them)
pass2 = self.mergePasswordAndSalt(rawPass, salt, False)
if not self.ignorePasswordCase:
return pass1 == pass2
else:
return pass1.upper() == pass2.upper()
class AbstractOneWayPasswordEncoder(BasePasswordEncoder):
"""
This is an abstract one-way hashing encoder. It is abstract because the
subclasses have to plugin their strategy.
"""
def __init__(self):
super(AbstractOneWayPasswordEncoder, self).__init__()
self.onewayHasher = None
self.logger = logging.getLogger("springpython.security.providers.encoding.AbstractOneWayPasswordEncoder")
def encodePassword(self, rawPass, salt):
"""Encodes the specified raw password with an implementation specific algorithm."""
hasher = self.onewayHashStrategy()
if not self.ignorePasswordCase:
hasher.update(self.mergePasswordAndSalt(rawPass, salt, False))
else:
hasher.update(self.mergePasswordAndSalt(rawPass.lower(), salt, False))
return hasher.hexdigest()
def isPasswordValid(self, encPass, rawPass, salt):
"""Validates a specified "raw" password against an encoded password."""
pass1 = encPass + ""
# Strict delimiters is false because pass2 never persisted anywhere
# and we want to avoid unnecessary exceptions as a result (the
# authentication will fail as the encodePassword never allows them)
pass2 = self.mergePasswordAndSalt(rawPass, salt, False)
hasher = self.onewayHashStrategy()
if self.ignorePasswordCase:
hasher.update(pass2.lower())
else:
hasher.update(pass2)
pass2 = hasher.hexdigest()
if not self.ignorePasswordCase:
return pass1 == hasher.hexdigest()
else:
return pass1.lower() == hasher.hexdigest()
class Md5PasswordEncoder(AbstractOneWayPasswordEncoder):
"""
MD5 implementation of PasswordEncoder.
If a None password is presented, it will be treated as an empty String ("") password.
As MD5 is a one-way hash, the salt can contain any characters.
"""
def __init__(self):
super(Md5PasswordEncoder, self).__init__()
try:
import hashlib
self.onewayHashStrategy = hashlib.md5
except ImportError:
import md5
self.onewayHashStrategy = md5.new
self.logger = logging.getLogger("springpython.security.providers.encoding.Md5PasswordEncoder")
class ShaPasswordEncoder(AbstractOneWayPasswordEncoder):
"""
SHA implementation of PasswordEncoder.
If a None password is presented, it will be treated as an empty String ("") password.
As SHA is a one-way hash, the salt can contain any characters.
"""
def __init__(self):
super(ShaPasswordEncoder, self).__init__()
try:
import hashlib
self.onewayHashStrategy = hashlib.sha1
except ImportError:
import sha
self.onewayHashStrategy = sha.new
self.logger = logging.getLogger("springpython.security.providers.encoding.ShaPasswordEncoder")
class LdapShaPasswordEncoder(PasswordEncoder):
def __init__(self):
super(PasswordEncoder, self).__init__()
self.sha_encoder = ShaPasswordEncoder()
self.logger = logging.getLogger("springpython.security.providers.encoding.LdapShaPasswordEncoder")
def encodePassword(self, rawPass, salt):
"""Encodes the specified raw password with an implementation specific algorithm."""
import base64
hasher = self.sha_encoder.onewayHashStrategy()
hasher.update(rawPass)
return "{SHA}" + base64.b64encode(hasher.digest())
def isPasswordValid(self, encPass, rawPass, salt):
"""Validates a raw password against an encrypted one. It checks the prefix, to tell if its encrypted
or stored in the clear."""
if encPass.startswith("{SHA}"):
return encPass == self.encodePassword(rawPass, salt)
else:
return encPass == rawPass
springpython-1.2.0+ds/springpython/security/providers/_Ldap_jython.py 0000644 0000000 0000000 00000015154 11464332043 025000 0 ustar root root """
Copyright 2006-2009 SpringSource (http://springsource.com), All Rights Reserved
Licensed 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.
"""
import logging
import re
import sys
from springpython.security import AuthenticationException
from springpython.security import AuthenticationServiceException
from springpython.security import BadCredentialsException
from springpython.security import DisabledException
from springpython.security import UsernameNotFoundException
from springpython.security.providers import AuthenticationProvider
from springpython.security.providers import UsernamePasswordAuthenticationToken
from springpython.security.providers.dao import AbstractUserDetailsAuthenticationProvider
from springpython.security.providers.encoding import LdapShaPasswordEncoder
"""
The ldap library only works with Jython. You should NOT import this library directly.
Due to the lack of a pure Python library, this version uses Spring Security/Spring LDAP jar files to perform
authentication and LDAP lookups.
"""
import java
import org.springframework.security.ldap.DefaultSpringSecurityContextSource
import org.springframework.security.ldap.populator.DefaultLdapAuthoritiesPopulator
import org.springframework.security.providers.ldap.authenticator.BindAuthenticator
import org.springframework.security.providers.ldap.authenticator.PasswordComparisonAuthenticator
import org.springframework.security.providers.UsernamePasswordAuthenticationToken
from jarray import array
print """
WARNING WARNING WARNING WARNING
===============================
This doesn't yet work. There is some issue with Jython.
See http://bugs.jython.org/issue1489 and http://jira.springframework.org/browse/SESPRINGPYTHONPY-121 for more details.
===============================
WARNING WARNING WARNING WARNING
"""
class DefaultSpringSecurityContextSource(object):
def __init__(self, url):
self._context = org.springframework.security.ldap.DefaultSpringSecurityContextSource(url)
java.lang.Thread.currentThread().setContextClassLoader(self._context.getClass().getClassLoader())
self._context.afterPropertiesSet()
class BindAuthenticator(object):
def __init__(self, context_source=None, user_dn_patterns="uid={0},ou=people"):
self.context_source = context_source
self.user_dn_patterns = user_dn_patterns
self.logger = logging.getLogger("springpython.security.providers.Ldap.BindAuthenticator")
self._authenticator = None
def authenticate(self, authentication):
if self._authenticator is None:
self._authenticator = org.springframework.security.providers.ldap.authenticator.BindAuthenticator(self.context_source._context)
self._authenticator.setUserDnPatterns(array([self.user_dn_patterns], java.lang.String))
self._authenticator.afterPropertiesSet()
#java.lang.Thread.currentThread().setContextClassLoader(self._authenticator.getClass().getClassLoader())
#print "BindAuthenticator class loader %s" % self._authenticator.getClass().getClassLoader()
token = org.springframework.security.providers.UsernamePasswordAuthenticationToken(authentication.username, authentication.password)
return self._authenticator.authenticate(token)
class PasswordComparisonAuthenticator(object):
def __init__(self, context_source=None, user_dn_patterns="uid={0},ou=people", password_attr_name="userPassword"):
self.context_source = context_source
self.user_dn_patterns = user_dn_patterns
self.password_attr_name = password_attr_name
self.encoder = LdapShaPasswordEncoder()
self.logger = logging.getLogger("springpython.security.providers.Ldap.PasswordComparisonAuthenticator")
def authenticate(self, authentication):
if jython:
raise Exception("This code doesn't work inside Jython.")
class DefaultLdapAuthoritiesPopulator(object):
def __init__(self, context_source=None, group_search_base="ou=groups", group_search_filter="(member={0})", group_role_attr="cn", role_prefix="ROLE_", convert_to_upper=True):
self.logger = logging.getLogger("springpython.security.providers.Ldap.DefaultLdapAuthoritiesPopulator")
self.context_source = context_source
self.group_search_base = group_search_base
self.group_search_filter = group_search_filter
self.group_role_attr = group_role_attr
self.role_prefix = role_prefix
self.convert_to_upper = convert_to_upper
self._populator = org.springframework.security.ldap.populator.DefaultLdapAuthoritiesPopulator(self.context_source._context, self.group_search_base)
#java.lang.Thread.currentThread().setContextClassLoader(self._populator.getClass().getClassLoader())
self._populator.setGroupSearchFilter(self.group_search_filter)
self._populator.setGroupRoleAttribute(self.group_role_attr)
self._populator.setRolePrefix(self.role_prefix)
self._populator.setConvertToUpperCase(self.convert_to_upper)
print "LdapAuthoritiesPopulator class loader %s" % self._populator.getClass().getClassLoader()
def get_granted_auths(self, user_details, username):
results = self._populator.getGrantedAuthorities(user_details, username)
print results
return results
class LdapAuthenticationProvider(AuthenticationProvider):
def __init__(self, ldap_authenticator=None, ldap_authorities_populator=None):
AuthenticationProvider.__init__(self)
self.ldap_authenticator = ldap_authenticator
self.ldap_authorities_populator = ldap_authorities_populator
self.logger = logging.getLogger("springpython.security.providers.Ldap.LdapAuthenticationProvider")
def authenticate(self, authentication):
user_details = self.ldap_authenticator.authenticate(authentication)
print "Context class loader %s" % user_details.getClass().getClassLoader()
from copy import deepcopy
results = deepcopy(authentication)
results.granted_auths = self.ldap_authorities_populator.get_granted_auths(user_details, authentication.username)
results.setAuthenticated(True)
l.unbind()
return results
springpython-1.2.0+ds/springpython/security/providers/dao.py 0000644 0000000 0000000 00000017356 11412453030 023130 0 ustar root root """
Copyright 2006-2008 SpringSource (http://springsource.com), All Rights Reserved
Licensed 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.
"""
import logging
from springpython.database import DataAccessException
from springpython.security import AuthenticationException
from springpython.security import AuthenticationServiceException
from springpython.security import BadCredentialsException
from springpython.security import DisabledException
from springpython.security import UsernameNotFoundException
from springpython.security.providers import AuthenticationProvider
from springpython.security.providers import UsernamePasswordAuthenticationToken
from springpython.security.providers.encoding import PlaintextPasswordEncoder
class UserCache(object):
def get_user(self, username):
raise NotImplementedError()
def put_user(self, user):
raise NotImplementedError()
def remove_user(self, username):
raise NotImplementedError()
class NullUserCache(UserCache):
def get_user(self, username):
return None
def put_user(self, user):
pass
def remove_user(self, username):
pass
class AbstractUserDetailsAuthenticationProvider(AuthenticationProvider):
def __init__(self):
super(AbstractUserDetailsAuthenticationProvider, self).__init__()
self.user_cache = NullUserCache()
self.hide_user_not_found_exceptions = True
self.force_principal_as_str = True
self.logger = logging.getLogger("springpython.security.providers.AbstractUserDetailsAuthenticationProvider")
def authenticate(self, authentication):
# Determine username
username = authentication.username
cache_was_used = True
user = self.user_cache.get_user(username)
if user is None:
cache_was_used = False
try:
user = self.retrieve_user(username, authentication)
except UsernameNotFoundException, notFound:
if self.hide_user_not_found_exceptions:
raise BadCredentialsException("UsernameNotFound: Bad credentials")
else:
raise notFound
if user is None:
raise Exception("retrieve_user returned null - a violation of the interface contract")
if not user.accountNonLocked:
raise LockedException("User account is locked")
if not user.enabled:
raise DisabledException("User is disabled")
if not user.accountNonExpired:
raise AccountExpiredException("User account has expired")
# This check must come here, as we don't want to tell users
# about account status unless they presented the correct credentials
try:
self.additional_auth_checks(user, authentication)
except AuthenticationException, exception:
if cache_was_used:
# There was a problem, so try again after checking we're using latest data (ie not from the cache)
cache_was_used = False
user = self.retrieve_user(username, authentication)
self.additional_auth_checks(user, authentication)
else:
raise exception
if not user.credentialsNonExpired:
raise CredentialsExpiredException("User credentials have expired")
if not cache_was_used:
self.user_cache.put_user(user)
principal_to_return = user
if self.force_principal_as_str:
principal_to_return = user.username
return self.create_success_auth(principal_to_return, authentication, user)
def additional_auth_checks(self, user_details, authentication):
raise NotImplementedError()
def retrieve_user(self, username, authentication):
raise NotImplementedError()
def create_success_auth(self, principal, authentication, user):
# Ensure we return the original credentials the user supplied,
# so subsequent attempts are successful even with encoded passwords.
# Also ensure we return the original getDetails(), so that future
# authentication events after cache expiry contain the details
result = UsernamePasswordAuthenticationToken(principal, authentication.getCredentials(), user.authorities)
#result.details = authentication.details
return result
class DaoAuthenticationProvider(AbstractUserDetailsAuthenticationProvider):
def __init__(self, user_details_service = None, password_encoder = PlaintextPasswordEncoder()):
super(DaoAuthenticationProvider, self).__init__()
self.password_encoder = password_encoder
self.salt_source = None
self.user_details_service = user_details_service
self.include_details_obj = True
self.logger = logging.getLogger("springpython.security.providers.DaoAuthenticationProvider")
def retrieve_user(self, username, authentication):
loaded_user = None
try:
loaded_user = self.user_details_service.load_user(username)
except DataAccessException, repositoryProblem:
raise AuthenticationServiceException(repositoryProblem)
if loaded_user is None:
raise AuthenticationServiceException("UserDetailsService returned null, which is an interface contract violation")
return loaded_user
def additional_auth_checks(self, user_details, authentication):
salt = None
if self.salt_source is not None:
salt = self.salt_source.get_salt(user_details)
if not self.password_encoder.isPasswordValid(user_details.password, authentication.getCredentials(), salt):
raise BadCredentialsException("additional_auth_checks: Bad credentials")
class SaltSource(object):
"""Provides alternative sources of the salt to use for encoding passwords."""
def get_salt(self, user):
"""Returns the salt to use for the indicated user."""
raise NotImplementedError()
class SystemWideSaltSource(SaltSource):
"""
Uses a static system-wide String as the salt.
Does not supply a different salt for each User. This means users sharing the same
password will still have the same digested password. Of benefit is the digested passwords will at least be more protected than if stored without any salt.
"""
def __init__(self, system_wide_salt = ""):
super(SystemWideSaltSource, self).__init__()
self.system_wide_salt = system_wide_salt
def get_salt(self, user):
return self.system_wide_salt
class ReflectionSaltSource(SaltSource):
"""
Obtains a salt from a specified property of the User object.
This allows you to subclass User and provide an additional bean getter for a salt.
You should use a synthetic value that does not change, such as a database primary key.
Do not use username if it is likely to change.
"""
def __init__(self, user_prop_to_use = ""):
super(ReflectionSaltSource, self).__init__()
self.user_prop_to_use = user_prop_to_use
def get_salt(self, user):
try:
reflectionMethod = getattr(user, self.user_prop_to_use)
return reflectionMethod()
except Exception, e:
raise AuthenticationServiceException(e);
springpython-1.2.0+ds/springpython/security/providers/Ldap.py 0000644 0000000 0000000 00000001377 11464332043 023250 0 ustar root root """
Copyright 2006-2008 SpringSource (http://springsource.com), All Rights Reserved
Licensed 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.
"""
import sys
if "java" in sys.platform.lower():
from _Ldap_jython import *
else:
from _Ldap_cpython import *
springpython-1.2.0+ds/springpython/security/cherrypy3.py 0000644 0000000 0000000 00000004710 11464332043 022275 0 ustar root root """
Copyright 2006-2008 SpringSource (http://springsource.com), All Rights Reserved
Licensed 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.
"""
import cherrypy
import logging
from springpython.security import AuthenticationException
from springpython.security.context import SecurityContextHolder, SecurityContext
from springpython.security.intercept import AbstractSecurityInterceptor
from springpython.security.providers import UsernamePasswordAuthenticationToken
from springpython.security.web import FilterChainProxy, SessionStrategy,RegExpBasedFilterInvocationDefinitionMap, FilterInvocation
class CP3FilterChainProxy(FilterChainProxy):
def __init__(self, filterInvocationDefinitionSource=None):
FilterChainProxy.__init__(self, filterInvocationDefinitionSource)
self.logger = logging.getLogger("springpython.security.cherrypy3.Another")
cherrypy.tools.securityFilterChain = cherrypy._cptools.HandlerTool(self)
def __call__(self, environ=None, start_response=None):
if cherrypy.request.handler is None:
return False
def cherrypy_handler(*args, **kwargs):
return cherrypy.request.handler(*args, **kwargs)
def func(args):
return args[0]()
self.application = (func, (cherrypy_handler,))
cherrypy.response.body = FilterChainProxy.__call__(self, cherrypy.request.wsgi_environ, None)
return True
class CP3SessionStrategy(SessionStrategy):
def __init__(self):
SessionStrategy.__init__(self)
self.logger = logging.getLogger("springpython.security.cherrypy3.CP3SessionStrategy")
def getHttpSession(self, environ):
return cherrypy.session.get("session_id")
def setHttpSession(self, key, value):
if "session_id" not in cherrypy.session:
cherrypy.session["session_id"] = {}
cherrypy.session["session_id"][key] = value
class CP3RedirectStrategy(object):
def redirect(self, url):
raise cherrypy.HTTPRedirect(url)
springpython-1.2.0+ds/springpython/security/vote.py 0000644 0000000 0000000 00000031301 11412453030 021307 0 ustar root root """
Copyright 2006-2008 SpringSource (http://springsource.com), All Rights Reserved
Licensed 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.
"""
import logging
from springpython.security import AccessDeniedException
logger = logging.getLogger("springpython.security.vote")
class AccessDecisionVoter:
"""
Indicates a class is responsible for voting on authorization decisions.
The coordination of voting (ie polling AccessDecisionVoters, tallying
their responses, and making the final authorization decision) is performed
by an AccessDecisionManager.
"""
ACCESS_ABSTAIN = 0
ACCESS_DENIED = 1
ACCESS_GRANTED = 2
access_dict = { ACCESS_ABSTAIN: "ACCESS_ABSTAIN", ACCESS_DENIED: "ACCESS_DENIED", ACCESS_GRANTED: "ACCESS_GRANTED" }
def supports(self, attr):
"""
Indicates whether this AccessDecisionVoter is able to vote on the passed in object.
"""
raise NotImplementedError()
def vote(self, authentication, object, config):
"""Indicates whether or not access is granted."""
raise NotImplementedError()
class RoleVoter(AccessDecisionVoter):
"""
Votes if any ConfigAttribute.getAttribute() starts with a prefix indicating that it is a role.
The default prefix string is ROLE_, but this may be overriden to any value. It may also be set
to empty, which means that essentially any attribute will be voted on. As described further
below, the effect of an empty prefix may not be quite desireable.
Abstains from voting if no configuration attribute commences with the role prefix. Votes to
grant access if there is an exact matching GrantedAuthority to a ConfigAttribute starting
with the role prefix. Votes to deny access if there is no exact matching GrantedAuthority
to a ConfigAttribute starting with the role prefix.
An empty role prefix means that the voter will vote for every ConfigAttribute. When there
are different categories of ConfigAttributes used, this will not be optimal since the voter
will be voting for attributes which do not represent roles. However, this option may be of
some use when using preexisting role names without a prefix, and no ability exists to prefix
them with a role prefix on reading them in, such as provided for example in JdbcDaoImpl.
All comparisons and prefixes are case sensitive.
"""
def __init__(self, role_prefix = "ROLE_"):
self.role_prefix = role_prefix
self.logger = logging.getLogger("springpython.security.vote.RoleVoter")
def supports(self, attr):
"""This voter will support a list, or a string starting with
the same characters as the set prefix.
"""
if isinstance(attr, list) or (attr is not None and attr.startswith(self.role_prefix)):
return True
else:
return False
def vote(self, authentication, invocation, config):
"""Grant access if any of the granted authorities matches any of the required
roles.
"""
results = self.ACCESS_ABSTAIN
for attribute in config:
if self.supports(attribute):
self.logger.debug("This %s role voter will vote whether user has %s" % (self.role_prefix, attribute))
results = self.ACCESS_DENIED
for authority in authentication.granted_auths:
if attribute == authority:
self.logger.debug("This user has %s in %s. Vote for GRANTED!" % (attribute, authentication.granted_auths))
return self.ACCESS_GRANTED
if results == self.ACCESS_ABSTAIN:
self.logger.debug("This %s voter is abstaining from voting" % self.role_prefix)
elif results == self.ACCESS_DENIED:
self.logger.debug("This %s voter did NOT find the required credentials in %s. Vote for DENIED!" % (self.role_prefix, authentication.granted_auths))
return results
def __str__(self):
return "<'%s' role voter>" % self.role_prefix
class AbstractAclVoter(AccessDecisionVoter):
"""
May/may not need this class
"""
pass
class LabelBasedAclVoter(AbstractAclVoter):
"""
* This Acl voter will evaluate methods based on labels applied to incoming arguments. It will
* only check methods that have been properly tagged in the MethodSecurityInterceptor with the
* value stored in attr_indicating_labeled_op. If a method has been tagged, then
* it examines each argument, and if the argument implements {@link LabeledData}, then it will
* asses if the user's list of granted authorities matches.
*
* By default, if none of the arguments are labeled, then the access will be granted. This can
* be overridden by setting allow_access_if_no_attr_labeled to false in the Spring
* context file.
*
* In many situations, different values are linked together to define a common label, it is
* necessary to define a map in the application context that links user-assigned label access
* to domain object labels. This is done by setting up the label_dict in the application
* context.
*
* @author Greg Turnquist
* @see org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor
"""
def __init__(self, label_dict = None, allow_access_if_no_attr_labeled = False, attr_indicating_labeled_op = ""):
if label_dict is None:
self.label_dict = {}
else:
self.label_dict = label_dict
self.allow_access_if_no_attr_labeled = allow_access_if_no_attr_labeled
self.attr_indicating_labeled_op = attr_indicating_labeled_op
self.logger = logging.getLogger("springpython.security.vote.LabelBasedAclVoter")
def supports(self, attr):
if isinstance(attr, list) or (attr == self.attr_indicating_labeled_op):
return True
else:
return False
def vote(self, authentication, invocation, config):
result = self.ACCESS_ABSTAIN;
for attribute in config:
if self.supports(attribute):
result = self.ACCESS_DENIED;
userLabels = []
for label in authentication.granted_auths:
if label in self.label_dict:
userLabels.extend(self.label_dict[label])
labeledArguments = [arg.getLabel() for arg in invocation.args if hasattr(arg, "getLabel")]
matches = [arg for arg in labeledArguments if arg in userLabels]
misses = [arg for arg in labeledArguments if arg not in userLabels]
self.logger.debug("Arguments: %s Matches: %s Misses: %s User labels: %s" % (labeledArguments, matches, misses, userLabels))
if len(matches) > 0 and misses == []:
self.logger.debug("Access is granted!")
return self.ACCESS_GRANTED;
elif labeledArguments == []:
if self.allow_access_if_no_attr_labeled:
self.logger.debug("Access is granted, since there are no attributes set!")
return self.ACCESS_GRANTED;
else:
self.logger.debug("Access is denied, since there are no attributes set!")
return self.ACCESS_DENIED;
self.logger.debug("No matches, so returning %s" % self.access_dict[result])
return result;
def __str__(self):
return "<'%s' label-based ACL voter>" % self.label_dict
class AccessDecisionManager:
""""
Makes a final access control (authorization) decision.
"""
def __init__(self, access_decision_voters = [], allow_if_all_abstain = False):
self.access_decision_voters = access_decision_voters
self.allow_if_all_abstain = allow_if_all_abstain
def decide(self, authentication, object, config):
"""Resolves an access control decision for the passed parameters."""
raise NotImplementedError()
def supports(self, attr):
"""
Indicates whether the AccessDecisionManager implementation is able to
provide access control decisions for the indicated secured object type.
"""
raise NotImplementedError()
class AffirmativeBased(AccessDecisionManager):
"""
Simple concrete implementation of AccessDecisionManager that grants access
if any AccessDecisionVoter returns an affirmative response.
"""
def __init__(self, access_decision_voters = [], allow_if_all_abstain = False):
AccessDecisionManager.__init__(self, access_decision_voters, allow_if_all_abstain)
self.logger = logging.getLogger("springpython.security.vote.AffirmativeBased")
def decide(self, authentication, invocation, config):
"""
This concrete implementation simply polls all configured
AccessDecisionVoters and grants access if any AccessDecisionVoter voted affirmatively.
"""
for voter in self.access_decision_voters:
if voter.supports(config) and \
voter.vote(authentication, invocation, config) == AccessDecisionVoter.ACCESS_GRANTED:
self.logger.debug("Received affirmative vote from %s, granting access." % voter)
return
raise AccessDeniedException("Access is denied.")
class ConsensusBased(AccessDecisionManager):
"""
Simple concrete implementation of AccessDecisionManager that uses a consensus-based approach.
"""
def __init__(self, access_decision_voters = [], allow_if_all_abstain = False):
AccessDecisionManager.__init__(self, access_decision_voters, allow_if_all_abstain)
self.allow_if_tied = True
self.logger = logging.getLogger("springpython.security.vote.ConsensusBased")
def decide(self, authentication, invocation, config):
"""
This concrete implementation simply polls all configured AccessDecisionVoters
and upon completion determines the consensus of granted vs denied responses.
"""
granted_votes = []
denied_votes = []
for voter in self.access_decision_voters:
if voter.supports(config):
vote = voter.vote(authentication, invocation, config)
if vote == AccessDecisionVoter.ACCESS_GRANTED:
granted_votes.append(voter)
if vote == AccessDecisionVoter.ACCESS_DENIED:
denied_votes.append(voter)
if len(granted_votes) > len(denied_votes):
self.logger.debug("%s granted votes, %s denial votes, granting access." % (len(granted_votes), len(denied_votes)))
return
elif len(granted_votes) < len(denied_votes):
self.logger.debug("%s granted votes, %s denial votes, denying access." % (len(granted_votes), len(denied_votes)))
raise AccessDeniedException("Access is denied.")
elif self.allow_if_tied:
self.logger.debug("%s granted votes, %s denial votes, granting access." % (len(granted_votes), len(denied_votes)))
return
else:
self.logger.debug("%s granted votes, %s denial votes, denying access." % (len(granted_votes), len(denied_votes)))
raise AccessDeniedException("Access is denied.")
class UnanimousBased(AccessDecisionManager):
"""
Simple concrete implementation of AccessDecisionManager that requires all voters to
abstain or grant access.
"""
def __init__(self, access_decision_voters = [], allow_if_all_abstain = False):
AccessDecisionManager.__init__(self, access_decision_voters, allow_if_all_abstain)
self.logger = logging.getLogger("springpython.security.vote.UnanimousBased")
def decide(self, authentication, invocation, config):
"""
This concrete implementation polls all configured AccessDecisionVoters for
each ConfigAttribute and grants access if only grant votes were received.
"""
for voter in self.access_decision_voters:
if voter.supports(config) and \
voter.vote(authentication, invocation, config) == AccessDecisionVoter.ACCESS_DENIED:
self.logger.debug("Received denial vote from %s, denying access" % voter)
raise AccessDeniedException("Access is denied.")
springpython-1.2.0+ds/springpython/security/context/ 0000755 0000000 0000000 00000000000 11544154725 021465 5 ustar root root springpython-1.2.0+ds/springpython/security/context/__init__.py 0000644 0000000 0000000 00000006174 11464332043 023576 0 ustar root root """
Copyright 2006-2008 SpringSource (http://springsource.com), All Rights Reserved
Licensed 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.
"""
import logging
import threading
from springpython.security.providers import Authentication
# See GlobalSecurityContextHolderStrategy
_globalContext = None
class SecurityContext(object):
def __init__(self, authentication = Authentication()):
self.authentication = authentication
def __str__(self):
if self.authentication == None:
return "Authentication is empty"
else:
return self.authentication.__str__()
class SecurityContextHolderStrategy(object):
"""Strategy interface to allow defining ways to store security context."""
def clearContext(self):
raise NotImplementedError()
def getContext(self):
raise NotImplementedError()
def setContext(self, context):
raise NotImplementedError()
class ThreadLocalSecurityContextHolderStrategy(SecurityContextHolderStrategy):
"""Strategy to store the security context in a local thread. This allows multi-threaded
apps to manage multiple contexts at the same time."""
def __init__(self):
self.logger = logging.getLogger("springpython.security.context.ThreadLocalSecurityContextHolderStrategy")
self.contextHolder = threading.local()
self.logger.debug("Creating a new threadlocal security context.")
self.clearContext()
def clearContext(self):
self.contextHolder.context = None
def getContext(self):
if not self.contextHolder.context:
self.setContext(SecurityContext())
return self.contextHolder.context
def setContext(self, context):
if not context:
raise SecurityException("Only non-None security context's are allowed")
self.contextHolder.context = context
class GlobalSecurityContextHolderStrategy(SecurityContextHolderStrategy):
"""Store one context in the entire python virtual machine. This typically suits a client-side
application."""
def __init__(self):
self.logger = logging.getLogger("springpython.security.context.GlobalSecurityContextHolderStrategy")
self.clearContext()
def clearContext(self):
global _globalContext
_globalContext = None
def getContext(self):
global _globalContext
if not _globalContext:
self.setContext(SecurityContext())
return _globalContext
def setContext(self, context):
global _globalContext
if not context:
raise SecurityException("Only non-None security context's are allowed")
_globalContext = context
springpython-1.2.0+ds/springpython/security/context/SecurityContextHolder.py 0000644 0000000 0000000 00000004232 11464332043 026342 0 ustar root root """
Copyright 2006-2008 SpringSource (http://springsource.com), All Rights Reserved
Licensed 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.
"""
from springpython.security import SecurityException
from springpython.security.context import ThreadLocalSecurityContextHolderStrategy
from springpython.security.context import GlobalSecurityContextHolderStrategy
"""
This represents a static object that holds the context of the current session.
"""
# Currently supported strategies
MODE_THREADLOCAL = "THREADLOCAL"
MODE_GLOBAL = "GLOBAL"
# Local settings used to track strategy configuration
settings = {"strategyName" : MODE_GLOBAL, "strategy" : None, "initialized" : False }
def initialize():
global settings
if settings["strategyName"] == MODE_THREADLOCAL:
settings["strategy"] = ThreadLocalSecurityContextHolderStrategy()
elif settings["strategyName"] == MODE_GLOBAL:
settings["strategy"] = GlobalSecurityContextHolderStrategy()
else:
raise SecurityException("We don't support strategy type %s" % settings["strategyName"])
settings["initialized"] = True
def setStrategy(newStrategyName):
global settings
settings["strategyName"] = newStrategyName
initialize()
def clearContext():
if not settings["initialized"]:
initialize()
settings["strategy"].clearContext()
def getContext():
"""Retrieve the context, based on the strategy."""
if not settings["initialized"]:
initialize()
return settings["strategy"].getContext()
def setContext(context):
"""Store the context, based on the strategy."""
if not settings["initialized"]:
initialize()
settings["strategy"].setContext(context)
springpython-1.2.0+ds/springpython/factory/ 0000755 0000000 0000000 00000000000 11544154725 017601 5 ustar root root springpython-1.2.0+ds/springpython/factory/__init__.py 0000644 0000000 0000000 00000005000 11412453030 021666 0 ustar root root """
Copyright 2006-2008 SpringSource (http://springsource.com), All Rights Reserved
Licensed 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.
"""
import logging
import sys
class ObjectFactory(object):
def create_object(self, constr, named_constr):
raise NotImplementedError()
class ReflectiveObjectFactory(ObjectFactory):
def __init__(self, module_and_class):
self.logger = logging.getLogger("springpython.factory.ReflectiveObjectFactory")
self.module_and_class = module_and_class
def create_object(self, constr, named_constr):
self.logger.debug("Creating an instance of %s" % self.module_and_class)
parts = self.module_and_class.split(".")
module_name = ".".join(parts[:-1])
class_name = parts[-1]
if module_name == "":
return __import__(class_name)(*constr, **named_constr)
else:
__import__(module_name)
cls = getattr(sys.modules[module_name], class_name)
return cls(*constr, **named_constr)
def __str__(self):
return "ReflectiveObjectFactory(%s)" % self.module_and_class
class PythonObjectFactory(ObjectFactory):
def __init__(self, method, wrapper):
self.logger = logging.getLogger("springpython.factory.PythonObjectFactory")
self.method = method
self.wrapper = wrapper
def create_object(self, constr, named_constr):
self.logger.debug("Creating an instance of %s" % self.method.func_name)
# Setting wrapper's top_func can NOT be done earlier than this method call,
# because it is tied to a wrapper decorator, which may not have yet been
# generated.
self.wrapper.func_globals["top_func"] = self.method.func_name
# Because @object-based objects use direct code to specify arguments, and NOT
# external configuration data, this factory doesn't care about the incoming arguments.
return self.method()
def __str__(self):
return "PythonObjectFactory(%s)" % self.method
springpython-1.2.0+ds/springpython/remoting/ 0000755 0000000 0000000 00000000000 11544154725 017756 5 ustar root root springpython-1.2.0+ds/springpython/remoting/hessian/ 0000755 0000000 0000000 00000000000 11544154725 021410 5 ustar root root springpython-1.2.0+ds/springpython/remoting/hessian/__init__.py 0000644 0000000 0000000 00000003277 11412453030 023513 0 ustar root root """
Copyright 2006-2008 SpringSource (http://springsource.com), All Rights Reserved
Licensed 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.
"""
from springpython.remoting.hessian.hessianlib import Hessian
class HessianProxyFactory(object):
"""
This is wrapper around a Hessian client proxy. The idea is to inject this object with a
Hessian service_url, which in turn generates a Hessian client proxy. After that, any
method calls or attribute accessses will be forwarded to the Hessian client proxy.
"""
def __init__(self):
self.__dict__["client_proxy"] = None
def __setattr__(self, name, value):
if name == "service_url":
self.__dict__["service_url"] = value
else:
setattr(self.client_proxy, name, value)
def __getattr__(self, name):
if name == "service_url":
return self.service_url
elif name in ["post_process_before_initialization", "post_process_after_initialization"]:
raise AttributeError, name
else:
if self.client_proxy is None:
self.__dict__["client_proxy"] = Hessian(self.service_url)
return getattr(self.client_proxy, name)
springpython-1.2.0+ds/springpython/remoting/hessian/hessianlib.py 0000644 0000000 0000000 00000027053 11412453030 024073 0 ustar root root #
# A Hessian client interface for Python. The date and long types require
# Python 2.2 or later.
#
# The Hessian proxy is used as follows:
#
# proxy = Hessian("http://hessian.caucho.com/test/basic")
#
# print proxy.hello()
#
# --------------------------------------------------------------------
#
# The Apache Software License, Version 1.1
#
# Copyright (c) 2001-2002 Caucho Technology, Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
#
# 3. The end-user documentation included with the redistribution, if
# any, must include the following acknowlegement:
# "This product includes software developed by the
# Caucho Technology (http://www.caucho.com/)."
# Alternately, this acknowlegement may appear in the software itself,
# if and wherever such third-party acknowlegements normally appear.
#
# 4. The names "Hessian", "Resin", and "Caucho" must not be used to
# endorse or promote products derived from this software without prior
# written permission. For written permission, please contact
# info@caucho.com.
#
# 5. Products derived from this software may not be called "Resin"
# nor may "Resin" appear in their names without prior written
# permission of Caucho Technology.
#
# THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL CAUCHO TECHNOLOGY OR ITS CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
# OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# --------------------------------------------------------------------
#
# Credits: hessianlib.py was inspired and partially based on
# xmlrpclib.py created by Fredrik Lundh at www.pythonware.org
#
import string, time
import urllib
from types import *
from struct import unpack
from struct import pack
__version__ = "0.1"
# --------------------------------------------------------------------
# Exceptions
class Error:
# base class for client errors
pass
class ProtocolError(Error):
# Represents an HTTP protocol error
def __init__(self, url, code, message, headers):
self.url = url
self.code = code
self.message = message
self.headers = headers
def __repr__(self):
return (
"" %
(self.url, self.code, self.message)
)
class Fault(Error):
# Represents a fault from Hessian
def __init__(self, code, message, **detail):
self.code = code
self.message = message
def __repr__(self):
return "" % (self.code, self.message)
# --------------------------------------------------------------------
# Wrappers for Hessian data types non-standard in Python
#
#
# Boolean -- use the True or False constants
#
class Boolean:
def __init__(self, value = 0):
self.value = (value != 0)
def _hessian_write(self, out):
if self.value:
out.write('T')
else:
out.write('F')
def __repr__(self):
if self.value:
return "" % id(self)
else:
return "" % id(self)
def __int__(self):
return self.value
def __nonzero__(self):
return self.value
True, False = Boolean(1), Boolean(0)
#
# Date - wraps a time value in seconds
#
class Date:
def __init__(self, value = 0):
self.value = value
def __repr__(self):
return ("" %
(time.asctime(time.localtime(self.value)), id(self)))
def _hessian_write(self, out):
out.write("d")
out.write(pack(">q", self.value * 1000.0))
#
# Binary - binary data
#
class Binary:
def __init__(self, data=None):
self.data = data
def _hessian_write(self, out):
out.write('B')
out.write(pack('>H', len(self.data)))
out.write(self.data)
# --------------------------------------------------------------------
# Marshalling and unmarshalling code
#
# HessianWriter - writes Hessian data from Python objects
#
class HessianWriter:
dispatch = {}
def write_call(self, method, params):
self.refs = {}
self.ref = 0
self.__out = []
self.write = write = self.__out.append
write("c\x01\x00m");
write(pack(">H", len(method)));
write(method);
for v in params:
self.write_object(v)
write("z");
result = string.join(self.__out, "")
del self.__out, self.write, self.refs
return result
def write_object(self, value):
try:
f = self.dispatch[type(value)]
except KeyError:
raise TypeError, "cannot write %s objects" % type(value)
else:
f(self, value)
def write_int(self, value):
self.write('I')
self.write(pack(">l", value))
dispatch[IntType] = write_int
def write_long(self, value):
self.write('L')
self.write(pack(">q", value))
dispatch[LongType] = write_long
def write_double(self, value):
self.write('D')
self.write(pack(">d", value))
dispatch[FloatType] = write_double
def write_string(self, value):
self.write('S')
self.write(pack('>H', len(value)))
self.write(value)
dispatch[StringType] = write_string
def write_reference(self, value):
# check for and write circular references
# returns 1 if the object should be written, i.e. not a reference
i = id(value)
if self.refs.has_key(i):
self.write('R')
self.write(pack(">L", self.refs[i]))
return 0
else:
self.refs[i] = self.ref
self.ref = self.ref + 1
return 1
def write_list(self, value):
if self.write_reference(value):
self.write("Vt\x00\x00I");
self.write(pack('>l', len(value)))
for v in value:
self.__write(v)
self.write('z')
dispatch[TupleType] = write_list
dispatch[ListType] = write_list
def write_map(self, value):
if self.write_reference(value):
self.write("Mt\x00\x00")
for k, v in value.items():
self.__write(k)
self.__write(v)
self.write("z")
dispatch[DictType] = write_map
def write_instance(self, value):
# check for special wrappers
if hasattr(value, "_hessian_write"):
value._hessian_write(self)
else:
fields = value.__dict__
if self.write_reference(fields):
self.write("Mt\x00\x00")
for k, v in fields.items():
self.__write(k)
self.__write(v)
self.write("z")
dispatch[InstanceType] = write_instance
#
# Parses the results from the server
#
class HessianParser:
def __init__(self, f):
self._f = f
self._peek = -1
# self.read = f.read
self._refs = []
def read(self, len):
if self._peek >= 0:
value = self._peek
self._peek = -1
return value
else:
return self._f.read(len)
def parse_reply(self):
# parse header 'c' x01 x00 'v' ... 'z'
read = self.read
if read(1) != 'r':
self.error()
major = read(1)
minor = read(1)
value = self.parse_object()
if read(1) == 'z':
return value
self.error() # actually a fault
def parse_object(self):
# parse an arbitrary object based on the type in the data
return self.parse_object_code(self.read(1))
def parse_object_code(self, code):
# parse an object when the code is known
read = self.read
if code == 'N':
return None
elif code == 'T':
return True
elif code == 'F':
return False
elif code == 'I':
return unpack('>l', read(4))[0]
elif code == 'L':
return unpack('>q', read(8))[0]
elif code == 'D':
return unpack('>d', read(8))[0]
elif code == 'd':
ms = unpack('>q', read(8))[0]
return Date(int(ms / 1000.0))
elif code == 'S' or code == 'X':
return self.parse_string()
elif code == 'B':
return Binary(self.parse_string())
elif code == 'V':
self.parse_type() # skip type
self.parse_length() # skip length
list = []
self._refs.append(list)
ch = read(1)
while ch != 'z':
list.append(self.parse_object_code(ch))
ch = read(1)
return list
elif code == 'M':
self.parse_type() # skip type
map = {}
self._refs.append(map)
ch = read(1)
while ch != 'z':
key = self.parse_object_code(ch)
value = self.parse_object()
map[key] = value
ch = read(1)
return map
elif code == 'R':
return self._refs[unpack('>l', read(4))[0]]
elif code == 'r':
self.parse_type() # skip type
url = self.parse_type() # reads the url
return Hessian(url)
else:
raise "UnknownObjectCode %d" % code
def parse_string(self):
f = self._f
len = unpack('>H', f.read(2))[0]
return f.read(len)
def parse_type(self):
f = self._f
code = self.read(1)
if code != 't':
self._peek = code
return ""
len = unpack('>H', f.read(2))[0]
return f.read(len)
def parse_length(self):
f = self._f
code = self.read(1);
if code != 'l':
self._peek = code
return -1;
len = unpack('>l', f.read(4))
return len
def error(self):
raise "FOO"
#
# Encapsulates the method to be called
#
class _Method:
def __init__(self, invoker, method):
self._invoker = invoker
self._method = method
def __call__(self, *args):
return self._invoker(self._method, args)
# --------------------------------------------------------------------
# Hessian is the main class. A Hessian proxy is created with the URL
# and then called just as for a local method
#
# proxy = Hessian("http://www.caucho.com/hessian/test/basic")
# print proxy.hello()
#
class Hessian:
"""Represents a remote object reachable by Hessian"""
def __init__(self, url):
# Creates a Hessian proxy object
self._url = url
# get the uri
type, uri = urllib.splittype(url)
if type != "http":
raise IOError, "unsupported Hessian protocol"
self._host, self._uri = urllib.splithost(uri)
def __invoke(self, method, params):
# call a method on the remote server
request = HessianWriter().write_call(method, params)
import httplib
h = httplib.HTTP(self._host)
h.putrequest("POST", self._uri)
# required by HTTP/1.1
h.putheader("Host", self._host)
h.putheader("User-Agent", "hessianlib.py/%s" % __version__)
h.putheader("Content-Length", str(len(request)))
h.endheaders()
h.send(request)
errcode, errmsg, headers = h.getreply()
if errcode != 200:
raise ProtocolError(self._url, errcode, errmsg, headers)
return self.parse_response(h.getfile())
def parse_response(self, f):
# read response from input file, and parse it
parser = HessianParser(f)
value = parser.parse_reply()
f.close()
return value
def _hessian_write(self, out):
# marshals the proxy itself
out.write("rt\x00\x00S")
out.write(pack(">H", len(self._url)))
out.write(self._url)
def __repr__(self):
return "" % self._url
__str__ = __repr__
def __getattr__(self, name):
# encapsulate the method call
return _Method(self.__invoke, name)
#
# Testing code.
#
if __name__ == "__main__":
proxy = Hessian("http://hessian.caucho.com/test/test")
try:
print proxy.hello()
except Error, v:
print "ERROR", v
springpython-1.2.0+ds/springpython/remoting/__init__.py 0000644 0000000 0000000 00000001213 11412453030 022045 0 ustar root root """
Copyright 2006-2008 SpringSource (http://springsource.com), All Rights Reserved
Licensed 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.
"""
springpython-1.2.0+ds/springpython/remoting/xmlrpc.py 0000644 0000000 0000000 00000017021 11464332043 021626 0 ustar root root # -*- coding: utf-8 -*-
# stdlib
import httplib
import logging
import socket
import ssl
import sys
import traceback
from SimpleXMLRPCServer import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler
from xmlrpclib import ServerProxy, Error, Transport
# Spring Python
from springpython.remoting.http import CAValidatingHTTPS
__all__ = ["VerificationException", "SSLServer", "SSLClient"]
class VerificationException(Exception):
""" Raised when the verification of a certificate's fields fails.
"""
# ##############################################################################
# Server
# ##############################################################################
class RequestHandler(SimpleXMLRPCRequestHandler):
rpc_paths = ("/", "/RPC2",)
def setup(self):
self.connection = self.request # for doPOST
self.rfile = socket._fileobject(self.request, "rb", self.rbufsize)
self.wfile = socket._fileobject(self.request, "wb", self.wbufsize)
class SSLServer(object, SimpleXMLRPCServer):
def __init__(self, host=None, port=None, keyfile=None, certfile=None,
ca_certs=None, cert_reqs=ssl.CERT_NONE, ssl_version=ssl.PROTOCOL_TLSv1,
do_handshake_on_connect=True, suppress_ragged_eofs=True, ciphers=None,
log_requests=True, **kwargs):
SimpleXMLRPCServer.__init__(self, (host, port), requestHandler=RequestHandler)
self.logger = logging.getLogger(self.__class__.__name__)
self.keyfile = keyfile
self.certfile = certfile
self.ca_certs = ca_certs
self.cert_reqs = cert_reqs
self.ssl_version = ssl_version
self.do_handshake_on_connect = do_handshake_on_connect
self.suppress_ragged_eofs = suppress_ragged_eofs
self.ciphers = ciphers
# Looks awkward to use camelCase here but that's what SimpleXMLRPCRequestHandler
# expects.
self.logRequests = log_requests
# 'verify_fields' is taken from kwargs to allow for adding more keywords
# in future versions.
self.verify_fields = kwargs.get("verify_fields")
self.register_functions()
def get_request(self):
""" Overridden from SocketServer.TCPServer.get_request, wraps the socket in
an SSL context.
"""
sock, from_addr = self.socket.accept()
# 'ciphers' argument is new in 2.7 and we must support 2.6 so add it
# to kwargs conditionally, depending on the Python version.
kwargs = {"keyfile":self.keyfile, "certfile":self.certfile,
"server_side":True, "cert_reqs":self.cert_reqs, "ssl_version":self.ssl_version,
"ca_certs":self.ca_certs, "do_handshake_on_connect":self.do_handshake_on_connect,
"suppress_ragged_eofs":self.suppress_ragged_eofs}
if sys.version_info >= (2, 7):
kwargs["ciphers"] = self.ciphers
sock = ssl.wrap_socket(sock, **kwargs)
if self.logger.isEnabledFor(logging.DEBUG):
self.logger.debug("get_request cert='%s', from_addr='%s'" % (sock.getpeercert(), from_addr))
return sock, from_addr
def verify_request(self, sock, from_addr):
""" Overridden from SocketServer.TCPServer.verify_request, adds validation of the
other side's certificate fields.
"""
try:
if self.verify_fields:
cert = sock.getpeercert()
if not cert:
msg = "Couldn't verify fields, peer didn't send the certificate, from_addr='%s'" % (from_addr,)
raise VerificationException(msg)
allow_peer, reason = self.verify_peer(cert, from_addr)
if not allow_peer:
self.logger.error(reason)
sock.close()
return False
except Exception, e:
# It was either an error on our side or the client didn't send the
# certificate even though self.cert_reqs was CERT_OPTIONAL (it couldn't
# have been CERT_REQUIRED because we wouldn't have got so far, the
# session would've been terminated much earlier in ssl.wrap_socket call).
# Regardless of the reason we cannot accept the client in that case.
msg = "Verification error='%s', cert='%s', from_addr='%s'" % (
traceback.format_exc(e), sock.getpeercert(), from_addr)
self.logger.error(msg)
sock.close()
return False
return True
def verify_peer(self, cert, from_addr):
""" Verifies the other side's certificate. May be overridden in subclasses
if the verification process needs to be customized.
"""
subject = cert.get("subject")
if not subject:
msg = "Peer certificate doesn't have the 'subject' field, cert='%s'" % cert
raise VerificationException(msg)
subject = dict(elem[0] for elem in subject)
for verify_field in self.verify_fields:
expected_value = self.verify_fields[verify_field]
cert_value = subject.get(verify_field, None)
if not cert_value:
reason = "Peer didn't send the '%s' field, subject fields received '%s'" % (
verify_field, subject)
return False, reason
if expected_value != cert_value:
reason = "Expected the subject field '%s' to have value '%s' instead of '%s', subject='%s'" % (
verify_field, expected_value, cert_value, subject)
return False, reason
return True, None
def register_functions(self):
raise NotImplementedError("Must be overridden by subclasses")
# ##############################################################################
# Client
# ##############################################################################
class SSLClientTransport(Transport):
""" Handles an HTTPS transaction to an XML-RPC server.
"""
user_agent = "SSL XML-RPC Client (by http://springpython.webfactional.com)"
def __init__(self, ca_certs=None, keyfile=None, certfile=None, cert_reqs=None,
ssl_version=None, timeout=None, strict=None):
self.ca_certs = ca_certs
self.keyfile = keyfile
self.certfile = certfile
self.cert_reqs = cert_reqs
self.ssl_version = ssl_version
self.timeout = timeout
self.strict = strict
Transport.__init__(self)
def make_connection(self, host):
return CAValidatingHTTPS(host, strict=self.strict, ca_certs=self.ca_certs,
keyfile=self.keyfile, certfile=self.certfile, cert_reqs=self.cert_reqs,
ssl_version=self.ssl_version, timeout=self.timeout)
class SSLClient(ServerProxy):
def __init__(self, uri=None, ca_certs=None, keyfile=None, certfile=None,
cert_reqs=ssl.CERT_REQUIRED, ssl_version=ssl.PROTOCOL_TLSv1,
transport=None, encoding=None, verbose=0, allow_none=0, use_datetime=0,
timeout=socket._GLOBAL_DEFAULT_TIMEOUT, strict=None):
if not transport:
_transport=SSLClientTransport(ca_certs, keyfile, certfile, cert_reqs,
ssl_version, timeout, strict)
else:
_transport=transport(ca_certs, keyfile, certfile, cert_reqs,
ssl_version, timeout, strict)
ServerProxy.__init__(self, uri, _transport, encoding, verbose,
allow_none, use_datetime)
self.logger = logging.getLogger(self.__class__.__name__) springpython-1.2.0+ds/springpython/remoting/http.py 0000644 0000000 0000000 00000003634 11464332043 021305 0 ustar root root # -*- coding: utf-8 -*-
# stdlib
import httplib
import socket
import ssl
class CAValidatingHTTPSConnection(httplib.HTTPConnection):
""" This class allows communication via SSL/TLS and takes Certificate Authorities
into account.
"""
def __init__(self, host, port=None, ca_certs=None, keyfile=None, certfile=None,
cert_reqs=None, strict=None, ssl_version=None,
timeout=None):
httplib.HTTPConnection.__init__(self, host, port, strict, timeout)
self.ca_certs = ca_certs
self.keyfile = keyfile
self.certfile = certfile
self.cert_reqs = cert_reqs
self.ssl_version = ssl_version
def connect(self):
""" Connect to a host on a given (SSL/TLS) port.
"""
sock = socket.create_connection((self.host, self.port), self.timeout)
if self._tunnel_host:
self.sock = sock
self._tunnel()
self.sock = self.wrap_socket(sock)
def wrap_socket(self, sock):
""" Gets a socket object and wraps it into an SSL/TLS-aware one. May be
overridden in subclasses if the wrapping process needs to be customized.
"""
return ssl.wrap_socket(sock, self.keyfile, self.certfile,
ca_certs=self.ca_certs, cert_reqs=self.cert_reqs,
ssl_version=self.ssl_version)
class CAValidatingHTTPS(httplib.HTTP):
""" A subclass of httplib.HTTP which is aware of Certificate Authorities
used in SSL/TLS transactions.
"""
_connection_class = CAValidatingHTTPSConnection
def __init__(self, host=None, port=None, strict=None, ca_certs=None, keyfile=None, certfile=None,
cert_reqs=None, ssl_version=None, timeout=None):
self._setup(self._connection_class(host, port, ca_certs, keyfile, certfile,
cert_reqs, strict, ssl_version, timeout)) springpython-1.2.0+ds/springpython/remoting/pyro/ 0000755 0000000 0000000 00000000000 11544154725 020747 5 ustar root root springpython-1.2.0+ds/springpython/remoting/pyro/__init__.py 0000644 0000000 0000000 00000016731 11464332043 023060 0 ustar root root """
Copyright 2006-2008 SpringSource (http://springsource.com), All Rights Reserved
Licensed 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.
"""
import logging
import Pyro.core
from springpython.context import InitializingObject
from springpython.remoting.pyro import PyroDaemonHolder
class PyroServiceExporter(InitializingObject):
"""
This class will expose an object using Pyro. It requires that a daemon thread
be up and running in order to receive requests and allow dispatching to the exposed
object.
"""
def __init__(self, service = None, service_name = None, service_host = "localhost", service_port = 7766):
self.logger = logging.getLogger("springpython.remoting.pyro.PyroServiceExporter")
self.service = service
self.service_name = service_name
self.service_host = service_host
self.service_port = service_port
self._pyro_thread = None
def __del__(self):
"""
When the service exporter goes out of scope and is garbage collected, the
service must be deregistered.
"""
PyroDaemonHolder.deregister(self.service_name, self.service_host, self.service_port)
def __setattr__(self, name, value):
"""
Only the explicitly listed attributes can be assigned values. Everything else is passed through to
the actual service.
"""
if name in ["logger", "service", "service_name", "service_host", "service_port", "_pyro_thread"]:
self.__dict__[name] = value
else:
object.__setattr__(self, name, value)
def after_properties_set(self):
if self.service is None: raise Exception("service must NOT be None")
if self.service_name is None: raise Exception("service_name must NOT be None")
if self.service_host is None: raise Exception("service_host must NOT be None")
if self.service_port is None: raise Exception("service_port must NOT be None")
self.logger.debug("Exporting %s as a Pyro service at %s:%s" % (self.service_name, self.service_host, self.service_port))
pyro_obj = Pyro.core.ObjBase()
pyro_obj.delegateTo(self.service)
PyroDaemonHolder.register(pyro_obj, self.service_name, self.service_host, self.service_port)
class PyroProxyFactory(object):
"""
This is wrapper around a Pyro client proxy. The idea is to inject this object with a
Pyro service_url, which in turn generates a Pyro client proxy. After that, any
method calls or attribute accessses will be forwarded to the Pyro client proxy.
"""
def __init__(self):
self.__dict__["client_proxy"] = None
self.__dict__["service_url"] = None
def __setattr__(self, name, value):
if name == "service_url":
self.__dict__["service_url"] = value
else:
setattr(self.client_proxy, name, value)
def __getattr__(self, name):
if name in ["service_url"]:
return self.__dict__[name]
elif name in ["post_process_before_initialization", "post_process_after_initialization"]:
raise AttributeError, name
else:
if self.client_proxy is None:
self.__dict__["client_proxy"] = Pyro.core.getProxyForURI(self.service_url)
return getattr(self.client_proxy, name)
class Pyro4ServiceExporter(InitializingObject):
"""
This class will expose an object using Pyro. It requires that a daemon thread
be up and running in order to receive requests and allow dispatching to the exposed
object.
"""
def __init__(self, service = None, service_name = None, service_host = "localhost", service_port = 7766):
self.logger = logging.getLogger("springpython.remoting.pyro.Pyro4ServiceExporter")
self.service = service
self.service_name = service_name
self.service_host = service_host
self.service_port = service_port
self._pyro_thread = None
def __del__(self):
"""
When the service exporter goes out of scope and is garbage collected, the
service must be deregistered.
"""
from springpython.remoting.pyro import Pyro4DaemonHolder
Pyro4DaemonHolder.deregister(self.service_name, self.service_host, self.service_port)
def __setattr__(self, name, value):
"""
Only the explicitly listed attributes can be assigned values. Everything else is passed through to
the actual service.
"""
if name in ["logger", "service", "service_name", "service_host", "service_port", "_pyro_thread"]:
self.__dict__[name] = value
else:
object.__setattr__(self, name, value)
def after_properties_set(self):
import Pyro4
from springpython.remoting.pyro import Pyro4DaemonHolder
if self.service is None: raise Exception("service must NOT be None")
if self.service_name is None: raise Exception("service_name must NOT be None")
if self.service_host is None: raise Exception("service_host must NOT be None")
if self.service_port is None: raise Exception("service_port must NOT be None")
self.logger.debug("Exporting %s as a Pyro service at %s:%s" % (self.service_name, self.service_host, self.service_port))
wrapping_obj = PyroWrapperObj(self.service)
Pyro4DaemonHolder.register(wrapping_obj, self.service_name, self.service_host, self.service_port)
class PyroWrapperObj(object):
def __init__(self, delegate):
self.delegate = delegate
def __getattr__(self, name):
if name in ["__pyroInvoke", "__call__", "_pyroId", "_pyroDaemon", "delegate"]:
return self.__dict__[name]
else:
return getattr(self.delegate, name)
def __setattr__(self, name, value):
if name in ["__pyroInvoke", "__call__", "_pyroId", "_pyroDaemon", "delegate"]:
self.__dict__[name] = value
else:
setattr(self.delegate, name, value)
class Pyro4ProxyFactory(object):
"""
This is wrapper around a Pyro client proxy. The idea is to inject this object with a
Pyro service_url, which in turn generates a Pyro client proxy. After that, any
method calls or attribute accessses will be forwarded to the Pyro client proxy.
"""
def __init__(self):
self.__dict__["client_proxy"] = None
self.__dict__["service_url"] = None
def __setattr__(self, name, value):
if name == "service_url":
self.__dict__["service_url"] = value
else:
setattr(self.client_proxy, name, value)
def __getattr__(self, name):
import Pyro4
if name in ["service_url"]:
return self.__dict__[name]
elif name in ["post_process_before_initialization", "post_process_after_initialization"]:
raise AttributeError, name
else:
if self.client_proxy is None:
self.__dict__["client_proxy"] = Pyro4.Proxy(self.service_url)
return getattr(self.client_proxy, name)
springpython-1.2.0+ds/springpython/remoting/pyro/Pyro4DaemonHolder.py 0000644 0000000 0000000 00000011367 11464332043 024620 0 ustar root root """
Copyright 2006-2008 SpringSource (http://springsource.com), All Rights Reserved
Licensed 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.
"""
import logging
import threading
import time
import Pyro4
from socket import getaddrinfo, gethostbyname
pyro_threads = {}
serviceList = {}
logger = logging.getLogger("springpython.remoting.pyro.Pyro4DaemonHolder")
def resolve(host, port):
canonhost = gethostbyname(host)
canonport = getaddrinfo(host, port)[0][4][1]
return canonhost, canonport
def register(pyro_obj, service_name, host, port):
"""
Register the Pyro4 object and its service name with the daemon.
Also add the service to a dictionary of objects. This allows the
PyroDaemonHolder to intelligently know when to start and stop the
daemon thread.
"""
logger.debug("Registering %s at %s:%s with the Pyro4 server" % (service_name, host, port))
host, port = resolve(host, port)
serviceList[(service_name, host, port)] = pyro_obj
if (host, port) not in pyro_threads:
logger.debug("Pyro4 thread needs to be started at %s:%s" % (host, port))
pyro_threads[(host, port)] = _Pyro4Thread(host, port)
pyro_threads[(host, port)].start()
if not hasattr(pyro_obj, "_pyroId"):
uri = pyro_threads[(host, port)].pyro_daemon.register(pyro_obj, service_name)
def deregister(service_name, host, port):
"""
Deregister the named service by removing it from the list of
managed services and also disconnect from the daemon.
"""
logger.debug("Deregistering %s at %s:%s with the Pyro4 server" % (service_name, host, port))
host, port = resolve(host, port)
if (host, port) in pyro_threads:
pyro_threads[(host, port)].pyro_daemon.unregister(serviceList[(service_name, host, port)])
del(serviceList[(service_name, host, port)])
def get_address((service_name, host, port)):
return (host, port)
if len([True for x in serviceList.keys() if get_address(x) == (host, port)]) == 0:
shutdown(host, port)
def shutdown(daemon_host, daemon_port):
"""This provides a hook so an application can deliberately shutdown a
daemon thread."""
logger.debug("Shutting down Pyro4 daemon at %s:%s" % (daemon_host, daemon_port))
daemon_host, daemon_port = resolve(daemon_host, daemon_port)
try:
pyro_threads[(daemon_host, daemon_port)].shutdown()
time.sleep(1.0)
del(pyro_threads[(daemon_host, daemon_port)])
except Exception, e:
logger.debug("Failed to shutdown %s:%s => %s" % (daemon_host, daemon_port, e))
class _Pyro4Thread(threading.Thread):
"""
This is a thread that runs the Pyro4 daemon. It is instantiated automatically
from within Pyro4ServiceExporter.
"""
def __init__(self, host, port):
"""
When this class is created, it also created a Pyro4 core daemon to manage.
"""
threading.Thread.__init__(self)
self.host = host
self.port = port
self.logger = logging.getLogger("springpython.remoting.pyro.Pyro4DaemonHolder._Pyro4Thread")
self.logger.debug("Creating Pyro4 daemon")
self.pyro_daemon = Pyro4.Daemon(host=host, port=port)
def run(self):
"""
When this thread starts up, it initializes the Pyro4 server and then puts the
daemon into listen mode so it can process remote requests.
"""
self.logger.debug("Starting up Pyro4 server thread for %s:%s" % (self.host, self.port))
self.pyro_daemon.requestLoop()
def shutdown(self):
"""
This is a hook in order to signal the thread that its time to shutdown
the Pyro4 daemon.
"""
self.logger.debug("Signaling shutdown of Pyro4 server thread for %s:%s" % (self.host, self.port))
class ShutdownThread(threading.Thread):
def __init__(self, pyro_daemon):
threading.Thread.__init__(self)
self.pyro_daemon = pyro_daemon
self.logger = logging.getLogger("springpython.remoting.pyro.Pyro4DaemonHolder.ShutdownThread")
def run(self):
self.logger.debug("Sending shutdown signal...")
self.pyro_daemon.shutdown()
ShutdownThread(self.pyro_daemon).start()
springpython-1.2.0+ds/springpython/remoting/pyro/PyroDaemonHolder.py 0000644 0000000 0000000 00000010370 11464323256 024533 0 ustar root root """
Copyright 2006-2008 SpringSource (http://springsource.com), All Rights Reserved
Licensed 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.
"""
import logging
import threading
import Pyro.core, Pyro.naming
from socket import getaddrinfo, gethostbyname
pyro_threads = {}
serviceList = {}
logger = logging.getLogger("springpython.remoting.pyro.PyroDaemonHolder")
def resolve(host, port):
canonhost = gethostbyname(host)
canonport = getaddrinfo(host, port)[0][4][1]
return canonhost, canonport
def register(pyro_obj, service_name, host, port):
"""
Register the pyro object and its service name with the daemon.
Also add the service to a dictionary of objects. This allows the
PyroDaemonHolder to intelligently know when to start and stop the
daemon thread.
"""
logger.debug("Registering %s at %s:%s with the Pyro server" % (service_name, host, port))
host, port = resolve(host, port)
serviceList[(service_name, host, port)] = pyro_obj
if (host, port) not in pyro_threads:
logger.debug("Pyro thread needs to be started at %s:%s" % (host, port))
pyro_threads[(host, port)] = _PyroThread(host, port)
pyro_threads[(host, port)].start()
pyro_threads[(host, port)].pyro_daemon.connect(pyro_obj, service_name)
def deregister(service_name, host, port):
"""
Deregister the named service by removing it from the list of
managed services and also disconnect from the daemon.
"""
logger.debug("Deregistering %s at %s:%s with the Pyro server" % (service_name, host, port))
host, port = resolve(host, port)
pyro_threads[(host, port)].pyro_daemon.disconnect(serviceList[(service_name, host, port)])
del(serviceList[(service_name, host, port)])
def get_address((service_name, host, port)):
return (host, port)
if len([True for x in serviceList.keys() if get_address(x) == (host, port)]) == 0:
logger.debug("Shutting down thread on %s:%s" % (host, port))
shutdown(host, port)
def shutdown(daemon_host, daemon_port):
"""This provides a hook so an application can deliberately shutdown a
daemon thread."""
logger.debug("Shutting down pyro daemon at %s:%s" % (daemon_host, daemon_port))
daemon_host, daemon_port = resolve(daemon_host, daemon_port)
try:
pyro_threads[(daemon_host, daemon_port)].shutdown()
del(pyro_threads[(daemon_host, daemon_port)])
except:
logger.debug("Failed to shutdown %s:%s" % (daemon_host, daemon_port))
class _PyroThread(threading.Thread):
"""
This is a thread that runs the Pyro daemon. It is instantiated automatically
from within PyroServiceExporter.
"""
def __init__(self, host, port):
"""
When this class is created, it also created a Pyro core daemon to manage.
"""
threading.Thread.__init__(self)
self.host = host
self.port = port
self.logger = logging.getLogger("springpython.remoting.pyro.PyroDaemonHolder._PyroThread")
self.pyro_daemon = Pyro.core.Daemon(host=host, port=port)
def run(self):
"""
When this thread starts up, it initializes the Pyro server and then puts the
daemon into listen mode so it can process remote requests.
"""
self._running = True
self.logger.debug("Starting up Pyro server thread for %s:%s" % (self.host, self.port))
Pyro.core.initServer()
self.pyro_daemon.requestLoop(condition = lambda:self._running)
def shutdown(self):
"""
This is a hook in order to signal the thread that its time to shutdown
the Pyro daemon.
"""
self._running = False
self.logger.debug("Signaling shutdown of Pyro server thread for %s:%s" % (self.host, self.port))
springpython-1.2.0+ds/springpython/container/ 0000755 0000000 0000000 00000000000 11544154725 020114 5 ustar root root springpython-1.2.0+ds/springpython/container/__init__.py 0000644 0000000 0000000 00000014771 11464332043 022227 0 ustar root root """
Copyright 2006-2008 SpringSource (http://springsource.com), All Rights Reserved
Licensed 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.
"""
import logging
from springpython.context import scope
class ObjectContainer(object):
"""
ObjectContainer is a container which uses multiple Config objects to read sources of
object definitions. When a object is requested from this container, it may optionally
pull the object from a scoped cache. If there is no stored copy of the object, it
uses the scanned definition and its associated ObjectFactory to create an instance. It
can then optionally store it in a scoped cache for future usage (e.g. singleton).
Object definitions are stored in the container in a neutral format, decoupling the
container entirely from the original source location. This means that XML, python code,
and other formats may all contain definitions. By the time they
reach this container, it doesn't matter what their original format was when a object
instance is needed. NOTE: This explicitly means that one object in one source
can refer to another object in another source OF ANY FORMAT as a property.
"""
def __init__(self, config = None):
self.logger = logging.getLogger("springpython.container.ObjectContainer")
if config is None:
self.configs = []
elif isinstance(config, list):
self.configs = config
else:
self.configs = [config]
self.object_defs = {}
for configuration in self.configs:
self.logger.debug("=== Scanning configuration %s for object definitions ===" % configuration)
for object_def in configuration.read_object_defs():
if object_def.id not in self.object_defs:
self.logger.debug("%s object definition does not exist. Adding to list of definitions." % object_def.id)
else:
self.logger.debug("Overriding previous definition of %s" % object_def.id)
self.object_defs[object_def.id] = object_def
self.logger.debug("=== Done reading object definitions. ===")
self.objects = {}
def get_object(self, name, ignore_abstract=False):
"""
This function attempts to find the object in the singleton cache. If not found,
delegates to _create_object in order to hunt for the definition, and request a
object factory to generate one.
"""
try:
object_def = self.object_defs[name]
if object_def.abstract and not ignore_abstract:
raise AbstractObjectException("Object [%s] is an abstract one." % name)
return self.objects[name]
except KeyError, e:
self.logger.debug("Did NOT find object '%s' in the singleton storage." % name)
try:
object_def = self.object_defs[name]
if object_def.abstract and not ignore_abstract:
raise AbstractObjectException("Object [%s] is an abstract one." % name)
comp = self._create_object(object_def)
# Evaluate any scopes, and store appropriately.
if self.object_defs[name].scope == scope.SINGLETON:
self.objects[name] = comp
self.logger.debug("Stored object '%s' in container's singleton storage" % name)
elif self.object_defs[name].scope == scope.PROTOTYPE:
pass
else:
raise InvalidObjectScope("Don't know how to handle scope %s" % self.object_defs[name].scope)
return comp
except KeyError, e:
self.logger.error("Object '%s' has no definition!" % name)
raise e
def _get_constructors_pos(self, object_def):
"""
This function iterates over the positional constructors, and assembles their values into a list.
In this situation, the order as read from the XML should be the order expected by the class
definition.
"""
return tuple([constr.get_value(self) for constr in object_def.pos_constr
if hasattr(constr, "get_value")])
def _get_constructors_kw(self, kwargs):
"""
This function iterates over the named constructors, and assembles their values into a list.
In this situation, each argument is associated with a name, and due to unicode format provided
by the XML parser, requires conversion into a new dictionary.
"""
return dict([(key, kwargs[key].get_value(self)) for key in kwargs
if hasattr(kwargs[key], "get_value")])
def _create_object(self, object_def):
"""
If the object isn't stored in any scoped cache, and must instead be created, this method
takes all the steps to read the object's definition, res it up, and store it in the appropriate
scoped cache.
"""
self.logger.debug("Creating an instance of %s" % object_def)
[constr.prefetch(self) for constr in object_def.pos_constr if hasattr(constr, "prefetch")]
[constr.prefetch(self) for constr in object_def.named_constr.values() if hasattr(constr, "prefetch")]
[prop.prefetch(self) for prop in object_def.props if hasattr(prop, "prefetch")]
# Res up an instance of the object, with ONLY constructor-based properties set.
obj = object_def.factory.create_object(self._get_constructors_pos(object_def),
self._get_constructors_kw(object_def.named_constr))
# Fill in the other property values.
[prop.set_value(obj, self) for prop in object_def.props if hasattr(prop, "set_value")]
return obj
class AbstractObjectException(Exception):
""" Raised when the user's code tries to get an abstract object from
the container.
"""
class InvalidObjectScope(Exception):
pass
springpython-1.2.0+ds/springpython/config/ 0000755 0000000 0000000 00000000000 11544154725 017377 5 ustar root root springpython-1.2.0+ds/springpython/config/__init__.py 0000644 0000000 0000000 00000001360 11464332043 021500 0 ustar root root """
Copyright 2006-2008 SpringSource (http://springsource.com), All Rights Reserved
Licensed 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.
"""
from _config_base import *
from _xml_config import *
from _yaml_config import *
from _python_config import *
springpython-1.2.0+ds/springpython/config/_config_base.py 0000644 0000000 0000000 00000026357 11464332043 022354 0 ustar root root """
Copyright 2006-2008 SpringSource (http://springsource.com), All Rights Reserved
Licensed 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.
"""
import re
import types
import inspect
import logging
from springpython.context import scope
from decorator import decorator, partial
from springpython.context import ApplicationContextAware
from springpython.factory import PythonObjectFactory
from springpython.factory import ReflectiveObjectFactory
from springpython.container import InvalidObjectScope
def get_string(value):
"""This function is used to parse text that could either be ASCII or unicode."""
try:
return str(value)
except UnicodeEncodeError:
return unicode(value)
class ObjectDef(object):
"""
ObjectDef is a format-neutral way of storing object definition information. It includes
a handle for the actual ObjectFactory that should be used to utilize this information when
creating an instance of a object.
"""
def __init__(self, id, props=None, factory=None, scope=scope.SINGLETON,
lazy_init=False, abstract=False, parent=None):
super(ObjectDef, self).__init__()
self.id = id
self.factory = factory
if props is None:
self.props = []
else:
self.props = props
self.scope = scope
self.lazy_init = lazy_init
self.abstract = abstract
self.parent = parent
self.pos_constr = []
self.named_constr = {}
def __str__(self):
return "id=%s props=%s scope=%s factory=%s" % (self.id, self.props, self.scope, self.factory)
class ReferenceDef(object):
"""
This class represents a definition that is referencing another object.
"""
def __init__(self, name, ref):
self.name = name
self.ref = ref
def prefetch(self, container):
self.get_value(container)
def get_value(self, container):
return container.get_object(self.ref)
def set_value(self, obj, container):
setattr(obj, self.name, container.objects[self.ref])
def __str__(self):
return "name=%s ref=%s" % (self.name, self.ref)
class InnerObjectDef(object):
"""
This class represents an inner object. It is optional whether or not the object
has its own name.
"""
def __init__(self, name, inner_comp):
self.name = name
self.inner_comp = inner_comp
def prefetch(self, container):
self.get_value(container)
def get_value(self, container):
return container.get_object(self.inner_comp.id)
def set_value(self, obj, container):
setattr(obj, self.name, self.get_value(container))
def __str__(self):
return "name=%s inner_comp=%s" % (self.name, self.inner_comp)
class ValueDef(object):
"""
This class represents a property that holds a value. The value can be simple value, or
it can be a complex container which internally holds references, inner objects, or
any other type.
"""
def __init__(self, name, value):
self.name = name
if value == "True":
self.value = True
elif value == "False":
self.value= False
else:
self.value = value
self.logger = logging.getLogger("springpython.config.ValueDef")
def scan_value(self, container, value):
if hasattr(value, "get_value"):
return value.get_value(container)
elif isinstance(value, tuple):
new_list = [self.scan_value(container, item) for item in value]
results = tuple(new_list)
return results
elif isinstance(value, list):
new_list = [self.scan_value(container, item) for item in value]
return new_list
elif isinstance(value, set):
results = set([self.scan_value(container, item) for item in value])
return results
elif isinstance(value, frozenset):
results = frozenset([self.scan_value(container, item) for item in value])
return results
else:
if value == "True":
return True
elif value == "False":
return False
else:
return value
def get_value(self, container):
val = self._replace_refs_with_actuals(self.value, container)
if val is None:
return self.value
else:
return val
def set_value(self, obj, container):
setattr(obj, self.name, self.value)
val = self._replace_refs_with_actuals(obj, container)
def _replace_refs_with_actuals(self, obj, container):
"""Normal values do nothing for this step. However, sub-classes are defined for
the various containers, like lists, set, dictionaries, etc., to handle iterating
through and pre-fetching items."""
pass
def __str__(self):
return "name=%s value=%s" % (self.name, self.value)
class DictDef(ValueDef):
"""Handles behavior for a dictionary-based value."""
def __init__(self, name, value):
super(DictDef, self).__init__(name, value)
def _replace_refs_with_actuals(self, obj, container):
for key in self.value.keys():
if hasattr(self.value[key], "ref"):
self.value[key] = container.get_object(self.value[key].ref)
else:
self.value[key] = self.scan_value(container, self.value[key])
class ListDef(ValueDef):
"""Handles behavior for a list-based value."""
def __init__(self, name, value):
super(ListDef, self).__init__(name, value)
self.logger = logging.getLogger("springpython.config.ListDef")
def _replace_refs_with_actuals(self, obj, container):
for i in range(0, len(self.value)):
self.logger.debug("Checking out %s, wondering if I need to do any replacement..." % get_string(self.value[i]))
if hasattr(self.value[i], "ref"):
self.value[i] = container.get_object(self.value[i].ref)
else:
self.value[i] = self.scan_value(container, self.value[i])
class TupleDef(ValueDef):
"""Handles behavior for a tuple-based value."""
def __init__(self, name, value):
super(TupleDef, self).__init__(name, value)
def _replace_refs_with_actuals(self, obj, container):
new_value = list(self.value)
for i in range(0, len(new_value)):
if hasattr(new_value[i], "ref"):
new_value[i] = container.get_object(new_value[i].ref)
else:
new_value[i] = self.scan_value(container, new_value[i])
try:
setattr(obj, self.name, tuple(new_value))
except AttributeError:
pass
return tuple(new_value)
class SetDef(ValueDef):
"""Handles behavior for a set-based value."""
def __init__(self, name, value):
super(SetDef, self).__init__(name, value)
self.logger = logging.getLogger("springpython.config.SetDef")
def _replace_refs_with_actuals(self, obj, container):
self.logger.debug("Replacing refs with actuals...")
self.logger.debug("set before changes = %s" % self.value)
new_set = set()
for item in self.value:
if hasattr(item, "ref"):
self.logger.debug("Item !!!%s!!! is a ref, trying to replace with actual object !!!%s!!!" % (item, item.ref))
#self.value.remove(item)
#self.value.add(container.get_object(item.ref))
newly_fetched_value = container.get_object(item.ref)
new_set.add(newly_fetched_value)
self.logger.debug("Item !!!%s!!! was removed, and newly fetched value !!!%s!!! was added." % (item, newly_fetched_value))
#new_set.add(container.get_object(item.ref))
else:
self.logger.debug("Item !!!%s!!! is NOT a ref, trying to replace with scanned value" % get_string(item))
#self.value.remove(item)
#self.value.add(self.scan_value(container, item))
newly_scanned_value = self.scan_value(container, item)
new_set.add(newly_scanned_value)
self.logger.debug("Item !!!%s!!! was removed, and newly scanned value !!!%s!!! was added." % (item, newly_scanned_value))
#new_set.add(self.scan_value(container, item))
#self.value = new_set
self.logger.debug("set after changes = %s" % new_set)
#return self.value
try:
setattr(obj, self.name, new_set)
except AttributeError:
pass
return new_set
class FrozenSetDef(ValueDef):
"""Handles behavior for a frozen-set-based value."""
def __init__(self, name, value):
super(FrozenSetDef, self).__init__(name, value)
self.logger = logging.getLogger("springpython.config.FrozenSetDef")
def _replace_refs_with_actuals(self, obj, container):
self.logger.debug("Replacing refs with actuals...")
self.logger.debug("set before changes = %s" % self.value)
new_set = set()
for item in self.value:
if hasattr(item, "ref"):
self.logger.debug("Item <<<%s>>> is a ref, trying to replace with actual object <<<%s>>>" % (item, item.ref))
#new_set.remove(item)
#debug begin
newly_fetched_value = container.get_object(item.ref)
new_set.add(newly_fetched_value)
self.logger.debug("Item <<<%s>>> was removed, and newly fetched value <<<%s>>> was added." % (item, newly_fetched_value))
#debug end
#new_set.add(container.get_object(item.ref))
else:
self.logger.debug("Item <<<%s>>> is NOT a ref, trying to replace with scanned value" % get_string(item))
#new_set.remove(item)
#debug begin
newly_scanned_value = self.scan_value(container, item)
new_set.add(newly_scanned_value)
self.logger.debug("Item <<<%s>>> was removed, and newly scanned value <<<%s>>> was added." % (item, newly_scanned_value))
#debug end
#new_set.add(self.scan_value(container, item))
#self.logger.debug("Newly built set = %s" % new_set)
#self.value = frozenset(new_set)
new_frozen_set = frozenset(new_set)
self.logger.debug("set after changes = %s" % new_frozen_set)
#return self.value
try:
setattr(obj, self.name, new_frozen_set)
except AttributeError:
pass
except TypeError:
pass
return new_frozen_set
class Config(object):
"""
Config is an interface that defines how to read object definitions from an input source.
"""
def read_object_defs(self):
"""Abstract method definition - should return an array of Object objects"""
raise NotImplementedError()
springpython-1.2.0+ds/springpython/config/_python_config.py 0000644 0000000 0000000 00000013330 11464332043 022746 0 ustar root root """
Copyright 2006-2008 SpringSource (http://springsource.com), All Rights Reserved
Licensed 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.
"""
try:
import cElementTree as etree
except ImportError:
try:
import xml.etree.ElementTree as etree
except ImportError:
from elementtree import ElementTree as etree
import re
import types
import inspect
import logging
from _config_base import *
from springpython.context import scope
from decorator import decorator, partial
from springpython.context import ApplicationContextAware
from springpython.factory import PythonObjectFactory
from springpython.factory import ReflectiveObjectFactory
from springpython.container import InvalidObjectScope
class PythonConfig(Config, ApplicationContextAware):
"""
PythonConfig supports using pure python code to define objects.
"""
def __init__(self):
self.logger = logging.getLogger("springpython.config.PythonConfig")
super(PythonConfig, self).__init__()
def read_object_defs(self):
self.logger.debug("==============================================================")
objects = []
self.logger.debug("Parsing %s" % self)
for name, method in inspect.getmembers(self, inspect.ismethod):
if name not in _pythonConfigMethods:
try:
wrapper = method.im_func.func_globals["_call_"]
if wrapper.func_name.startswith("object"):
c = ObjectDef(id=name, factory=PythonObjectFactory(method, wrapper),
scope=wrapper.scope, lazy_init=wrapper.lazy_init,
abstract=wrapper.abstract, parent=wrapper.parent)
objects.append(c)
except KeyError, e:
pass
self.logger.debug("==============================================================")
return objects
def set_app_context(self, app_context):
super(PythonConfig, self).set_app_context(app_context)
try:
_object_context[(self,)]["container"] = app_context
except KeyError, e:
_object_context[(self,)] = {"container": app_context}
_pythonConfigMethods = [name for (name, method) in inspect.getmembers(PythonConfig, inspect.ismethod)]
_object_context = {}
def _object_wrapper(f, scope, parent, log_func_name, *args, **kwargs):
"""
This function checks if the object already exists in the container. If so,
it will retrieve its results. Otherwise, it calls the function.
For prototype objects, the function is basically a pass through,
because everytime a prototype function is called, there should be no
caching of results.
Using the @decorator library greatly simplifies the implementation of this.
"""
def _deco(f, scope, parent, log_func_name, *args, **kwargs):
log = logging.getLogger("springpython.config.%s%s - %s%s" % (log_func_name,
f, str(args), scope))
if f.func_name != top_func:
log.debug("This is NOT the top-level object %s, deferring to container." % top_func)
container = _object_context[args]["container"]
log.debug("Container = %s" % container)
if parent:
parent_result = container.get_object(parent, ignore_abstract=True)
log.debug("This IS the top-level object, calling %s(%s)" \
% (f.func_name, parent_result))
results = container.get_object(f.func_name)(parent_result)
else:
results = container.get_object(f.func_name)
log.debug("Found %s inside the container" % results)
return results
else:
if parent:
container = _object_context[(args[0],)]["container"]
parent_result = container.get_object(parent, ignore_abstract=True)
log.debug("This IS the top-level object, calling %s(%s)" \
% (f.func_name, parent_result))
results = f(container, parent_result)
else:
log.debug("This IS the top-level object, calling %s()." % f.func_name)
results = f(*args, **kwargs)
log.debug("Found %s" % results)
return results
return _deco(f, scope, parent, log_func_name, *args, **kwargs)
def Object(theScope=scope.SINGLETON, lazy_init=False, abstract=False, parent=None):
"""
This function is a wrapper around the function which returns the real decorator.
It decides, based on scope and lazy-init, which decorator to return.
"""
if type(theScope) == types.FunctionType:
return Object()(theScope)
elif theScope == scope.SINGLETON:
log_func_name = "objectSingleton"
elif theScope == scope.PROTOTYPE:
log_func_name = "objectPrototype"
else:
raise InvalidObjectScope("Don't know how to handle scope %s" % theScope)
def object_wrapper(f, *args, **kwargs):
return _object_wrapper(f, theScope, parent, log_func_name, *args, **kwargs)
object_wrapper.lazy_init = lazy_init
object_wrapper.abstract = abstract
object_wrapper.parent = parent
object_wrapper.scope = theScope
return decorator(object_wrapper)
springpython-1.2.0+ds/springpython/config/_yaml_config.py 0000644 0000000 0000000 00000045010 11464332043 022367 0 ustar root root """
Copyright 2006-2008 SpringSource (http://springsource.com), All Rights Reserved
Licensed 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.
"""
import re
import types
import inspect
import logging
from _config_base import *
from springpython.context import scope
from decorator import decorator, partial
from springpython.context import ApplicationContextAware
from springpython.factory import PythonObjectFactory
from springpython.factory import ReflectiveObjectFactory
from springpython.container import InvalidObjectScope
yaml_mappings = {
"str":"types.StringType", "unicode":"types.UnicodeType",
"int":"types.IntType", "long":"types.LongType",
"float":"types.FloatType", "decimal":"decimal.Decimal",
"bool":"types.BooleanType", "complex":"types.ComplexType",
"list":"types.ListType", "tuple":"types.TupleType",
"dict":"types.DictType",
}
class YamlConfig(Config):
"""
YamlConfig provides an alternative YAML-based version of objects.
"""
def __init__(self, config_location):
if isinstance(config_location, list):
self.config_location = config_location
else:
self.config_location = [config_location]
self.logger = logging.getLogger("springpython.config.YamlConfig")
# By making this an instance-based property (instead of function local), inner object
# definitions can add themselves to the list in the midst of parsing an input.
self.objects = []
def read_object_defs(self):
import yaml
self.logger.debug("==============================================================")
# Reset, in case the file is re-read
self.objects = []
for config in self.config_location:
self.logger.debug("* Parsing %s" % config)
stream = file(config)
doc = yaml.load(stream)
self.logger.debug(doc)
# A dictionary of abstract objects, keyed by their IDs, used in
# traversing the hierarchies of parents; built upfront here for
# convenience.
abstract_objects = {}
for object in doc["objects"]:
if "abstract" in object:
abstract_objects[object["object"]] = object
for object in doc["objects"]:
if not "class" in object and not "parent" in object:
self._map_custom_class(object, yaml_mappings)
elif "parent" in object:
# Children are added to self.objects during the children->abstract parents traversal.
pos_constr = self._get_pos_constr(object)
named_constr = self._get_named_constr(object)
props = self._get_props(object)
self._traverse_parents(object, object, pos_constr, named_constr, props, abstract_objects)
continue
self._print_obj(object)
self.objects.append(self._convert_object(object))
self.logger.debug("==============================================================")
self.logger.debug("objects = %s" % self.objects)
return self.objects
def _map_custom_class(self, obj, mappings):
""" Enrich the object's attributes and make it look to the rest of
YamlConfig as if the object had all of them right in the definition.
"""
for class_name in mappings:
if class_name in obj:
self.logger.debug("Found a matching type: %s -> %s" % (obj["object"],
class_name))
obj["class"] = mappings[class_name]
obj["constructor-args"] = [obj[class_name]]
break
else:
self.logger.warning("No matching type found for object %s" % obj)
def _traverse_parents(self, leaf, child, pos_constr,
named_constr, props, abstract_objects):
parent = abstract_objects[child["parent"]]
# At this point we only build up the lists of parameters but we don't create
# the object yet because the current parent object may still have its
# own parent.
# Positional constructors
parent_pos_constrs = self._get_pos_constr(parent)
# Make sure there are as many child positional parameters as there
# are in the parent's list.
len_pos_constr = len(pos_constr)
len_parent_pos_constrs = len(parent_pos_constrs)
if len_pos_constr < len_parent_pos_constrs:
pos_constr.extend([None] * (len_parent_pos_constrs - len_pos_constr))
for idx, parent_pos_constr in enumerate(parent_pos_constrs):
if not pos_constr[idx]:
pos_constr[idx] = parent_pos_constr
# Named constructors
child_named_constrs = named_constr
parent_named_constrs = self._get_named_constr(parent)
for parent_named_constr in parent_named_constrs:
if parent_named_constr not in child_named_constrs:
named_constr[parent_named_constr] = parent_named_constrs[parent_named_constr]
# Properties
child_props = [prop.name for prop in props]
parent_props = self._get_props(parent)
for parent_prop in parent_props:
if parent_prop.name not in child_props:
props.append(parent_prop)
if "parent" in parent:
self._traverse_parents(leaf, parent, pos_constr, named_constr, props, abstract_objects)
else:
# Now we know we can create an object out of all the accumulated values.
# The object's class is its topmost parent's class.
class_ = parent["class"]
id, factory, lazy_init, abstract, parent, scope_ = self._get_basic_object_data(leaf, class_)
c = self._create_object(id, factory, lazy_init, abstract, parent,
scope_, pos_constr, named_constr, props)
self.objects.append(c)
return parent
def _get_pos_constr(self, object):
""" Returns a list of all positional constructor arguments of an object.
"""
if "constructor-args" in object and isinstance(object["constructor-args"], list):
return [self._convert_prop_def(object, constr, object["object"]) for constr in object["constructor-args"]]
return []
def _get_named_constr(self, object):
""" Returns a dictionary of all named constructor arguments of an object.
"""
if "constructor-args" in object and isinstance(object["constructor-args"], dict):
return dict([(name, self._convert_prop_def(object, constr, object["object"]))
for (name, constr) in object["constructor-args"].items()])
return {}
def _get_props(self, object):
""" Returns a list of all properties defined by an object.
"""
if "properties" in object:
return [self._convert_prop_def(object, p, name) for (name, p) in object["properties"].items()]
return []
def _create_object(self, id, factory, lazy_init, abstract, parent,
scope, pos_constr, named_constr, props):
""" A helper function which creates an object out of the supplied
arguments.
"""
c = ObjectDef(id=id, factory=factory, lazy_init=lazy_init,
abstract=abstract, parent=parent)
c.scope = scope
c.pos_constr = pos_constr
c.named_constr = named_constr
c.props = props
self.logger.debug("object: props = %s" % c.props)
self.logger.debug("object: There are %s props" % len(c.props))
return c
def _get_basic_object_data(self, object, class_):
""" A convenience method which creates basic object's data so that
the code is not repeated.
"""
if "scope" in object:
scope_ = scope.convert(object["scope"])
else:
scope_ = scope.SINGLETON
return(object["object"], ReflectiveObjectFactory(class_),
object.get("lazy-init", False), object.get("abstract", False),
object.get("parent"), scope_)
def _convert_object(self, object, prefix=""):
"This function generates a object definition, then converts scope and property elements."
if prefix != "":
if "object" in object and object["object"] is not None:
object["object"] = prefix + "." + object["object"]
else:
object["object"] = prefix + "."
id, factory, lazy_init, abstract, parent, scope_ = self._get_basic_object_data(object, object.get("class"))
pos_constr = self._get_pos_constr(object)
named_constr = self._get_named_constr(object)
props = self._get_props(object)
return self._create_object(id, factory, lazy_init, abstract, parent,
scope_, pos_constr, named_constr, props)
def _print_obj(self, obj, level=0):
self.logger.debug("%sobject = %s" % ("\t"*level, obj["object"]))
self.logger.debug("%sobject id = %s" % ("\t"*level, obj["object"]))
self.logger.debug("%sclass = %s" % ("\t"*(level+1), obj["class"]))
if "scope" in obj:
self.logger.debug("%sscope = %s" % ("\t"*(level+1), obj["scope"]))
else:
self.logger.debug("%sscope = singleton (default)" % ("\t"*(level+1)))
if "properties" in obj:
self.logger.debug("%sproperties:" % ("\t"*(level+1)))
for prop in obj["properties"].keys():
if "object" in obj["properties"][prop]:
self.logger.debug("%s%s = ..." % ("\t"*(level+2), prop))
self._print_obj(obj["properties"][prop], level+3)
else:
self.logger.debug("%s%s = %s" % ("\t"*(level+2), prop, obj["properties"][prop]))
self.logger.debug("")
def _convert_ref(self, ref_node, name):
self.logger.debug("ref: Parsing %s, %s" % (ref_node, name))
if "object" in ref_node:
return ReferenceDef(name, ref_node["object"])
else:
return ReferenceDef(name, ref_node)
def _convert_value(self, value, id, name):
results = []
if isinstance(value, dict):
if "tuple" in value:
self.logger.debug("value: Converting tuple")
return self._convert_tuple(value["tuple"], id, name)
elif "list" in value:
self.logger.debug("value: Converting list")
return self._convert_list(value["list"], id, name)
elif "dict" in value:
self.logger.debug("value: Converting dict")
return self._convert_dict(value["dict"], id, name)
elif "set" in value:
self.logger.debug("value: Converting set")
return self._convert_set(value["set"], id, name)
elif "frozenset" in value:
self.logger.debug("value: Converting frozenset")
return self._convert_frozen_set(value["frozenset"], id, name)
else:
self.logger.debug("value: Plain ole value = %s" % value)
return value
return results
def _convert_dict(self, dict_node, id, name):
d = {}
for (k, v) in dict_node.items():
if isinstance(v, dict):
self.logger.debug("dict: You have a special type stored at %s" % k)
if "ref" in v:
self.logger.debug("dict/ref: k,v = %s,%s" % (k, v))
d[k] = self._convert_ref(v["ref"], "%s.dict['%s']" % (name, k))
self.logger.debug("dict: Stored %s => %s" % (k, d[k]))
elif "tuple" in v:
self.logger.debug("dict: Converting a tuple...")
d[k] = self._convert_tuple(v["tuple"], id, "%s.dict['%s']" % (name, k))
else:
self.logger.debug("dict: Don't know how to handle type %s" % v)
else:
self.logger.debug("dict: %s is NOT a dict, so going to convert as a value." % v)
d[k] = self._convert_value(v, id, "%s.dict['%s']" % (name, k))
return DictDef(name, d)
def _convert_props(self, props_node, name):
dict = {}
for prop in props_node.prop:
dict[prop.key] = str(prop)
return DictDef(name, dict)
def _convert_list(self, list_node, id, name):
list = []
for item in list_node:
self.logger.debug("list: Adding %s to list..." % item)
if isinstance(item, dict):
if "ref" in item:
list.append(self._convert_ref(item["ref"], "%s.list[%s]" % (name, len(list))))
elif "object" in item:
list.append(self._convert_inner_object(item, id, "%s.list[%s]" % (name, len(list))))
elif len(set(["dict", "tuple", "set", "frozenset", "list"]) & set(item)) > 0:
list.append(self._convert_value(item, id, "%s.list[%s]" % (name, len(list))))
else:
self.logger.debug("list: Don't know how to handle %s" % item.keys())
else:
list.append(item)
return ListDef(name, list)
def _convert_tuple(self, tuple_node, id, name):
list = []
self.logger.debug("tuple: tuple_node = %s, id = %s, name = %s" % (tuple_node, id, name))
for item in tuple_node:
if isinstance(item, dict):
if "ref" in item:
list.append(self._convert_ref(item["ref"], name + ".tuple"))
elif "object" in item:
list.append(self._convert_inner_object(item, id, "%s.tuple[%s]" % (name, len(list))))
elif len(set(["dict", "tuple", "set", "frozenset", "list"]) & set(item)) > 0:
list.append(self._convert_value(item, id, "%s.tuple[%s]" % (name, len(list))))
else:
self.logger.debug("tuple: Don't know how to handle %s" % item)
else:
list.append(item)
return TupleDef(name, tuple(list))
def _convert_set(self, set_node, id, name):
s = set()
self.logger.debug("set: set_node = %s, id = %s, name = %s" % (set_node, id, name))
for item in set_node:
if isinstance(item, dict):
if "ref" in item:
s.add(self._convert_ref(item["ref"], name + ".set"))
elif "object" in item:
s.add(self._convert_inner_object(item, id, "%s.set[%s]" % (name, len(s))))
elif len(set(["dict", "tuple", "set", "frozenset", "list"]) & set(item)) > 0:
s.add(self._convert_value(item, id, "%s.set[%s]" % (name, len(s))))
else:
self.logger.debug("set: Don't know how to handle %s" % item)
else:
s.add(item)
return SetDef(name, s)
def _convert_frozen_set(self, frozen_set_node, id, name):
item = self._convert_set(frozen_set_node, id, name)
self.logger.debug("frozenset: Just got back converted set %s" % item)
self.logger.debug("frozenset: value is %s, which will be turned into %s" % (item.value, frozenset(item.value)))
return FrozenSetDef(name, frozenset(item.value))
def _convert_inner_object(self, object_node, id, name):
self.logger.debug("inner object: Converting %s" % object_node)
inner_object_def = self._convert_object(object_node, prefix="%s.%s" % (id, name))
self.objects.append(inner_object_def)
return InnerObjectDef(name, inner_object_def)
def _convert_prop_def(self, comp, p, name):
"This function translates object properties into useful collections of information for the container."
self.logger.debug("prop_def: Trying to read property %s -> %s" % (name, p))
if isinstance(p, dict):
if "ref" in p:
self.logger.debug("prop_def: >>>>>>>>>>>>Call _convert_ref(%s, %s)" % (p["ref"], name))
return self._convert_ref(p["ref"], name)
elif "tuple" in p:
self.logger.debug("prop_def: Call _convert_tuple(%s,%s,%s)" % (p["tuple"], comp["object"], name))
return self._convert_tuple(p["tuple"], comp["object"], name)
elif "set" in p:
self.logger.debug("prop_def: Call _convert_set(%s,%s,%s)" % (p["set"], comp["object"], name))
return self._convert_set(p["set"], comp["object"], name)
elif "frozenset" in p:
self.logger.debug("prop_def: Call _convert_frozen_set(%s,%s,%s)" % (p["frozenset"], comp["object"], name))
return self._convert_frozen_set(p["frozenset"], comp["object"], name)
elif "object" in p:
self.logger.debug("prop_def: Call _convert_inner_object(%s,%s,%s)" % (p, comp["object"], name))
return self._convert_inner_object(p, comp["object"], name)
else:
#self.logger.debug("prop_def: Don't know how to handle %s" % p)
return self._convert_dict(p, comp["object"], name)
elif isinstance(p, list):
return self._convert_list(p, comp["object"], name)
elif isinstance(p, unicode):
return ValueDef(name, unicode(p))
else:
return ValueDef(name, str(p))
return None
if hasattr(p, "ref"):
return self._convert_ref(p.ref, name)
elif hasattr(p, "value"):
return ValueDef(name, str(p.value))
elif hasattr(p, "dict"):
return self._convert_dict(p.dict, comp.id, name)
elif hasattr(p, "props"):
return self._convert_props(p.props, name)
elif hasattr(p, "list"):
return self._convert_list(p.list, comp.id, name)
elif hasattr(p, "tuple"):
return self._convert_tuple(p.tuple, comp.id, name)
elif hasattr(p, "set"):
return self._convert_set(p.set, comp.id, name)
elif hasattr(p, "frozenset"):
self.logger.debug("Converting frozenset")
return self._convert_frozen_set(p.frozenset, comp.id, name)
elif hasattr(p, "object"):
return self._convert_inner_object(p.object, comp.id, name)
springpython-1.2.0+ds/springpython/config/_xml_config.py 0000644 0000000 0000000 00000071366 11464332043 022242 0 ustar root root """
Copyright 2006-2008 SpringSource (http://springsource.com), All Rights Reserved
Licensed 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.
"""
try:
import cElementTree as etree
except ImportError:
try:
import xml.etree.ElementTree as etree
except ImportError:
from elementtree import ElementTree as etree
import re
import types
import inspect
import logging
from _config_base import *
from springpython.context import scope
from springpython.context import ApplicationContextAware
from springpython.factory import PythonObjectFactory
from springpython.factory import ReflectiveObjectFactory
from springpython.container import InvalidObjectScope
xml_mappings = {
"str":"types.StringType", "unicode":"types.UnicodeType",
"int":"types.IntType", "long":"types.LongType",
"float":"types.FloatType", "decimal":"decimal.Decimal",
"bool":"types.BooleanType", "complex":"types.ComplexType",
}
class PyContainerConfig(Config):
"""
PyContainerConfig supports the legacy XML dialect (PyContainer) of reading object definitions.
"""
NS = "{http://www.springframework.org/springpython/schema/pycontainer-components}"
def __init__(self, config_location):
if isinstance(config_location, list):
self.config_location = config_location
else:
self.config_location = [config_location]
self.logger = logging.getLogger("springpython.config.PyContainerConfig")
def read_object_defs(self):
self.logger.debug("==============================================================")
objects = []
for config in self.config_location:
self.logger.debug("* Parsing %s" % config)
components = etree.parse(config).getroot()
objects.extend([self._convert_component(component) for component in components])
self.logger.debug("==============================================================")
return objects
def _convert_component(self, component):
"This function generates a object definition, then converts scope and property elements."
self.logger.debug("component: Processing %s" % component)
c = ObjectDef(component.get("id"), factory=ReflectiveObjectFactory(component.get("class")))
if "scope" in component.attrib:
c.scope = scope.convert(component.get("scope"))
c.props = [self._convert_prop_def(p) for p in component.findall(self.NS+"property")]
return c
def _convert_prop_def(self, p):
"This function translates object properties into useful dictionaries of information for the container."
if "local" in p.attrib or p.find(self.NS+"local") is not None:
if "local" in p.attrib:
return ReferenceDef(p.get("name"), p.get("local"))
else:
return ReferenceDef(p.get("name"), p.find(self.NS+"local"))
elif "list" in p.attrib or p.find(self.NS+"list") is not None:
if "list" in p.attrib:
return ListDef(p.name, [ReferenceDef(p.name + ".list", prop_list.local) for prop_list in p.list])
else:
return ListDef(p.name, [ReferenceDef(p.name + ".list", prop_list.local) for prop_list in p.list])
else:
self.logger.debug("py: name = %s code = %s" % (p.get("name"), p.text))
thing = eval(str(p.text).strip())
self.logger.debug("py: You have parsed %s" % thing)
return ValueDef(p.get("name"), eval(str(p.text).strip()))
class SpringJavaConfig(Config):
"""
SpringJavaConfig supports current Spring Java format of XML bean definitions.
"""
NS = "{http://www.springframework.org/schema/beans}"
def __init__(self, config_location):
if isinstance(config_location, list):
self.config_location = config_location
else:
self.config_location = [config_location]
self.logger = logging.getLogger("springpython.config.SpringJavaConfig")
# By making this an instance-based property (instead of function local), inner object
# definitions can add themselves to the list in the midst of parsing an input.
self.objects = []
def read_object_defs(self):
self.logger.debug("==============================================================")
# Reset, in case the file is re-read
self.objects = []
for config in self.config_location:
self.logger.debug("* Parsing %s" % config)
beans = etree.parse(config).getroot()
self.objects.extend([self._convert_bean(bean) for bean in beans])
self.logger.debug("==============================================================")
return self.objects
def _convert_bean(self, bean, prefix=""):
"This function generates a object definition, then converts scope and property elements."
if prefix != "":
if "id" in bean.attrib:
bean.set("id", prefix + bean.get("id"))
else:
bean.set("id", prefix + "")
c = ObjectDef(bean.get("id"), factory=ReflectiveObjectFactory(bean.get("class")))
if "scope" in bean.attrib:
c.scope = scope.convert(bean.get("scope"))
self.logger.debug("bean: %s" % bean)
c.pos_constr = [self._convert_prop_def(bean, constr, bean.get("id") + ".constr") for constr in bean.findall(self.NS+"constructor-arg")]
self.logger.debug("Constructors = %s" % c.pos_constr)
c.props = [self._convert_prop_def(bean, p, p.get("name")) for p in bean.findall(self.NS+"property")]
return c
def _convert_prop_def(self, bean, p, name):
"This function translates object constructors/properties into useful collections of information for the container."
if "ref" in p.keys() or p.find(self.NS+"ref") is not None:
if "ref" in p.keys():
return ReferenceDef(name, p.get("ref"))
else:
return ReferenceDef(name, p.find(self.NS+"ref").get("bean"))
elif "value" in p.keys() or p.find(self.NS+"value") is not None:
if "value" in p.keys():
return ValueDef(name, p.get("value"))
else:
return ValueDef(name, p.find(self.NS+"value").text)
elif p.find(self.NS+"map") is not None:
dict = {}
for entry in p.find(self.NS+"map"):
key = entry.find(self.NS+"key").find(self.NS+"value").text
if entry.find(self.NS+"value") is not None:
dict[key] = str(entry.find(self.NS+"value").text)
elif entry.find(self.NS+"ref") is not None:
dict[key] = ReferenceDef(key, entry.find(self.NS+"ref").get("bean"))
else:
self.logger.debug("Don't know how to handle %s" % entry)
return DictDef(name, dict)
elif p.find(self.NS+"props") is not None:
dict = {}
for prop in p.find(self.NS+"props"):
dict[prop.get("key")] = str(prop.text)
return DictDef(name, dict)
elif p.find(self.NS+"list") is not None:
list = []
for element in p.find(self.NS+"list"):
if element.tag == self.NS+"value":
list.append(element.text)
elif element.tag == self.NS+"ref":
list.append(ReferenceDef(name + ".list", element.get("bean")))
else:
self.logger.debug("Don't know how to handle %s" % element.tag)
return ListDef(name, list)
elif p.find(self.NS+"set") is not None:
s = set()
for element in p.find(self.NS+"set"):
if element.tag == self.NS+"value":
s.add(element.text)
elif element.tag == self.NS+"ref":
s.add(ReferenceDef(name + ".set", element.get("bean")))
else:
self.logger.debug("Don't know how to handle %s" % element.tag)
return SetDef(name, s)
elif p.find(self.NS+"bean"):
inner_object_def = self._convert_bean(p.find(self.NS+"bean"), prefix=bean.get("id") + "." + name + ".")
self.objects.append(inner_object_def)
return InnerObjectDef(name, inner_object_def)
class XMLConfig(Config):
"""
XMLConfig supports current Spring Python format of XML object definitions.
"""
NS = "{http://www.springframework.org/springpython/schema/objects}"
NS_11 = "{http://www.springframework.org/springpython/schema/objects/1.1}"
def __init__(self, config_location):
if isinstance(config_location, list):
self.config_location = config_location
else:
self.config_location = [config_location]
self.logger = logging.getLogger("springpython.config.XMLConfig")
# By making this an instance-based property (instead of function local), inner object
# definitions can add themselves to the list in the midst of parsing an input.
self.objects = []
def read_object_defs(self):
self.logger.debug("==============================================================")
# Reset, in case the file is re-read
self.objects = []
for config in self.config_location:
self.logger.debug("* Parsing %s" % config)
# A flat list of objects, as found in the XML document.
objects = etree.parse(config).getroot()
# We need to handle both 1.0 and 1.1 XSD schemata *and* we may be
# passed a list of config locations of different XSD versions so we
# must find out here which one is used in the current config file
# and pass the correct namespace down to other parts of XMLConfig.
ns = objects.tag[:objects.tag.find("}") + 1]
# A dictionary of abstract objects, keyed by their IDs, used in
# traversing the hierarchies of parents; built upfront here for
# convenience.
abstract_objects = {}
for obj in objects:
if obj.get("abstract"):
abstract_objects[obj.get("id")] = obj
for obj in objects:
if obj.get("class") is None and not obj.get("parent"):
self._map_custom_class(obj, xml_mappings, ns)
elif obj.get("parent"):
# Children are added to self.objects during the children->abstract parents traversal.
pos_constr = self._get_pos_constr(obj, ns)
named_constr = self._get_named_constr(obj, ns)
props = self._get_props(obj, ns)
self._traverse_parents(obj, obj, ns, pos_constr, named_constr, props, abstract_objects)
continue
self.objects.append(self._convert_object(obj, ns=ns))
self.logger.debug("==============================================================")
for object in self.objects:
self.logger.debug("Parsed %s" % object)
return self.objects
def _map_custom_class(self, obj, mappings, ns):
""" Fill in the missing attributes of Python objects and make it look
to the rest of XMLConfig as if they already were in the XML config file.
"""
for class_name in mappings:
tag_no_ns = obj.tag.replace(ns, "")
if class_name == tag_no_ns:
obj.set("class", mappings[class_name])
constructor_arg = etree.Element("%s%s" % (ns, "constructor-arg"))
value = etree.Element("%s%s" % (ns, "value"))
value.text = obj.text
obj.append(constructor_arg)
constructor_arg.append(value)
obj.text = ""
break
else:
self.logger.warning("No matching type found for object %s" % obj)
def _traverse_parents(self, leaf, child, ns, pos_constr,
named_constr, props, abstract_objects):
parent = abstract_objects[child.get("parent")]
# At this point we only build up the lists of parameters but we don't create
# the object yet because the current parent object may still have its
# own parent.
# Positional constructors
parent_pos_constrs = self._get_pos_constr(parent, ns)
# Make sure there are as many child positional parameters as there
# are in the parent's list.
len_pos_constr = len(pos_constr)
len_parent_pos_constrs = len(parent_pos_constrs)
if len_pos_constr < len_parent_pos_constrs:
pos_constr.extend([None] * (len_parent_pos_constrs - len_pos_constr))
for idx, parent_pos_constr in enumerate(parent_pos_constrs):
if not pos_constr[idx]:
pos_constr[idx] = parent_pos_constr
# Named constructors
child_named_constrs = named_constr
parent_named_constrs = self._get_named_constr(parent, ns)
for parent_named_constr in parent_named_constrs:
if parent_named_constr not in child_named_constrs:
named_constr[parent_named_constr] = parent_named_constrs[parent_named_constr]
# Properties
child_props = [prop.name for prop in props]
parent_props = self._get_props(parent, ns)
for parent_prop in parent_props:
if parent_prop.name not in child_props:
props.append(parent_prop)
if parent.get("parent"):
self._traverse_parents(leaf, parent, ns, pos_constr, named_constr, props, abstract_objects)
else:
# Now we know we can create an object out of all the accumulated values.
# The object's class is its topmost parent's class.
class_ = parent.get("class")
id, factory, lazy_init, abstract, parent, scope_ = self._get_basic_object_data(leaf, class_)
c = self._create_object(id, factory, lazy_init, abstract, parent,
scope_, pos_constr, named_constr, props)
self.objects.append(c)
return parent
def _get_pos_constr(self, object, ns):
""" Returns a list of all positional constructor arguments of an object.
"""
return [self._convert_prop_def(object, constr, object.get("id") + ".constr", ns) for constr in object.findall(ns+"constructor-arg")
if not "name" in constr.attrib]
def _get_named_constr(self, object, ns):
""" Returns a dictionary of all named constructor arguments of an object.
"""
return dict([(str(constr.get("name")), self._convert_prop_def(object, constr, object.get("id") + ".constr", ns))
for constr in object.findall(ns+"constructor-arg") if "name" in constr.attrib])
def _get_props(self, object, ns):
""" Returns a list of all properties defined by an object.
"""
return [self._convert_prop_def(object, p, p.get("name"), ns) for p in object.findall(ns+"property")]
def _create_object(self, id, factory, lazy_init, abstract, parent,
scope, pos_constr, named_constr, props):
""" A helper function which creates an object out of the supplied
arguments.
"""
c = ObjectDef(id=id, factory=factory, lazy_init=lazy_init,
abstract=abstract, parent=parent)
c.scope = scope
c.pos_constr = pos_constr
c.named_constr = named_constr
c.props = props
self.logger.debug("object: props = %s" % c.props)
self.logger.debug("object: There are %s props" % len(c.props))
return c
def _get_basic_object_data(self, object, class_):
""" A convenience method which creates basic object's data so that
the code is not repeated.
"""
if "scope" in object.attrib:
scope_ = scope.convert(object.get("scope"))
else:
scope_ = scope.SINGLETON
return(object.get("id"), ReflectiveObjectFactory(class_),
object.get("lazy-init", False), object.get("abstract", False),
object.get("parent"), scope_)
def _convert_object(self, object, prefix="", ns=None):
""" This function collects all parameters required for an object creation
and then calls a helper function which creates it.
"""
if prefix != "":
if "id" in object.attrib:
object.set("id", prefix + "." + object.get("id"))
else:
object.set("id", prefix + ".")
id, factory, lazy_init, abstract, parent, scope_ = self._get_basic_object_data(object, object.get("class"))
pos_constr = self._get_pos_constr(object, ns)
named_constr = self._get_named_constr(object, ns)
props = self._get_props(object, ns)
return self._create_object(id, factory, lazy_init, abstract, parent,
scope_, pos_constr, named_constr, props)
def _convert_ref(self, ref_node, name):
if hasattr(ref_node, "attrib"):
results = ReferenceDef(name, ref_node.get("object"))
self.logger.debug("ref: Returning %s" % results)
return results
else:
results = ReferenceDef(name, ref_node)
self.logger.debug("ref: Returning %s" % results)
return results
def _convert_value(self, value, id, name, ns):
if value.text is not None and value.text.strip() != "":
self.logger.debug("value: Converting a direct value <%s>" % value.text)
return value.text
else:
if value.tag == ns+"value":
self.logger.debug("value: Converting a value's children %s" % value.getchildren()[0])
results = self._convert_value(value.getchildren()[0], id, name, ns)
self.logger.debug("value: results = %s" % str(results))
return results
elif value.tag == ns+"tuple":
self.logger.debug("value: Converting a tuple")
return self._convert_tuple(value, id, name, ns).value
elif value.tag == ns+"list":
self.logger.debug("value: Converting a list")
return self._convert_list(value, id, name, ns).value
elif value.tag == ns+"dict":
self.logger.debug("value: Converting a dict")
return self._convert_dict(value, id, name, ns).value
elif value.tag == ns+"set":
self.logger.debug("value: Converting a set")
return self._convert_set(value, id, name, ns).value
elif value.tag == ns+"frozenset":
self.logger.debug("value: Converting a frozenset")
return self._convert_frozen_set(value, id, name, ns).value
else:
self.logger.debug("value: %s.%s Don't know how to handle %s" % (id, name, value.tag))
def _convert_dict(self, dict_node, id, name, ns):
dict = {}
for entry in dict_node.findall(ns+"entry"):
self.logger.debug("dict: entry = %s" % entry)
key = entry.find(ns+"key").find(ns+"value").text
self.logger.debug("dict: key = %s" % key)
if entry.find(ns+"value") is not None:
dict[key] = self._convert_value(entry.find(ns+"value"), id, "%s.dict['%s']" % (name, key), ns)
elif entry.find(ns+"ref") is not None:
dict[key] = self._convert_ref(entry.find(ns+"ref"), "%s.dict['%s']" % (name, key))
elif entry.find(ns+"object") is not None:
self.logger.debug("dict: Parsing an inner object definition...")
dict[key] = self._convert_inner_object(entry.find(ns+"object"), id, "%s.dict['%s']" % (name, key), ns)
else:
for token in ["dict", "tuple", "set", "frozenset", "list"]:
if entry.find(ns+token) is not None:
dict[key] = self._convert_value(entry.find(ns+token), id, "%s.dict['%s']" % (name, key), ns)
break
if key not in dict:
self.logger.debug("dict: Don't know how to handle %s" % entry.tag)
self.logger.debug("Dictionary is now %s" % dict)
return DictDef(name, dict)
def _convert_props(self, props_node, name, ns):
dict = {}
self.logger.debug("props: Looking at %s" % props_node)
for prop in props_node:
dict[prop.get("key")] = str(prop.text)
self.logger.debug("props: Dictionary is now %s" % dict)
return DictDef(name, dict)
def _convert_list(self, list_node, id, name, ns):
list = []
self.logger.debug("list: Parsing %s" % list_node)
for element in list_node:
if element.tag == ns+"value":
list.append(get_string(element.text))
elif element.tag == ns+"ref":
list.append(self._convert_ref(element, "%s.list[%s]" % (name, len(list))))
elif element.tag == ns+"object":
self.logger.debug("list: Parsing an inner object definition...")
list.append(self._convert_inner_object(element, id, "%s.list[%s]" % (name, len(list)), ns))
elif element.tag in [ns+token for token in ["dict", "tuple", "set", "frozenset", "list"]]:
self.logger.debug("This list has child elements of type %s." % element.tag)
list.append(self._convert_value(element, id, "%s.list[%s]" % (name, len(list)), ns))
self.logger.debug("List is now %s" % list)
else:
self.logger.debug("list: Don't know how to handle %s" % element.tag)
self.logger.debug("List is now %s" % list)
return ListDef(name, list)
def _convert_tuple(self, tuple_node, id, name, ns):
list = []
self.logger.debug("tuple: Parsing %s" % tuple_node)
for element in tuple_node:
self.logger.debug("tuple: Looking at %s" % element)
if element.tag == ns+"value":
self.logger.debug("tuple: Appending %s" % element.text)
list.append(get_string(element.text))
elif element.tag == ns+"ref":
list.append(self._convert_ref(element, "%s.tuple(%s}" % (name, len(list))))
elif element.tag == ns+"object":
self.logger.debug("tuple: Parsing an inner object definition...")
list.append(self._convert_inner_object(element, id, "%s.tuple(%s)" % (name, len(list)), ns))
elif element.tag in [ns+token for token in ["dict", "tuple", "set", "frozenset", "list"]]:
self.logger.debug("tuple: This tuple has child elements of type %s." % element.tag)
list.append(self._convert_value(element, id, "%s.tuple(%s)" % (name, len(list)), ns))
self.logger.debug("tuple: List is now %s" % list)
else:
self.logger.debug("tuple: Don't know how to handle %s" % element.tag)
self.logger.debug("Tuple is now %s" % str(tuple(list)))
return TupleDef(name, tuple(list))
def _convert_set(self, set_node, id, name, ns):
s = set()
self.logger.debug("set: Parsing %s" % set_node)
for element in set_node:
self.logger.debug("Looking at element %s" % element)
if element.tag == ns+"value":
s.add(get_string(element.text))
elif element.tag == ns+"ref":
s.add(self._convert_ref(element, name + ".set"))
elif element.tag == ns+"object":
self.logger.debug("set: Parsing an inner object definition...")
s.add(self._convert_inner_object(element, id, "%s.set(%s)" % (name, len(s)), ns))
elif element.tag in [ns+token for token in ["dict", "tuple", "set", "frozenset", "list"]]:
self.logger.debug("set: This set has child elements of type %s." % element.tag)
s.add(self._convert_value(element, id, "%s.set(%s)" % (name,len(s)), ns))
else:
self.logger.debug("set: Don't know how to handle %s" % element.tag)
self.logger.debug("Set is now %s" % s)
return SetDef(name, s)
def _convert_frozen_set(self, frozen_set_node, id, name, ns):
item = self._convert_set(frozen_set_node, id, name, ns)
self.logger.debug("frozenset: Frozen set is now %s" % frozenset(item.value))
return FrozenSetDef(name, frozenset(item.value))
def _convert_inner_object(self, object_node, id, name, ns):
inner_object_def = self._convert_object(object_node, prefix="%s.%s" % (id, name), ns=ns)
self.logger.debug("innerobj: Innerobject is now %s" % inner_object_def)
self.objects.append(inner_object_def)
return InnerObjectDef(name, inner_object_def)
def _convert_prop_def(self, comp, p, name, ns):
"This function translates object properties into useful collections of information for the container."
#self.logger.debug("Is %s.%s a ref? %s" % (comp.get("id"), p.get("name"), p.find(ns+"ref") is not None or "ref" in p.attrib))
#self.logger.debug("Is %s.%s a value? %s" % (comp.get("id"), p.get("name"), p.find(ns+"value") is not None or "value" in p.attrib))
#self.logger.debug("Is %s.%s an inner object? %s" % (comp.get("id"), p.get("name"), p.find(ns+"object") is not None or "object" in p.attrib))
#self.logger.debug("Is %s.%s a dict? %s" % (comp.get("id"), p.get("name"), p.find(ns+"dict") is not None or "dict" in p.attrib))
#self.logger.debug("Is %s.%s a list? %s" % (comp.get("id"), p.get("name"), p.find(ns+"list") is not None or "list" in p.attrib))
#self.logger.debug("Is %s.%s a tuple? %s" % (comp.get("id"), p.get("name"), p.find(ns+"tuple") is not None or "tuple" in p.attrib))
#self.logger.debug("Is %s.%s a set? %s" % (comp.get("id"), p.get("name"), p.find(ns+"set") is not None or "set" in p.attrib))
#self.logger.debug("Is %s.%s a frozenset? %s" % (comp.get("id"), p.get("name"), p.find(ns+"frozenset") is not None or "frozenset" in p.attrib))
#self.logger.debug("")
if "ref" in p.attrib or p.find(ns+"ref") is not None:
if "ref" in p.attrib:
return self._convert_ref(p.get("ref"), name)
else:
return self._convert_ref(p.find(ns+"ref"), name)
elif "value" in p.attrib or p.find(ns+"value") is not None:
if "value" in p.attrib:
return ValueDef(name, get_string(p.get("value")))
else:
return ValueDef(name, get_string(p.find(ns+"value").text))
elif "dict" in p.attrib or p.find(ns+"dict") is not None:
if "dict" in p.attrib:
return self._convert_dict(p.get("dict"), comp.get("id"), name, ns)
else:
return self._convert_dict(p.find(ns+"dict"), comp.get("id"), name, ns)
elif "props" in p.attrib or p.find(ns+"props") is not None:
if "props" in p.attrib:
return self._convert_props(p.get("props"), name, ns)
else:
return self._convert_props(p.find(ns+"props"), name, ns)
elif "list" in p.attrib or p.find(ns+"list") is not None:
if "list" in p.attrib:
return self._convert_list(p.get("list"), comp.get("id"), name, ns)
else:
return self._convert_list(p.find(ns+"list"), comp.get("id"), name, ns)
elif "tuple" in p.attrib or p.find(ns+"tuple") is not None:
if "tuple" in p.attrib:
return self._convert_tuple(p.get("tuple"), comp.get("id"), name, ns)
else:
return self._convert_tuple(p.find(ns+"tuple"), comp.get("id"), name, ns)
elif "set" in p.attrib or p.find(ns+"set") is not None:
if "set" in p.attrib:
return self._convert_set(p.get("set"), comp.get("id"), name, ns)
else:
return self._convert_set(p.find(ns+"set"), comp.get("id"), name, ns)
elif "frozenset" in p.attrib or p.find(ns+"frozenset") is not None:
if "frozenset" in p.attrib:
return self._convert_frozen_set(p.get("frozenset"), comp.get("id"), name, ns)
else:
return self._convert_frozen_set(p.find(ns+"frozenset"), comp.get("id"), name, ns)
elif "object" in p.attrib or p.find(ns+"object") is not None:
if "object" in p.attrib:
return self._convert_inner_object(p.get("object"), comp.get("id"), name, ns)
else:
return self._convert_inner_object(p.find(ns+"object"), comp.get("id"), name, ns)
springpython-1.2.0+ds/springpython/config/decorator.py 0000644 0000000 0000000 00000023240 11412453030 021715 0 ustar root root ########################## LICENCE ###############################
##
## Copyright (c) 2005, Michele Simionato
## All rights reserved.
##
## Redistributions of source code must retain the above copyright
## notice, this list of conditions and the following disclaimer.
## Redistributions in bytecode form must reproduce the above copyright
## notice, this list of conditions and the following disclaimer in
## the documentation and/or other materials provided with the
## distribution.
## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
## HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
## INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
## BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
## OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
## ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
## TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
## USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
## DAMAGE.
"""
Decorator module, see http://pypi.python.org/pypi/decorator
for the documentation.
"""
__all__ = ["decorator", "FunctionMaker", "partial",
"deprecated", "getinfo", "new_wrapper"]
import os, sys, re, inspect, warnings
try:
from functools import partial
except ImportError: # for Python version < 2.5
class partial(object):
"A simple replacement of functools.partial"
def __init__(self, func, *args, **kw):
self.func = func
self.args = args
self.keywords = kw
def __call__(self, *otherargs, **otherkw):
kw = self.keywords.copy()
kw.update(otherkw)
return self.func(*(self.args + otherargs), **kw)
DEF = re.compile('\s*def\s*([_\w][_\w\d]*)\s*\(')
# basic functionality
class FunctionMaker(object):
"""
An object with the ability to create functions with a given signature.
It has attributes name, doc, module, signature, defaults, dict and
methods update and make.
"""
def __init__(self, func=None, name=None, signature=None,
defaults=None, doc=None, module=None, funcdict=None):
if func:
# func can also be a class or a callable, but not an instance method
self.name = func.__name__
if self.name == '': # small hack for lambda functions
self.name = '_lambda_'
self.doc = func.__doc__
self.module = func.__module__
if inspect.isfunction(func):
self.signature = inspect.formatargspec(
formatvalue=lambda val: "", *inspect.getargspec(func))[1:-1]
self.defaults = func.func_defaults
self.dict = func.__dict__.copy()
if name:
self.name = name
if signature is not None:
self.signature = signature
if defaults:
self.defaults = defaults
if doc:
self.doc = doc
if module:
self.module = module
if funcdict:
self.dict = funcdict
# check existence required attributes
assert hasattr(self, 'name')
if not hasattr(self, 'signature'):
raise TypeError('You are decorating a non function: %s' % func)
def update(self, func, **kw):
"Update the signature of func with the data in self"
func.__name__ = self.name
func.__doc__ = getattr(self, 'doc', None)
func.__dict__ = getattr(self, 'dict', {})
func.func_defaults = getattr(self, 'defaults', ())
callermodule = sys._getframe(3).f_globals.get('__name__', '?')
func.__module__ = getattr(self, 'module', callermodule)
func.__dict__.update(kw)
def make(self, src_templ, evaldict=None, addsource=False, **attrs):
"Make a new function from a given template and update the signature"
src = src_templ % vars(self) # expand name and signature
evaldict = evaldict or {}
mo = DEF.match(src)
if mo is None:
raise SyntaxError('not a valid function template\n%s' % src)
name = mo.group(1) # extract the function name
reserved_names = set([name] + [
arg.strip(' *') for arg in self.signature.split(',')])
for n, v in evaldict.iteritems():
if n in reserved_names:
raise NameError('%s is overridden in\n%s' % (n, src))
if not src.endswith('\n'): # add a newline just for safety
src += '\n'
try:
code = compile(src, '', 'single')
exec code in evaldict
except:
print >> sys.stderr, 'Error in generated code:'
print >> sys.stderr, src
raise
func = evaldict[name]
if addsource:
attrs['__source__'] = src
self.update(func, **attrs)
return func
@classmethod
def create(cls, obj, body, evaldict, defaults=None, addsource=True,**attrs):
"""
Create a function from the strings name, signature and body.
evaldict is the evaluation dictionary. If addsource is true an attribute
__source__ is added to the result. The attributes attrs are added,
if any.
"""
if isinstance(obj, str): # "name(signature)"
name, rest = obj.strip().split('(', 1)
signature = rest[:-1]
func = None
else: # a function
name = None
signature = None
func = obj
fun = cls(func, name, signature, defaults)
ibody = '\n'.join(' ' + line for line in body.splitlines())
return fun.make('def %(name)s(%(signature)s):\n' + ibody,
evaldict, addsource, **attrs)
def decorator(caller, func=None):
"""
decorator(caller) converts a caller function into a decorator;
decorator(caller, func) decorates a function using a caller.
"""
if func is not None: # returns a decorated function
return FunctionMaker.create(
func, "return _call_(_func_, %(signature)s)",
dict(_call_=caller, _func_=func), undecorated=func)
else: # returns a decorator
if isinstance(caller, partial):
return partial(decorator, caller)
# otherwise assume caller is a function
f = inspect.getargspec(caller)[0][0] # first arg
return FunctionMaker.create(
'%s(%s)' % (caller.__name__, f),
'return decorator(_call_, %s)' % f,
dict(_call_=caller, decorator=decorator), undecorated=caller)
###################### deprecated functionality #########################
@decorator
def deprecated(func, *args, **kw):
"A decorator for deprecated functions"
warnings.warn(
('Calling the deprecated function %r\n'
'Downgrade to decorator 2.3 if you want to use this functionality')
% func.__name__, DeprecationWarning, stacklevel=3)
return func(*args, **kw)
@deprecated
def getinfo(func):
"""
Returns an info dictionary containing:
- name (the name of the function : str)
- argnames (the names of the arguments : list)
- defaults (the values of the default arguments : tuple)
- signature (the signature : str)
- doc (the docstring : str)
- module (the module name : str)
- dict (the function __dict__ : str)
>>> def f(self, x=1, y=2, *args, **kw): pass
>>> info = getinfo(f)
>>> info["name"]
'f'
>>> info["argnames"]
['self', 'x', 'y', 'args', 'kw']
>>> info["defaults"]
(1, 2)
>>> info["signature"]
'self, x, y, *args, **kw'
"""
assert inspect.ismethod(func) or inspect.isfunction(func)
regargs, varargs, varkwargs, defaults = inspect.getargspec(func)
argnames = list(regargs)
if varargs:
argnames.append(varargs)
if varkwargs:
argnames.append(varkwargs)
signature = inspect.formatargspec(regargs, varargs, varkwargs, defaults,
formatvalue=lambda value: "")[1:-1]
return dict(name=func.__name__, argnames=argnames, signature=signature,
defaults = func.func_defaults, doc=func.__doc__,
module=func.__module__, dict=func.__dict__,
globals=func.func_globals, closure=func.func_closure)
@deprecated
def update_wrapper(wrapper, model, infodict=None):
"A replacement for functools.update_wrapper"
infodict = infodict or getinfo(model)
wrapper.__name__ = infodict['name']
wrapper.__doc__ = infodict['doc']
wrapper.__module__ = infodict['module']
wrapper.__dict__.update(infodict['dict'])
wrapper.func_defaults = infodict['defaults']
wrapper.undecorated = model
return wrapper
@deprecated
def new_wrapper(wrapper, model):
"""
An improvement over functools.update_wrapper. The wrapper is a generic
callable object. It works by generating a copy of the wrapper with the
right signature and by updating the copy, not the original.
Moreovoer, 'model' can be a dictionary with keys 'name', 'doc', 'module',
'dict', 'defaults'.
"""
if isinstance(model, dict):
infodict = model
else: # assume model is a function
infodict = getinfo(model)
assert not '_wrapper_' in infodict["argnames"], (
'"_wrapper_" is a reserved argument name!')
src = "lambda %(signature)s: _wrapper_(%(signature)s)" % infodict
funcopy = eval(src, dict(_wrapper_=wrapper))
return update_wrapper(funcopy, model, infodict)
springpython-1.2.0+ds/springpython/COPYRIGHT 0000644 0000000 0000000 00000020425 11364062063 017421 0 ustar root root Copyright 2006-2008 SpringSource (http://springsource.com), All Rights Reserved
Licensed 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.
*****************************************************************************************
Spring Python is inspired by the Spring framework (http://www.springframework.org)
which is released under the Apache Foundation License. Spring Python does NOT require
redistribution of Spring's software modules, nor any of its dependencies (binary or source code).
However, you are free to download their source code to understand the basis of this product.
The Spring Python's Security module is inspired by Acegi Security Java-based framework
(http://www.acegisecurity.org), which is released under the Apache Foundation License.
Spring Python's Security module does NOT require redistribution of Acegi's components,
nor any of its dependencies (binary or source code). However, you are free to download
their source code to understand the basis of this product.
*****************************************************************************************
Spring Python has incorporated the "decorator" library written by Michele Simionato
into springpython.context in order to implement a decorator based IoC container
solution.
See http://www.phyast.pitt.edu/~micheles/python/documentation.html for more information
about downloads of this library.
Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
Redistributions in bytecode form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
*****************************************************************************************
Spring Python includes software developed by Fourthought, Inc. (http://www.fourthought.com).
License and copyright info for 4Suite software License and copyright info for 4Suite
software Mike Olson Fourthought, Inc. Uche Ogbuji Fourthought, Inc. License and copyright
info for 4Suite software 1.1 2002-01-21 MO Initial version in post-0.11.1 codebase 1.4
2005-03-03 MB Converted source to Simplified DocBook XML 1.0 4Suite copyright license
4Suite software copyright The copyright on 4Suite as a whole is owned by Fourthought,
Inc. (USA). Copyright on the components of 4Suite is indicated in the source code; most
files have their own notice of copyright and ownership, and a CVS datestamp to clarify
the actual date of authorship or last revision/publication. For purposes of usage and
redistribution, the following Apache-based license applies.
The 4Suite License, Version 1.1
Copyright (c) 2000 Fourthought, Inc.. All rights reserved.
Redistribution and use in source
and binary forms, with or without modification, are permitted provided that the following
conditions are met: Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer. Redistributions in binary form must
reproduce the above copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the distribution. The end-user
documentation included with the redistribution, if any, must include the following
acknowledgment: "This product includes software developed by Fourthought, Inc.
(http://www.fourthought.com)." Alternately, this acknowledgment may appear in the software
itself, if and wherever such third-party acknowledgments normally appear. The names "4Suite",
"4Suite Server" and "Fourthought" must not be used to endorse or promote products derived from
this software without prior written permission. For written permission, please contact
info@fourthought.com. Products derived from this software may not be called "4Suite",
nor may "4Suite" appear in their name, without prior written permission of Fourthought,
Inc.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL FOURTHOGHT, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
====================================================================
This license is based on the Apache Software License, Version 1.1,
Copyright (c) 2000 The Apache Software Foundation. All rights reserved.
*****************************************************************************************
Spring Python includes software developed by Uche Ogbuji (http://uche.ogbuji.net).
Redistribution and use in source and binary forms, with or without modification, are permitted
provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of
conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of
conditions and the following disclaimer in the documentation and/or other materials provided
with the distribution.
3. The end-user documentation included with the redistribution, if any, must include the
following acknowledgment: "This product includes software developed by Uche Ogbuji
(http://uche.ogbuji.net)." Alternately, this acknowledgment may appear in the software
itself, if and wherever such third-party acknowledgments normally appear.
4. The names "Amara" and "Uche Ogbuji" must not be used to endorse or promote products derived
from this software without prior written permission of Uche Ogbuji (uche@ogbuji.net).
5. Products derived from this software may not be called "Amara", nor may "Amara" appear in
their name, without prior written permission of Uche Ogbuji (uche.ogbuji@gmail.com).
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL FOURTHOGHT, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
====================================================================
This license is based on the Apache Software License, Version 1.1,
Copyright (c) 2000 The Apache Software Foundation. All rights reserved.
springpython-1.2.0+ds/springpython/images/ 0000755 0000000 0000000 00000000000 11544154725 017377 5 ustar root root springpython-1.2.0+ds/springpython/images/spring_python_white.png 0000644 0000000 0000000 00000036745 11364062063 024220 0 ustar root root PNG
IHDR Z bKGD pHYs ~ tIME
7e 3P IDATxy|Tw}l$DPZ*
Z+nE-
V+*nV-qE!.@d
{2ɬws~A#y5ܙsssssU4iҤjI&-iҤo)Hf0mUUQE(!P/Ȗ(Jl@ )H*~ja* Emk8oE@P^Uĩj,1T
@"ވ SDDAAU|.U!PV[TEX,PtkX" ov z}g;eTj\J `Ֆ{,OKBX؊4KX4dDPDeFiJaz%!",mRBaxP1<"]({>lSP?@a|
\ \St$F埫huv=<2`lz@X1T7{J.9AY} >xm4K`S(?L-ܻV!hjL,OPX0:}~
BЉ4^r,9=z$֟K^牻D
:3;73ƔSpvr '
<
GTN"kf