From: <fwi...@us...> - 2008-12-12 15:47:03
|
Revision: 5751 http://jython.svn.sourceforge.net/jython/?rev=5751&view=rev Author: fwierzbicki Date: 2008-12-12 15:46:58 +0000 (Fri, 12 Dec 2008) Log Message: ----------- Dropping modjy code directly into Lib. Needed to move the code formerly in modjy.py into __init__.py in order to have a toplevel modjy/ dir (current modjy goes directly into a root namespace). Dropping com/xhaus/modjy/ModjyServlet.java into Jython's src dir, keeping com/xhaus/modjy packaging as requested by Alan Kennedy, the author of modjy. Added Paths: ----------- branches/modjy/Lib/modjy/ branches/modjy/Lib/modjy/__init__.py branches/modjy/Lib/modjy/modjy_exceptions.py branches/modjy/Lib/modjy/modjy_impl.py branches/modjy/Lib/modjy/modjy_log.py branches/modjy/Lib/modjy/modjy_params.py branches/modjy/Lib/modjy/modjy_publish.py branches/modjy/Lib/modjy/modjy_response.py branches/modjy/Lib/modjy/modjy_write.py branches/modjy/Lib/modjy/modjy_wsgi.py branches/modjy/src/com/xhaus/ branches/modjy/src/com/xhaus/modjy/ branches/modjy/src/com/xhaus/modjy/ModjyJServlet.java Added: branches/modjy/Lib/modjy/__init__.py =================================================================== --- branches/modjy/Lib/modjy/__init__.py (rev 0) +++ branches/modjy/Lib/modjy/__init__.py 2008-12-12 15:46:58 UTC (rev 5751) @@ -0,0 +1,119 @@ +### +# +# Copyright 2004-2008 Alan Kennedy. +# +# You may contact the copyright holder at this uri: +# +# http://www.xhaus.com/contact/modjy +# +# The licence under which this code is released is the Apache License v2.0. +# +# The terms and conditions of this license are listed in a file contained +# in the distribution that also contained this file, under the name +# LICENSE.txt. +# +# You may also read a copy of the license at the following web address. +# +# http://modjy.xhaus.com/LICENSE.txt +# +### + +__all__ = ['modjy', 'modjy_exceptions', 'modjy_impl', 'modjy_log', 'modjy_params', 'modjy_publish', 'modjy_response', 'modjy_write', 'modjy_wsgi',] + +import jarray +import synchronize +import sys +import types + +sys.add_package("javax.servlet") +sys.add_package("javax.servlet.http") +sys.add_package("org.python.core") + +from modjy_exceptions import * +from modjy_log import * +from modjy_params import modjy_param_mgr, modjy_servlet_params +from modjy_wsgi import modjy_wsgi +from modjy_response import start_response_object +from modjy_impl import modjy_impl +from modjy_publish import modjy_publisher + +from javax.servlet.http import HttpServlet + +class modjy_servlet(HttpServlet, modjy_publisher, modjy_wsgi, modjy_impl): + + def __init__(self): + HttpServlet.__init__(self) + + def do_param(self, name, value): + if name[:3] == 'log': + getattr(self.log, "set_%s" % name)(value) + else: + self.params[name] = value + + def get_params(self): + for pname in self.servlet_context.getInitParameterNames(): + self.do_param(pname, self.servlet_context.getInitParameter(pname)) + for pname in self.servlet.getInitParameterNames(): + self.do_param(pname, self.servlet.getInitParameter(pname)) + + def init(self, delegator): + self.servlet = delegator + self.servlet_context = self.servlet.getServletContext() + self.servlet_config = self.servlet.getServletConfig() + self.log = modjy_logger(self.servlet_context) + self.params = modjy_param_mgr(modjy_servlet_params) + self.get_params() + self.init_impl() + self.init_publisher() + import modjy_exceptions + self.exc_handler = getattr(modjy_exceptions, '%s_handler' % self.params['exc_handler'])() + + def service (self, req, resp): + wsgi_environ = {} + try: + self.dispatch_to_application(req, resp, wsgi_environ) + except ModjyException, mx: + self.log.error("Exception servicing request: %s" % str(mx)) + typ, value, tb = sys.exc_info()[:] + self.exc_handler.handle(req, resp, wsgi_environ, mx, (typ, value, tb) ) + + def get_j2ee_ns(self, req, resp): + return { + 'servlet': self.servlet, + 'servlet_context': self.servlet_context, + 'servlet_config': self.servlet_config, + 'request': req, + 'response': resp, + } + + def dispatch_to_application(self, req, resp, environ): + app_callable = self.get_app_object(req, environ) + self.set_wsgi_environment(req, resp, environ, self.params, self.get_j2ee_ns(req, resp)) + response_callable = start_response_object(req, resp) + try: + app_return = self.call_application(app_callable, environ, response_callable) + if app_return is None: + raise ReturnNotIterable("Application returned None: must return an iterable") + self.deal_with_app_return(environ, response_callable, app_return) + except ModjyException, mx: + self.raise_exc(mx.__class__, str(mx)) + except Exception, x: + self.raise_exc(ApplicationException, str(x)) + + def call_application(self, app_callable, environ, response_callable): + if self.params['multithread']: + return app_callable.__call__(environ, response_callable) + else: + return synchronize.apply_synchronized( \ + app_callable, \ + app_callable, \ + (environ, response_callable)) + + def expand_relative_path(self, path): + if path.startswith("$"): + return self.servlet.getServletContext().getRealPath(path[1:]) + return path + + def raise_exc(self, exc_class, message): + self.log.error(message) + raise exc_class(message) Added: branches/modjy/Lib/modjy/modjy_exceptions.py =================================================================== --- branches/modjy/Lib/modjy/modjy_exceptions.py (rev 0) +++ branches/modjy/Lib/modjy/modjy_exceptions.py 2008-12-12 15:46:58 UTC (rev 5751) @@ -0,0 +1,91 @@ +### +# +# Copyright 2004-2008 Alan Kennedy. +# +# You may contact the copyright holder at this uri: +# +# http://www.xhaus.com/contact/modjy +# +# The licence under which this code is released is the Apache License v2.0. +# +# The terms and conditions of this license are listed in a file contained +# in the distribution that also contained this file, under the name +# LICENSE.txt. +# +# You may also read a copy of the license at the following web address. +# +# http://modjy.xhaus.com/LICENSE.txt +# +### + +import sys +import StringIO +import traceback + +from java.lang import IllegalStateException +from java.io import IOException +from javax.servlet import ServletException + +class ModjyException(Exception): pass + +class ModjyIOException(ModjyException): pass + +class ConfigException(ModjyException): pass +class BadParameter(ConfigException): pass +class ApplicationNotFound(ConfigException): pass +class NoCallable(ConfigException): pass + +class RequestException(ModjyException): pass + +class ApplicationException(ModjyException): pass +class StartResponseNotCalled(ApplicationException): pass +class StartResponseCalledTwice(ApplicationException): pass +class ResponseCommitted(ApplicationException): pass +class HopByHopHeaderSet(ApplicationException): pass +class WrongLength(ApplicationException): pass +class BadArgument(ApplicationException): pass +class ReturnNotIterable(ApplicationException): pass +class NonStringOutput(ApplicationException): pass + +class exception_handler: + + def handle(self, req, resp, environ, exc, exc_info): + pass + + def get_status_and_message(self, req, resp, exc): + return resp.SC_INTERNAL_SERVER_ERROR, "Server configuration error" + +# +# Special exception handler for testing +# + +class testing_handler(exception_handler): + + def handle(self, req, resp, environ, exc, exc_info): + typ, value, tb = exc_info + err_msg = StringIO.StringIO() + err_msg.write("%s: %s\n" % (typ, value,) ) + err_msg.write(">Environment\n") + for k in environ.keys(): + err_msg.write("%s=%s\n" % (k, repr(environ[k])) ) + err_msg.write("<Environment\n") + err_msg.write(">TraceBack\n") + for line in traceback.format_exception(typ, value, tb): + err_msg.write(line) + err_msg.write("<TraceBack\n") + try: + status, message = self.get_status_and_message(req, resp, exc) + resp.setStatus(status) + resp.setContentLength(len(err_msg.getvalue())) + resp.getOutputStream().write(err_msg.getvalue()) + except IllegalStateException, ise: + raise exc # Let the container deal with it + +# +# Standard exception handler +# + +class standard_handler(exception_handler): + + def handle(self, req, resp, environ, exc, exc_info): + raise exc Added: branches/modjy/Lib/modjy/modjy_impl.py =================================================================== --- branches/modjy/Lib/modjy/modjy_impl.py (rev 0) +++ branches/modjy/Lib/modjy/modjy_impl.py 2008-12-12 15:46:58 UTC (rev 5751) @@ -0,0 +1,101 @@ +### +# +# Copyright 2004-2008 Alan Kennedy. +# +# You may contact the copyright holder at this uri: +# +# http://www.xhaus.com/contact/modjy +# +# The licence under which this code is released is the Apache License v2.0. +# +# The terms and conditions of this license are listed in a file contained +# in the distribution that also contained this file, under the name +# LICENSE.txt. +# +# You may also read a copy of the license at the following web address. +# +# http://modjy.xhaus.com/LICENSE.txt +# +### + +import types +import sys + +from modjy_exceptions import * + +class modjy_impl: + + def deal_with_app_return(self, environ, start_response_callable, app_return): + self.log.debug("Processing app return type: %s" % str(type(app_return))) + if isinstance(app_return, types.StringTypes): + raise ReturnNotIterable("Application returned object that was not an iterable: %s" % str(type(app_return))) + if type(app_return) is types.FileType: + pass # TBD: What to do here? can't call fileno() + if hasattr(app_return, '__len__') and callable(app_return.__len__): + expected_pieces = app_return.__len__() + else: + expected_pieces = -1 + try: + try: + ix = 0 + for next_piece in app_return: + if not isinstance(next_piece, types.StringType): + raise NonStringOutput("Application returned iterable containing non-strings: %s" % str(type(next_piece))) + if ix == 0: + # The application may have called start_response in the first iteration + if not start_response_callable.called: + raise StartResponseNotCalled("Start_response callable was never called.") + if not start_response_callable.content_length \ + and expected_pieces == 1 \ + and start_response_callable.write_callable.num_writes == 0: + # Take the length of the first piece + start_response_callable.set_content_length(len(next_piece)) + start_response_callable.write_callable(next_piece) + ix += 1 + if ix == expected_pieces: + break + if expected_pieces != -1 and ix != expected_pieces: + raise WrongLength("Iterator len() was wrong. Expected %d pieces: got %d" % (expected_pieces, ix) ) + except AttributeError, ax: + if str(ax) == "__getitem__": + raise ReturnNotIterable("Application returned object that was not an iterable: %s" % str(type(app_return))) + else: + raise ax + except TypeError, tx: + raise ReturnNotIterable("Application returned object that was not an iterable: %s" % str(type(app_return))) + except ModjyException, mx: + raise mx + except Exception, x: + raise ApplicationException(x) + finally: + if hasattr(app_return, 'close') and callable(app_return.close): + app_return.close() + + def init_impl(self): + self.do_j_env_params() + + def add_packages(self, package_list): + packages = [p.strip() for p in package_list.split(';')] + for p in packages: + self.log.info("Adding java package %s to jython" % p) + sys.add_package(p) + + def add_classdirs(self, classdir_list): + classdirs = [cd.strip() for cd in classdir_list.split(';')] + for cd in classdirs: + self.log.info("Adding directory %s to jython class file search path" % cd) + sys.add_classdir(cd) + + def add_extdirs(self, extdir_list): + extdirs = [ed.strip() for ed in extdir_list.split(';')] + for ed in extdirs: + self.log.info("Adding directory %s for .jars and .zips search path" % ed) + sys.add_extdir(self.expand_relative_path(ed)) + + def do_j_env_params(self): + if self.params['packages']: + self.add_packages(self.params['packages']) + if self.params['classdirs']: + self.add_classdirs(self.params['classdirs']) + if self.params['extdirs']: + self.add_extdirs(self.params['extdirs']) Added: branches/modjy/Lib/modjy/modjy_log.py =================================================================== --- branches/modjy/Lib/modjy/modjy_log.py (rev 0) +++ branches/modjy/Lib/modjy/modjy_log.py 2008-12-12 15:46:58 UTC (rev 5751) @@ -0,0 +1,80 @@ +### +# +# Copyright 2004-2008 Alan Kennedy. +# +# You may contact the copyright holder at this uri: +# +# http://www.xhaus.com/contact/modjy +# +# The licence under which this code is released is the Apache License v2.0. +# +# The terms and conditions of this license are listed in a file contained +# in the distribution that also contained this file, under the name +# LICENSE.txt. +# +# You may also read a copy of the license at the following web address. +# +# http://modjy.xhaus.com/LICENSE.txt +# +### + +import java + +import sys + +DEBUG = 'debug' +INFO = 'info' +WARN = 'warn' +ERROR = 'error' +FATAL = 'fatal' + +levels_dict = {} +ix = 0 +for level in [DEBUG, INFO, WARN, ERROR, FATAL, ]: + levels_dict[level]=ix + ix += 1 + +class modjy_logger: + + def __init__(self, context): + self.log_ctx = context + self.format_str = "%(lvl)s:\t%(msg)s" + self.log_level = levels_dict[DEBUG] + + def _log(self, level, level_str, msg, exc): + if level >= self.log_level: + msg = self.format_str % {'lvl': level_str, 'msg': msg, } + if exc: +# java.lang.System.err.println(msg, exc) + self.log_ctx.log(msg, exc) + else: +# java.lang.System.err.println(msg) + self.log_ctx.log(msg) + + def debug(self, msg, exc=None): + self._log(0, DEBUG, msg, exc) + + def info(self, msg, exc=None): + self._log(1, INFO, msg, exc) + + def warn(self, msg, exc=None): + self._log(2, WARN, msg, exc) + + def error(self, msg, exc=None): + self._log(3, ERROR, msg, exc) + + def fatal(self, msg, exc=None): + self._log(4, FATAL, msg, exc) + + def set_log_level(self, level_string): + try: + self.level = levels_dict[level_string] + except KeyError: + raise BadParameter("Invalid log level: '%s'" % level_string) + + def set_log_format(self, format_string): + # BUG! Format string never actually used in this function. + try: + self._log(debug, "This is a log formatting test", None) + except KeyError: + raise BadParameter("Bad format string: '%s'" % format_string) Added: branches/modjy/Lib/modjy/modjy_params.py =================================================================== --- branches/modjy/Lib/modjy/modjy_params.py (rev 0) +++ branches/modjy/Lib/modjy/modjy_params.py 2008-12-12 15:46:58 UTC (rev 5751) @@ -0,0 +1,84 @@ +### +# +# Copyright 2004-2008 Alan Kennedy. +# +# You may contact the copyright holder at this uri: +# +# http://www.xhaus.com/contact/modjy +# +# The licence under which this code is released is the Apache License v2.0. +# +# The terms and conditions of this license are listed in a file contained +# in the distribution that also contained this file, under the name +# LICENSE.txt. +# +# You may also read a copy of the license at the following web address. +# +# http://modjy.xhaus.com/LICENSE.txt +# +### + +from UserDict import UserDict + +BOOLEAN = ('boolean', int) +INTEGER = ('integer', int) +FLOAT = ('float', float) +STRING = ('string', None) + +modjy_servlet_params = { + + 'multithread': (BOOLEAN, 1), + 'cache_callables': (BOOLEAN, 1), + 'reload_on_mod': (BOOLEAN, 0), + + 'app_import_name': (STRING, None), + + 'app_directory': (STRING, None), + 'app_filename': (STRING, 'application.py'), + 'app_callable_name': (STRING, 'handler'), + 'callable_query_name': (STRING, None), + + 'exc_handler': (STRING, 'standard'), + + 'log_level': (STRING, 'info'), + + 'packages': (STRING, None), + 'classdirs': (STRING, None), + 'extdirs': (STRING, None), + + 'initial_env': (STRING, None), +} + +class modjy_param_mgr(UserDict): + + def __init__(self, param_types): + UserDict.__init__(self) + self.param_types = param_types + for pname in self.param_types.keys(): + typ, default = self.param_types[pname] + self.__setitem__(pname, default) + + def __getitem__(self, name): + return self._get_defaulted_value(name) + + def __setitem__(self, name, value): + self.data[name] = self._convert_value(name, value) + + def _convert_value(self, name, value): + if self.param_types.has_key(name): + typ, default = self.param_types[name] + typ_str, typ_func = typ + if typ_func: + try: + return typ_func(value) + except ValueError: + raise BadParameter("Illegal value for %s parameter '%s': %s" % (typ_str, name, value) ) + return value + + def _get_defaulted_value(self, name): + if self.data.has_key(name): + return self.data[name] + if self.param_types.has_key(name): + typ, default = self.param_types[name] + return default + raise KeyError(name) Added: branches/modjy/Lib/modjy/modjy_publish.py =================================================================== --- branches/modjy/Lib/modjy/modjy_publish.py (rev 0) +++ branches/modjy/Lib/modjy/modjy_publish.py 2008-12-12 15:46:58 UTC (rev 5751) @@ -0,0 +1,142 @@ +### +# +# Copyright 2004-2008 Alan Kennedy. +# +# You may contact the copyright holder at this uri: +# +# http://www.xhaus.com/contact/modjy +# +# The licence under which this code is released is the Apache License v2.0. +# +# The terms and conditions of this license are listed in a file contained +# in the distribution that also contained this file, under the name +# LICENSE.txt. +# +# You may also read a copy of the license at the following web address. +# +# http://modjy.xhaus.com/LICENSE.txt +# +### + +import sys +import synchronize + +from java.io import File + +from modjy_exceptions import * + +class modjy_publisher: + + def init_publisher(self): + self.cache = None + if self.params['app_directory']: + self.app_directory = self.expand_relative_path(self.params['app_directory']) + else: + self.app_directory = self.servlet_context.getRealPath('/') + self.params['app_directory'] = self.app_directory + if not self.app_directory in sys.path: + sys.path.append(self.app_directory) + + def map_uri(self, req, environ): + script_name = "%s%s" % (req.getContextPath(), req.getServletPath()) + path_info = req.getPathInfo() or "" + source_uri = '%s%s%s' % (self.app_directory, File.separator, self.params['app_filename']) + callable_name = self.params['app_callable_name'] + if self.params['callable_query_name']: + query_string = req.getQueryString() + if query_string and '=' in query_string: + for name_val in query_string.split('&'): + name, value = name_val.split('=') + if name == self.params['callable_query_name']: + callable_name = value + environ["SCRIPT_NAME"] = script_name + environ["PATH_INFO"] = path_info + environ["PATH_TRANSLATED"] = File(self.app_directory, path_info).getPath() + return source_uri, callable_name + + def get_app_object(self, req, environ): + if self.params['app_import_name'] is not None: + return self.get_app_object_importable(self.params['app_import_name']) + else: + if self.cache is None: + self.cache = {} + return self.get_app_object_old_style(req, environ) + + get_app_object = synchronize.make_synchronized(get_app_object) + + def get_app_object_importable(self, importable_name): + self.log.debug("Attempting to import application callable '%s'\n" % (importable_name, )) + # Under the importable mechanism, the cache contains a single object + if self.cache is None: + application, instantiable, method_name = self.load_importable(importable_name.strip()) + if instantiable and self.params['cache_callables']: + application = application() + self.cache = application, instantiable, method_name + application, instantiable, method_name = self.cache + self.log.debug("Application is " + str(application)) + if instantiable and not self.params['cache_callables']: + application = application() + self.log.debug("Instantiated application is " + str(application)) + if method_name is not None: + application = getattr(application, method_name) + self.log.debug("Application method is " + str(application)) + return application + + def load_importable(self, name): + try: + instantiable = False ; method_name = None + names = name.split('.') ; names.reverse() + imported = __import__(names.pop()) + while names: + n = names.pop() + if n.endswith("()"): + n = n[:-2] ; instantiable = True + self.log.debug("importable '%s' is instantiable." % n) + if len(names) > 1: + names.reverse() + message = "Failed to import '%s': '%s' is not a valid method name" % (name, ".".join(names)) + self.log.error(message) + self.raise_exc(ApplicationNotFound, message) + elif len(names) == 1: + method_name = names.pop() + else: + method_name = None + imported = getattr(imported, n) + self.log.debug("Imported '%s' from '%s'\n" % (n, str(imported))) + return imported, instantiable, method_name + except (ImportError, AttributeError), aix: + self.log.fatal("Import error import application callable '%s': %s\n" % (name, str(aix))) + self.raise_exc(ApplicationNotFound, "Failed to import app callable '%s': %s" % (name, str(aix))) + + def get_app_object_old_style(self, req, environ): + source_uri, callable_name = self.map_uri(req, environ) + source_filename = source_uri + if not self.params['cache_callables']: + self.log.debug("Caching of callables disabled") + return self.load_object(source_filename, callable_name) + if not self.cache.has_key( (source_filename, callable_name) ): + self.log.debug("Callable object not in cache: %s#%s" % (source_filename, callable_name) ) + return self.load_object(source_filename, callable_name) + app_callable, last_mod = self.cache.get( (source_filename, callable_name) ) + self.log.debug("Callable object was in cache: %s#%s" % (source_filename, callable_name) ) + if self.params['reload_on_mod']: + f = File(source_filename) + if f.lastModified() > last_mod: + self.log.info("Source file '%s' has been modified: reloading" % source_filename) + return self.load_object(source_filename, callable_name) + return app_callable + + def load_object(self, path, callable_name): + try: + app_ns = {} ; execfile(path, app_ns) + app_callable = app_ns[callable_name] + f = File(path) + self.cache[ (path, callable_name) ] = (app_callable, f.lastModified()) + return app_callable + except IOError, ioe: + self.raise_exc(ApplicationNotFound, "Application filename not found: %s" % path) + except KeyError, k: + self.raise_exc(NoCallable, "No callable named '%s' in %s" % (callable_name, path)) + except Exception, x: + self.raise_exc(NoCallable, "Error loading jython callable '%s': %s" % (callable_name, str(x)) ) + Added: branches/modjy/Lib/modjy/modjy_response.py =================================================================== --- branches/modjy/Lib/modjy/modjy_response.py (rev 0) +++ branches/modjy/Lib/modjy/modjy_response.py 2008-12-12 15:46:58 UTC (rev 5751) @@ -0,0 +1,113 @@ +### +# +# Copyright 2004-2008 Alan Kennedy. +# +# You may contact the copyright holder at this uri: +# +# http://www.xhaus.com/contact/modjy +# +# The licence under which this code is released is the Apache License v2.0. +# +# The terms and conditions of this license are listed in a file contained +# in the distribution that also contained this file, under the name +# LICENSE.txt. +# +# You may also read a copy of the license at the following web address. +# +# http://modjy.xhaus.com/LICENSE.txt +# +### + +import types + +from java.lang import System + +from modjy_exceptions import * +from modjy_write import write_object + +# From: http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.5.1 + +hop_by_hop_headers = { + 'connection': None, + 'keep-alive': None, + 'proxy-authenticate': None, + 'proxy-authorization': None, + 'te': None, + 'trailers': None, + 'transfer-encoding': None, + 'upgrade': None, +} + +class start_response_object: + + def __init__(self, req, resp): + self.http_req = req + self.http_resp = resp + self.write_callable = None + self.called = 0 + self.content_length = None + + # I'm doing the parameters this way to facilitate porting back to java + def __call__(self, *args, **keywords): + if len(args) < 2 or len(args) > 3: + raise BadArgument("Start response callback requires either two or three arguments: got %s" % str(args)) + if len(args) == 3: + exc_info = args[2] + try: + try: + self.http_resp.reset() + except IllegalStateException, isx: + raise exc_info[0], exc_info[1], exc_info[2] + finally: + exc_info = None + else: + if self.called > 0: + raise StartResponseCalledTwice("Start response callback may only be called once, without exception information.") + status_str = args[0] + headers_list = args[1] + if not isinstance(status_str, types.StringType): + raise BadArgument("Start response callback requires string as first argument") + if not isinstance(headers_list, types.ListType): + raise BadArgument("Start response callback requires list as second argument") + try: + status_code, status_message_str = status_str.split(" ", 1) + self.http_resp.setStatus(int(status_code)) + except ValueError: + raise BadArgument("Status string must be of the form '<int> <string>'") + self.make_write_object() + try: + for header_name, header_value in headers_list: + header_name_lower = header_name.lower() + if hop_by_hop_headers.has_key(header_name_lower): + raise HopByHopHeaderSet("Under WSGI, it is illegal to set hop-by-hop headers, i.e. '%s'" % header_name) + if header_name_lower == "content-length": + try: + self.set_content_length(int(header_value)) + except ValueError, v: + raise BadArgument("Content-Length header value must be a string containing an integer, not '%s'" % header_value) + else: + final_value = header_value.encode('latin-1') + # Here would be the place to check for control characters, whitespace, etc + self.http_resp.addHeader(header_name, final_value) + except (AttributeError, TypeError), t: + raise BadArgument("Start response callback headers must contain a list of (<string>,<string>) tuples") + except UnicodeError, u: + raise BadArgument("Encoding error: header values may only contain latin-1 characters, not '%s'" % repr(header_value)) + except ValueError, v: + raise BadArgument("Headers list must contain 2-tuples") + self.called += 1 + return self.write_callable + + def set_content_length(self, length): + if self.write_callable.num_writes == 0: + self.content_length = length + self.http_resp.setContentLength(length) + else: + raise ResponseCommitted("Cannot set content-length: response is already commited.") + + def make_write_object(self): + try: + self.write_callable = write_object(self.http_resp.getOutputStream()) + except IOException, iox: + raise IOError(iox) + return self.write_callable Added: branches/modjy/Lib/modjy/modjy_write.py =================================================================== --- branches/modjy/Lib/modjy/modjy_write.py (rev 0) +++ branches/modjy/Lib/modjy/modjy_write.py 2008-12-12 15:46:58 UTC (rev 5751) @@ -0,0 +1,43 @@ +### +# +# Copyright 2004-2008 Alan Kennedy. +# +# You may contact the copyright holder at this uri: +# +# http://www.xhaus.com/contact/modjy +# +# The licence under which this code is released is the Apache License v2.0. +# +# The terms and conditions of this license are listed in a file contained +# in the distribution that also contained this file, under the name +# LICENSE.txt. +# +# You may also read a copy of the license at the following web address. +# +# http://modjy.xhaus.com/LICENSE.txt +# +### + +import types + +from modjy_exceptions import * + +class write_object: + + def __init__(self, ostream): + self.ostream = ostream + self.num_writes = 0 + + def __call__(self, *args, **keywords): + if len(args) != 1 or type(args[0]) is not types.StringType: + raise NonStringOutput("Invocation of write callable requires exactly one string argument") + try: + self.ostream.write(args[0]) # Jython implicitly converts the (binary) string to a byte array + # WSGI requires that all output be flushed before returning to the application + # According to the java docs: " The flush method of OutputStream does nothing." + # Still, leave it in place for now: it's in the right place should this + # code ever be ported to another platform. + self.ostream.flush() + self.num_writes += 1 + except Exception, x: + raise ModjyIOException(x) Added: branches/modjy/Lib/modjy/modjy_wsgi.py =================================================================== --- branches/modjy/Lib/modjy/modjy_wsgi.py (rev 0) +++ branches/modjy/Lib/modjy/modjy_wsgi.py 2008-12-12 15:46:58 UTC (rev 5751) @@ -0,0 +1,143 @@ +### +# +# Copyright 2004-2008 Alan Kennedy. +# +# You may contact the copyright holder at this uri: +# +# http://www.xhaus.com/contact/modjy +# +# The licence under which this code is released is the Apache License v2.0. +# +# The terms and conditions of this license are listed in a file contained +# in the distribution that also contained this file, under the name +# LICENSE.txt. +# +# You may also read a copy of the license at the following web address. +# +# http://modjy.xhaus.com/LICENSE.txt +# +### + +from java.lang import System +from org.python.core import PyFile + +from modjy_exceptions import * + +server_name = "modjy" +server_param_prefix = "%s.param" % server_name +j2ee_ns_prefix = "j2ee" + +class modjy_wsgi: + + # + # WSGI constants + # + + empty_pystring = "" + wsgi_version = (1,0) + + # + # Container-specific constants + # + + modjy_version = (0, 22, 3) + + def set_string_envvar(self, dict, name, value, default_value): + if value == default_value: + dict[name] = self.empty_pystring + else: + dict[name] = value + + def set_string_envvar_optional(self, dict, name, value, default_value): + if value != default_value: + dict[name] = str(value) + + def set_int_envvar(self, dict, name, value, default_value): + if value == default_value: + dict[name] = self.empty_pystring + else: + dict[name] = str(value) + + def set_container_specific_wsgi_vars(self, req, resp, dict, params): + dict["%s.version" % server_name] = self.modjy_version + for pname in params.keys(): + dict["%s.%s" % (server_param_prefix, pname)] = params[pname] + + def set_j2ee_specific_wsgi_vars(self, dict, j2ee_ns): + for p in j2ee_ns.keys(): + dict["%s.%s" % (j2ee_ns_prefix, p)] = j2ee_ns[p] + + def set_required_cgi_environ (self, req, resp, dict): + self.set_string_envvar(dict, "REQUEST_METHOD", req.getMethod(), None) + self.set_string_envvar(dict, "QUERY_STRING", req.getQueryString(), None) + self.set_string_envvar(dict, "CONTENT_TYPE", req.getContentType(), None) + self.set_int_envvar(dict, "CONTENT_LENGTH", req.getContentLength(), -1) + self.set_string_envvar(dict, "SERVER_NAME", req.getLocalName(), None) + self.set_int_envvar(dict, "SERVER_PORT", req.getLocalPort(), 0) + + def set_other_cgi_environ (self, req, resp, dict): + if req.isSecure(): + self.set_string_envvar(dict, "HTTPS", 'on', None) + else: + self.set_string_envvar(dict, "HTTPS", 'off', None) + self.set_string_envvar(dict, "SERVER_PROTOCOL", req.getProtocol(), None) + self.set_string_envvar(dict, "REMOTE_HOST", req.getRemoteHost(), None) + self.set_string_envvar(dict, "REMOTE_ADDR", req.getRemoteAddr(), None) + self.set_int_envvar(dict, "REMOTE_PORT", req.getRemotePort(), -1) + self.set_string_envvar_optional(dict, "AUTH_TYPE", req.getAuthType(), None) + self.set_string_envvar_optional(dict, "REMOTE_USER", req.getRemoteUser(), None) + + def set_http_header_environ(self, req, resp, dict): + for curr_header_name in req.getHeaderNames(): + values = None + for next_value in req.getHeaders(curr_header_name): + if values is None: + values = next_value + else: + if isinstance(values, types.ListType): + values.append(next_value) + else: + values = [values] + dict["HTTP_%s" % curr_header_name.replace('-', '_').upper()] = values + + def set_required_wsgi_vars(self, req, resp, dict): + dict["wsgi.version"] = self.wsgi_version + dict["wsgi.url_scheme"] = req.getScheme() + dict["wsgi.multithread"] = \ + int(dict["%s.cache_callables" % server_param_prefix]) \ + and \ + int(dict["%s.multithread" % server_param_prefix]) + dict["wsgi.multiprocess"] = self.wsgi_multiprocess = 0 + dict["wsgi.run_once"] = not(dict["%s.cache_callables" % server_param_prefix]) + + def set_wsgi_streams(self, req, resp, dict): + try: + dict["wsgi.input"] = PyFile(req.getInputStream()) + dict["wsgi.errors"] = PyFile(System.err) + except IOException, iox: + raise ModjyIOException(iox) + + def set_wsgi_classes(self, req, resp, dict): + # dict["wsgi.file_wrapper"] = modjy_file_wrapper + pass + + def set_user_specified_environment(self, req, resp, wsgi_environ, params): + if not params.has_key('initial_env') or not params['initial_env']: + return + user_env_string = params['initial_env'] + for l in user_env_string.split('\n'): + l = l.strip() + if l: + name, value = l.split(':', 1) + wsgi_environ[name.strip()] = value.strip() + + def set_wsgi_environment(self, req, resp, wsgi_environ, params, j2ee_ns): + self.set_container_specific_wsgi_vars(req, resp, wsgi_environ, params) + self.set_j2ee_specific_wsgi_vars(wsgi_environ, j2ee_ns) + self.set_required_cgi_environ(req, resp, wsgi_environ) + self.set_other_cgi_environ(req, resp, wsgi_environ) + self.set_http_header_environ(req, resp, wsgi_environ) + self.set_required_wsgi_vars(req, resp, wsgi_environ) + self.set_wsgi_streams(req, resp, wsgi_environ) + self.set_wsgi_classes(req, resp, wsgi_environ) + self.set_user_specified_environment(req, resp, wsgi_environ, params) Added: branches/modjy/src/com/xhaus/modjy/ModjyJServlet.java =================================================================== --- branches/modjy/src/com/xhaus/modjy/ModjyJServlet.java (rev 0) +++ branches/modjy/src/com/xhaus/modjy/ModjyJServlet.java 2008-12-12 15:46:58 UTC (rev 5751) @@ -0,0 +1,217 @@ +/*### +# +# Copyright 2004-2008 Alan Kennedy. +# +# You may contact the copyright holder at this uri: +# +# http://www.xhaus.com/contact/modjy +# +# The licence under which this code is released is the Apache License v2.0. +# +# The terms and conditions of this license are listed in a file contained +# in the distribution that also contained this file, under the name +# LICENSE.txt. +# +# You may also read a copy of the license at the following web address. +# +# http://www.xhaus.com/modjy/LICENSE.txt +# +###*/ + +package com.xhaus.modjy; + +import java.io.*; +import java.util.*; +import javax.servlet.*; +import javax.servlet.http.*; +import org.python.core.*; +import org.python.util.*; + +public class ModjyJServlet extends HttpServlet +{ + + protected final static String MODJY_PYTHON_CLASSNAME = "modjy_servlet"; + protected final static String LIB_PYTHON = "/WEB-INF/lib-python"; + protected final static String PTH_FILE_EXTENSION = ".pth"; + + protected PythonInterpreter interp; + protected HttpServlet modjyServlet; + + /** + * Read configuration + * 1. Both context and servlet parameters are included in the set, + * so that the definition of some parameters (e.g python.*) can be shared + * between multiple WSGI servlets. + * 2. servlet params take precedence over context parameters + */ + + protected Properties readConfiguration ( ) + { + Properties props = new Properties(); + // Context parameters + ServletContext context = getServletContext(); + Enumeration e = context.getInitParameterNames(); + while (e.hasMoreElements()) + { + String name = (String) e.nextElement(); + props.put(name, context.getInitParameter(name)); + } + // Servlet parameters override context parameters + e = getInitParameterNames(); + while (e.hasMoreElements()) + { + String name = (String) e.nextElement(); + props.put(name, getInitParameter(name)); + } + return props; + } + + /** + * Initialise the modjy servlet. + * 1. Read the configuration + * 2. Initialise the jython runtime + * 3. Setup, in relation to the J2EE servlet environment + * 4. Create the jython-implemented servlet + * 5. Initialise the jython-implemented servlet + */ + + public void init ( ) + throws ServletException + { + try + { + Properties props = readConfiguration(); + PythonInterpreter.initialize(System.getProperties(), props, new String[0]); + interp = new PythonInterpreter(null, new PySystemState()); + String modjyJarLocation = setupEnvironment(props, Py.getSystemState()); + try + { interp.exec("from modjy import "+MODJY_PYTHON_CLASSNAME); } + catch (PyException ix) + { throw new ServletException("Unable to import '"+MODJY_PYTHON_CLASSNAME+"' from "+modjyJarLocation+ + ": do you maybe need to set the 'modjy_jar.location' parameter?");} + PyObject pyServlet = ((PyClass)interp.get(MODJY_PYTHON_CLASSNAME)).__call__(); + Object temp = pyServlet.__tojava__(HttpServlet.class); + if (temp == Py.NoConversion) + throw new ServletException("Corrupted modjy file: cannot find definition of '"+MODJY_PYTHON_CLASSNAME+"' class"); + modjyServlet = (HttpServlet) temp; + modjyServlet.init(this); + } + catch (PyException pyx) + { + throw new ServletException("Exception creating modjy servlet: " + pyx.toString(), pyx); + } + } + + /** + * Actually service the incoming request. + * Simply delegate to the jython servlet. + * + * @param request - The incoming HttpServletRequest + * @param response - The outgoing HttpServletResponse + */ + + public void service ( HttpServletRequest req, HttpServletResponse resp ) + throws ServletException, IOException + { + modjyServlet.service(req, resp); + } + + /** + * Setup the modjy environment, i.e. + * 1. Find the location of the modjy.jar file and add it to sys.path + * 2. Process the WEB-INF/lib-python directory, if it exists + * + * @param props The properties from which config options are found + * @param systemState The PySystemState corresponding to the interpreter servicing requests + * @returns A String giving the path to the modjy.jar file (which is used only for error reporting) + */ + + protected String setupEnvironment(Properties props, PySystemState systemState) + { + String modjyJarLocation = locateModjyJar(props); + systemState.path.append(new PyString(modjyJarLocation)); + processPythonLib(systemState); + return modjyJarLocation; + } + + /** + * Find out the location of "modjy.jar", so that it can + * be added to the sys.path and thus imported + * + * @param The properties from which config options are found + * @returns A String giving the path to the modjy.jar file + */ + + protected String locateModjyJar ( Properties props ) + { + // Give priority to modjy_jar.location + if (props.get("modjy_jar.location") != null) + return (String)props.get("modjy_jar.location"); + // Then try to find it in WEB-INF/lib + String location = getServletContext().getRealPath("/WEB-INF/lib/modjy.jar"); + if (location != null) + { + File f = new File(location); + if (f.exists()) + return location; + } + // Try finding the archive that this class was loaded from + try + { return this.getClass().getProtectionDomain().getCodeSource().getLocation().getFile(); } + catch (Exception x) + { return null;} + } + + /** + * Do all processing in relation to the lib-python subdirectory of WEB-INF + * + * @param systemState - The PySystemState whose path should be updated + */ + + protected void processPythonLib(PySystemState systemState) + { + // Add the lib-python directory to sys.path + String pythonLibPath = getServletContext().getRealPath(LIB_PYTHON); + if (pythonLibPath == null) + return; + File pythonLib = new File(pythonLibPath); + if (!pythonLib.exists()) + return; + systemState.path.append(new PyString(pythonLibPath)); + // Now check for .pth files in lib-python and process each one + String[] libPythonContents = pythonLib.list(); + for (int ix = 0 ; ix < libPythonContents.length ; ix++) + if (libPythonContents[ix].endsWith(PTH_FILE_EXTENSION)) + processPthFile(systemState, pythonLibPath, libPythonContents[ix]); + } + + /** + * Process an individual file .pth file in the lib-python directory + * + * @param systemState - The PySystemState whose path should be updated + * @param pythonLibPath - The actual path to the lib-python directory + * @param pthFilename - The PySystemState whose path should be updated + */ + + protected void processPthFile(PySystemState systemState, String pythonLibPath, String pthFilename) + { + try + { + LineNumberReader lineReader = new LineNumberReader(new FileReader(new File(pythonLibPath, pthFilename))); + String line; + while ((line = lineReader.readLine()) != null) + { + line = line.trim(); + if (line.startsWith("#")) + continue; + File archiveFile = new File(pythonLibPath, line); + String archiveRealpath = archiveFile.getAbsolutePath(); + systemState.path.append(new PyString(archiveRealpath)); + } + } + catch (IOException iox) + { + System.err.println("IOException: " + iox.toString()); + } + } +} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <am...@us...> - 2009-03-05 13:15:54
|
Revision: 6066 http://jython.svn.sourceforge.net/jython/?rev=6066&view=rev Author: amak Date: 2009-03-05 13:15:50 +0000 (Thu, 05 Mar 2009) Log Message: ----------- Removing old version of modjy, to get a fresh start on copying in the latest version. Removed Paths: ------------- branches/modjy/Lib/modjy/ branches/modjy/src/com/xhaus/ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <am...@us...> - 2009-03-05 13:18:58
|
Revision: 6067 http://jython.svn.sourceforge.net/jython/?rev=6067&view=rev Author: amak Date: 2009-03-05 13:18:55 +0000 (Thu, 05 Mar 2009) Log Message: ----------- Copying over latest version of modjy, version 0.25.3. Added Paths: ----------- branches/modjy/Lib/modjy/ branches/modjy/Lib/modjy/__init__.py branches/modjy/Lib/modjy/modjy.py branches/modjy/Lib/modjy/modjy_exceptions.py branches/modjy/Lib/modjy/modjy_impl.py branches/modjy/Lib/modjy/modjy_log.py branches/modjy/Lib/modjy/modjy_params.py branches/modjy/Lib/modjy/modjy_publish.py branches/modjy/Lib/modjy/modjy_response.py branches/modjy/Lib/modjy/modjy_write.py branches/modjy/Lib/modjy/modjy_wsgi.py branches/modjy/src/com/xhaus/ branches/modjy/src/com/xhaus/modjy/ branches/modjy/src/com/xhaus/modjy/ModjyJServlet.java Added: branches/modjy/Lib/modjy/__init__.py =================================================================== --- branches/modjy/Lib/modjy/__init__.py (rev 0) +++ branches/modjy/Lib/modjy/__init__.py 2009-03-05 13:18:55 UTC (rev 6067) @@ -0,0 +1,22 @@ +### +# +# Copyright Alan Kennedy. +# +# You may contact the copyright holder at this uri: +# +# http://www.xhaus.com/contact/modjy +# +# The licence under which this code is released is the Apache License v2.0. +# +# The terms and conditions of this license are listed in a file contained +# in the distribution that also contained this file, under the name +# LICENSE.txt. +# +# You may also read a copy of the license at the following web address. +# +# http://modjy.xhaus.com/LICENSE.txt +# +### + +__all__ = ['modjy', 'modjy_exceptions', 'modjy_impl', 'modjy_log', 'modjy_params', 'modjy_publish', 'modjy_response', 'modjy_write', 'modjy_wsgi',] + Added: branches/modjy/Lib/modjy/modjy.py =================================================================== --- branches/modjy/Lib/modjy/modjy.py (rev 0) +++ branches/modjy/Lib/modjy/modjy.py 2009-03-05 13:18:55 UTC (rev 6067) @@ -0,0 +1,121 @@ +### +# +# Copyright Alan Kennedy. +# +# You may contact the copyright holder at this uri: +# +# http://www.xhaus.com/contact/modjy +# +# The licence under which this code is released is the Apache License v2.0. +# +# The terms and conditions of this license are listed in a file contained +# in the distribution that also contained this file, under the name +# LICENSE.txt. +# +# You may also read a copy of the license at the following web address. +# +# http://modjy.xhaus.com/LICENSE.txt +# +### + +import jarray +import synchronize +import sys +import types + +sys.add_package("javax.servlet") +sys.add_package("javax.servlet.http") +sys.add_package("org.python.core") + +from modjy_exceptions import * +from modjy_log import * +from modjy_params import modjy_param_mgr, modjy_servlet_params +from modjy_wsgi import modjy_wsgi +from modjy_response import start_response_object +from modjy_impl import modjy_impl +from modjy_publish import modjy_publisher + +from javax.servlet.http import HttpServlet + +class modjy_servlet(HttpServlet, modjy_publisher, modjy_wsgi, modjy_impl): + + def __init__(self): + HttpServlet.__init__(self) + + def do_param(self, name, value): + if name[:3] == 'log': + getattr(self.log, "set_%s" % name)(value) + else: + self.params[name] = value + + def process_param_container(self, param_container): + param_enum = param_container.getInitParameterNames() + while param_enum.hasMoreElements(): + param_name = param_enum.nextElement() + self.do_param(param_name, param_container.getInitParameter(param_name)) + + def get_params(self): + self.process_param_container(self.servlet_context) + self.process_param_container(self.servlet) + + def init(self, delegator): + self.servlet = delegator + self.servlet_context = self.servlet.getServletContext() + self.servlet_config = self.servlet.getServletConfig() + self.log = modjy_logger(self.servlet_context) + self.params = modjy_param_mgr(modjy_servlet_params) + self.get_params() + self.init_impl() + self.init_publisher() + import modjy_exceptions + self.exc_handler = getattr(modjy_exceptions, '%s_handler' % self.params['exc_handler'])() + + def service (self, req, resp): + wsgi_environ = {} + try: + self.dispatch_to_application(req, resp, wsgi_environ) + except ModjyException, mx: + self.log.error("Exception servicing request: %s" % str(mx)) + typ, value, tb = sys.exc_info()[:] + self.exc_handler.handle(req, resp, wsgi_environ, mx, (typ, value, tb) ) + + def get_j2ee_ns(self, req, resp): + return { + 'servlet': self.servlet, + 'servlet_context': self.servlet_context, + 'servlet_config': self.servlet_config, + 'request': req, + 'response': resp, + } + + def dispatch_to_application(self, req, resp, environ): + app_callable = self.get_app_object(req, environ) + self.set_wsgi_environment(req, resp, environ, self.params, self.get_j2ee_ns(req, resp)) + response_callable = start_response_object(req, resp) + try: + app_return = self.call_application(app_callable, environ, response_callable) + if app_return is None: + raise ReturnNotIterable("Application returned None: must return an iterable") + self.deal_with_app_return(environ, response_callable, app_return) + except ModjyException, mx: + self.raise_exc(mx.__class__, str(mx)) + except Exception, x: + self.raise_exc(ApplicationException, str(x)) + + def call_application(self, app_callable, environ, response_callable): + if self.params['multithread']: + return app_callable.__call__(environ, response_callable) + else: + return synchronize.apply_synchronized( \ + app_callable, \ + app_callable, \ + (environ, response_callable)) + + def expand_relative_path(self, path): + if path.startswith("$"): + return self.servlet.getServletContext().getRealPath(path[1:]) + return path + + def raise_exc(self, exc_class, message): + self.log.error(message) + raise exc_class(message) Added: branches/modjy/Lib/modjy/modjy_exceptions.py =================================================================== --- branches/modjy/Lib/modjy/modjy_exceptions.py (rev 0) +++ branches/modjy/Lib/modjy/modjy_exceptions.py 2009-03-05 13:18:55 UTC (rev 6067) @@ -0,0 +1,91 @@ +### +# +# Copyright Alan Kennedy. +# +# You may contact the copyright holder at this uri: +# +# http://www.xhaus.com/contact/modjy +# +# The licence under which this code is released is the Apache License v2.0. +# +# The terms and conditions of this license are listed in a file contained +# in the distribution that also contained this file, under the name +# LICENSE.txt. +# +# You may also read a copy of the license at the following web address. +# +# http://modjy.xhaus.com/LICENSE.txt +# +### + +import sys +import StringIO +import traceback + +from java.lang import IllegalStateException +from java.io import IOException +from javax.servlet import ServletException + +class ModjyException(Exception): pass + +class ModjyIOException(ModjyException): pass + +class ConfigException(ModjyException): pass +class BadParameter(ConfigException): pass +class ApplicationNotFound(ConfigException): pass +class NoCallable(ConfigException): pass + +class RequestException(ModjyException): pass + +class ApplicationException(ModjyException): pass +class StartResponseNotCalled(ApplicationException): pass +class StartResponseCalledTwice(ApplicationException): pass +class ResponseCommitted(ApplicationException): pass +class HopByHopHeaderSet(ApplicationException): pass +class WrongLength(ApplicationException): pass +class BadArgument(ApplicationException): pass +class ReturnNotIterable(ApplicationException): pass +class NonStringOutput(ApplicationException): pass + +class exception_handler: + + def handle(self, req, resp, environ, exc, exc_info): + pass + + def get_status_and_message(self, req, resp, exc): + return resp.SC_INTERNAL_SERVER_ERROR, "Server configuration error" + +# +# Special exception handler for testing +# + +class testing_handler(exception_handler): + + def handle(self, req, resp, environ, exc, exc_info): + typ, value, tb = exc_info + err_msg = StringIO.StringIO() + err_msg.write("%s: %s\n" % (typ, value,) ) + err_msg.write(">Environment\n") + for k in environ.keys(): + err_msg.write("%s=%s\n" % (k, repr(environ[k])) ) + err_msg.write("<Environment\n") + err_msg.write(">TraceBack\n") + for line in traceback.format_exception(typ, value, tb): + err_msg.write(line) + err_msg.write("<TraceBack\n") + try: + status, message = self.get_status_and_message(req, resp, exc) + resp.setStatus(status) + resp.setContentLength(len(err_msg.getvalue())) + resp.getOutputStream().write(err_msg.getvalue()) + except IllegalStateException, ise: + raise exc # Let the container deal with it + +# +# Standard exception handler +# + +class standard_handler(exception_handler): + + def handle(self, req, resp, environ, exc, exc_info): + raise exc_info[0], exc_info[1], exc_info[2] Added: branches/modjy/Lib/modjy/modjy_impl.py =================================================================== --- branches/modjy/Lib/modjy/modjy_impl.py (rev 0) +++ branches/modjy/Lib/modjy/modjy_impl.py 2009-03-05 13:18:55 UTC (rev 6067) @@ -0,0 +1,101 @@ +### +# +# Copyright Alan Kennedy. +# +# You may contact the copyright holder at this uri: +# +# http://www.xhaus.com/contact/modjy +# +# The licence under which this code is released is the Apache License v2.0. +# +# The terms and conditions of this license are listed in a file contained +# in the distribution that also contained this file, under the name +# LICENSE.txt. +# +# You may also read a copy of the license at the following web address. +# +# http://modjy.xhaus.com/LICENSE.txt +# +### + +import types +import sys + +from modjy_exceptions import * + +class modjy_impl: + + def deal_with_app_return(self, environ, start_response_callable, app_return): + self.log.debug("Processing app return type: %s" % str(type(app_return))) + if isinstance(app_return, types.StringTypes): + raise ReturnNotIterable("Application returned object that was not an iterable: %s" % str(type(app_return))) + if type(app_return) is types.FileType: + pass # TBD: What to do here? can't call fileno() + if hasattr(app_return, '__len__') and callable(app_return.__len__): + expected_pieces = app_return.__len__() + else: + expected_pieces = -1 + try: + try: + ix = 0 + for next_piece in app_return: + if not isinstance(next_piece, types.StringTypes): + raise NonStringOutput("Application returned iterable containing non-strings: %s" % str(type(next_piece))) + if ix == 0: + # The application may have called start_response in the first iteration + if not start_response_callable.called: + raise StartResponseNotCalled("Start_response callable was never called.") + if not start_response_callable.content_length \ + and expected_pieces == 1 \ + and start_response_callable.write_callable.num_writes == 0: + # Take the length of the first piece + start_response_callable.set_content_length(len(next_piece)) + start_response_callable.write_callable(next_piece) + ix += 1 + if ix == expected_pieces: + break + if expected_pieces != -1 and ix != expected_pieces: + raise WrongLength("Iterator len() was wrong. Expected %d pieces: got %d" % (expected_pieces, ix) ) + except AttributeError, ax: + if str(ax) == "__getitem__": + raise ReturnNotIterable("Application returned object that was not an iterable: %s" % str(type(app_return))) + else: + raise ax + except TypeError, tx: + raise ReturnNotIterable("Application returned object that was not an iterable: %s" % str(type(app_return))) + except ModjyException, mx: + raise mx + except Exception, x: + raise ApplicationException(x) + finally: + if hasattr(app_return, 'close') and callable(app_return.close): + app_return.close() + + def init_impl(self): + self.do_j_env_params() + + def add_packages(self, package_list): + packages = [p.strip() for p in package_list.split(';')] + for p in packages: + self.log.info("Adding java package %s to jython" % p) + sys.add_package(p) + + def add_classdirs(self, classdir_list): + classdirs = [cd.strip() for cd in classdir_list.split(';')] + for cd in classdirs: + self.log.info("Adding directory %s to jython class file search path" % cd) + sys.add_classdir(cd) + + def add_extdirs(self, extdir_list): + extdirs = [ed.strip() for ed in extdir_list.split(';')] + for ed in extdirs: + self.log.info("Adding directory %s for .jars and .zips search path" % ed) + sys.add_extdir(self.expand_relative_path(ed)) + + def do_j_env_params(self): + if self.params['packages']: + self.add_packages(self.params['packages']) + if self.params['classdirs']: + self.add_classdirs(self.params['classdirs']) + if self.params['extdirs']: + self.add_extdirs(self.params['extdirs']) Added: branches/modjy/Lib/modjy/modjy_log.py =================================================================== --- branches/modjy/Lib/modjy/modjy_log.py (rev 0) +++ branches/modjy/Lib/modjy/modjy_log.py 2009-03-05 13:18:55 UTC (rev 6067) @@ -0,0 +1,80 @@ +### +# +# Copyright Alan Kennedy. +# +# You may contact the copyright holder at this uri: +# +# http://www.xhaus.com/contact/modjy +# +# The licence under which this code is released is the Apache License v2.0. +# +# The terms and conditions of this license are listed in a file contained +# in the distribution that also contained this file, under the name +# LICENSE.txt. +# +# You may also read a copy of the license at the following web address. +# +# http://modjy.xhaus.com/LICENSE.txt +# +### + +import java + +import sys + +DEBUG = 'debug' +INFO = 'info' +WARN = 'warn' +ERROR = 'error' +FATAL = 'fatal' + +levels_dict = {} +ix = 0 +for level in [DEBUG, INFO, WARN, ERROR, FATAL, ]: + levels_dict[level]=ix + ix += 1 + +class modjy_logger: + + def __init__(self, context): + self.log_ctx = context + self.format_str = "%(lvl)s:\t%(msg)s" + self.log_level = levels_dict[DEBUG] + + def _log(self, level, level_str, msg, exc): + if level >= self.log_level: + msg = self.format_str % {'lvl': level_str, 'msg': msg, } + if exc: +# java.lang.System.err.println(msg, exc) + self.log_ctx.log(msg, exc) + else: +# java.lang.System.err.println(msg) + self.log_ctx.log(msg) + + def debug(self, msg, exc=None): + self._log(0, DEBUG, msg, exc) + + def info(self, msg, exc=None): + self._log(1, INFO, msg, exc) + + def warn(self, msg, exc=None): + self._log(2, WARN, msg, exc) + + def error(self, msg, exc=None): + self._log(3, ERROR, msg, exc) + + def fatal(self, msg, exc=None): + self._log(4, FATAL, msg, exc) + + def set_log_level(self, level_string): + try: + self.log_level = levels_dict[level_string] + except KeyError: + raise BadParameter("Invalid log level: '%s'" % level_string) + + def set_log_format(self, format_string): + # BUG! Format string never actually used in this function. + try: + self._log(debug, "This is a log formatting test", None) + except KeyError: + raise BadParameter("Bad format string: '%s'" % format_string) Added: branches/modjy/Lib/modjy/modjy_params.py =================================================================== --- branches/modjy/Lib/modjy/modjy_params.py (rev 0) +++ branches/modjy/Lib/modjy/modjy_params.py 2009-03-05 13:18:55 UTC (rev 6067) @@ -0,0 +1,84 @@ +### +# +# Copyright Alan Kennedy. +# +# You may contact the copyright holder at this uri: +# +# http://www.xhaus.com/contact/modjy +# +# The licence under which this code is released is the Apache License v2.0. +# +# The terms and conditions of this license are listed in a file contained +# in the distribution that also contained this file, under the name +# LICENSE.txt. +# +# You may also read a copy of the license at the following web address. +# +# http://modjy.xhaus.com/LICENSE.txt +# +### + +from UserDict import UserDict + +BOOLEAN = ('boolean', int) +INTEGER = ('integer', int) +FLOAT = ('float', float) +STRING = ('string', None) + +modjy_servlet_params = { + + 'multithread': (BOOLEAN, 1), + 'cache_callables': (BOOLEAN, 1), + 'reload_on_mod': (BOOLEAN, 0), + + 'app_import_name': (STRING, None), + + 'app_directory': (STRING, None), + 'app_filename': (STRING, 'application.py'), + 'app_callable_name': (STRING, 'handler'), + 'callable_query_name': (STRING, None), + + 'exc_handler': (STRING, 'standard'), + + 'log_level': (STRING, 'info'), + + 'packages': (STRING, None), + 'classdirs': (STRING, None), + 'extdirs': (STRING, None), + + 'initial_env': (STRING, None), +} + +class modjy_param_mgr(UserDict): + + def __init__(self, param_types): + UserDict.__init__(self) + self.param_types = param_types + for pname in self.param_types.keys(): + typ, default = self.param_types[pname] + self.__setitem__(pname, default) + + def __getitem__(self, name): + return self._get_defaulted_value(name) + + def __setitem__(self, name, value): + self.data[name] = self._convert_value(name, value) + + def _convert_value(self, name, value): + if self.param_types.has_key(name): + typ, default = self.param_types[name] + typ_str, typ_func = typ + if typ_func: + try: + return typ_func(value) + except ValueError: + raise BadParameter("Illegal value for %s parameter '%s': %s" % (typ_str, name, value) ) + return value + + def _get_defaulted_value(self, name): + if self.data.has_key(name): + return self.data[name] + if self.param_types.has_key(name): + typ, default = self.param_types[name] + return default + raise KeyError(name) Added: branches/modjy/Lib/modjy/modjy_publish.py =================================================================== --- branches/modjy/Lib/modjy/modjy_publish.py (rev 0) +++ branches/modjy/Lib/modjy/modjy_publish.py 2009-03-05 13:18:55 UTC (rev 6067) @@ -0,0 +1,138 @@ +### +# +# Copyright Alan Kennedy. +# +# You may contact the copyright holder at this uri: +# +# http://www.xhaus.com/contact/modjy +# +# The licence under which this code is released is the Apache License v2.0. +# +# The terms and conditions of this license are listed in a file contained +# in the distribution that also contained this file, under the name +# LICENSE.txt. +# +# You may also read a copy of the license at the following web address. +# +# http://modjy.xhaus.com/LICENSE.txt +# +### + +import sys +import synchronize + +from java.io import File + +from modjy_exceptions import * + +class modjy_publisher: + + def init_publisher(self): + self.cache = None + if self.params['app_directory']: + self.app_directory = self.expand_relative_path(self.params['app_directory']) + else: + self.app_directory = self.servlet_context.getRealPath('/') + self.params['app_directory'] = self.app_directory + if not self.app_directory in sys.path: + sys.path.append(self.app_directory) + + def map_uri(self, req, environ): + source_uri = '%s%s%s' % (self.app_directory, File.separator, self.params['app_filename']) + callable_name = self.params['app_callable_name'] + if self.params['callable_query_name']: + query_string = req.getQueryString() + if query_string and '=' in query_string: + for name_val in query_string.split('&'): + name, value = name_val.split('=') + if name == self.params['callable_query_name']: + callable_name = value + return source_uri, callable_name + + def get_app_object(self, req, environ): + environ["SCRIPT_NAME"] = "%s%s" % (req.getContextPath(), req.getServletPath()) + path_info = req.getPathInfo() or "" + environ["PATH_INFO"] = path_info + environ["PATH_TRANSLATED"] = File(self.app_directory, path_info).getPath() + + if self.params['app_import_name'] is not None: + return self.get_app_object_importable(self.params['app_import_name']) + else: + if self.cache is None: + self.cache = {} + return self.get_app_object_old_style(req, environ) + + get_app_object = synchronize.make_synchronized(get_app_object) + + def get_app_object_importable(self, importable_name): + self.log.debug("Attempting to import application callable '%s'\n" % (importable_name, )) + # Under the importable mechanism, the cache contains a single object + if self.cache is None: + application, instantiable, method_name = self.load_importable(importable_name.strip()) + if instantiable and self.params['cache_callables']: + application = application() + self.cache = application, instantiable, method_name + application, instantiable, method_name = self.cache + self.log.debug("Application is " + str(application)) + if instantiable and not self.params['cache_callables']: + application = application() + self.log.debug("Instantiated application is " + str(application)) + if method_name is not None: + if not hasattr(application, method_name): + self.log.fatal("Attribute error application callable '%s' as no method '%s'" % (application, method_name)) + self.raise_exc(ApplicationNotFound, "Attribute error application callable '%s' as no method '%s'" % (application, method_name)) + application = getattr(application, method_name) + self.log.debug("Application method is " + str(application)) + return application + + def load_importable(self, name): + try: + instantiable = False ; method_name = None + importable_name = name + if name.find('()') != -1: + instantiable = True + importable_name, method_name = name.split('()') + if method_name.startswith('.'): + method_name = method_name[1:] + if not method_name: + method_name = None + module_path, from_name = importable_name.rsplit('.', 1) + imported = __import__(module_path, globals(), locals(), [from_name]) + imported = getattr(imported, from_name) + return imported, instantiable, method_name + except (ImportError, AttributeError), aix: + self.log.fatal("Import error import application callable '%s': %s\n" % (name, str(aix))) + self.raise_exc(ApplicationNotFound, "Failed to import app callable '%s': %s" % (name, str(aix))) + + def get_app_object_old_style(self, req, environ): + source_uri, callable_name = self.map_uri(req, environ) + source_filename = source_uri + if not self.params['cache_callables']: + self.log.debug("Caching of callables disabled") + return self.load_object(source_filename, callable_name) + if not self.cache.has_key( (source_filename, callable_name) ): + self.log.debug("Callable object not in cache: %s#%s" % (source_filename, callable_name) ) + return self.load_object(source_filename, callable_name) + app_callable, last_mod = self.cache.get( (source_filename, callable_name) ) + self.log.debug("Callable object was in cache: %s#%s" % (source_filename, callable_name) ) + if self.params['reload_on_mod']: + f = File(source_filename) + if f.lastModified() > last_mod: + self.log.info("Source file '%s' has been modified: reloading" % source_filename) + return self.load_object(source_filename, callable_name) + return app_callable + + def load_object(self, path, callable_name): + try: + app_ns = {} ; execfile(path, app_ns) + app_callable = app_ns[callable_name] + f = File(path) + self.cache[ (path, callable_name) ] = (app_callable, f.lastModified()) + return app_callable + except IOError, ioe: + self.raise_exc(ApplicationNotFound, "Application filename not found: %s" % path) + except KeyError, k: + self.raise_exc(NoCallable, "No callable named '%s' in %s" % (callable_name, path)) + except Exception, x: + self.raise_exc(NoCallable, "Error loading jython callable '%s': %s" % (callable_name, str(x)) ) + Added: branches/modjy/Lib/modjy/modjy_response.py =================================================================== --- branches/modjy/Lib/modjy/modjy_response.py (rev 0) +++ branches/modjy/Lib/modjy/modjy_response.py 2009-03-05 13:18:55 UTC (rev 6067) @@ -0,0 +1,113 @@ +### +# +# Copyright Alan Kennedy. +# +# You may contact the copyright holder at this uri: +# +# http://www.xhaus.com/contact/modjy +# +# The licence under which this code is released is the Apache License v2.0. +# +# The terms and conditions of this license are listed in a file contained +# in the distribution that also contained this file, under the name +# LICENSE.txt. +# +# You may also read a copy of the license at the following web address. +# +# http://modjy.xhaus.com/LICENSE.txt +# +### + +import types + +from java.lang import System + +from modjy_exceptions import * +from modjy_write import write_object + +# From: http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.5.1 + +hop_by_hop_headers = { + 'connection': None, + 'keep-alive': None, + 'proxy-authenticate': None, + 'proxy-authorization': None, + 'te': None, + 'trailers': None, + 'transfer-encoding': None, + 'upgrade': None, +} + +class start_response_object: + + def __init__(self, req, resp): + self.http_req = req + self.http_resp = resp + self.write_callable = None + self.called = 0 + self.content_length = None + + # I'm doing the parameters this way to facilitate porting back to java + def __call__(self, *args, **keywords): + if len(args) < 2 or len(args) > 3: + raise BadArgument("Start response callback requires either two or three arguments: got %s" % str(args)) + if len(args) == 3: + exc_info = args[2] + try: + try: + self.http_resp.reset() + except IllegalStateException, isx: + raise exc_info[0], exc_info[1], exc_info[2] + finally: + exc_info = None + else: + if self.called > 0: + raise StartResponseCalledTwice("Start response callback may only be called once, without exception information.") + status_str = args[0] + headers_list = args[1] + if not isinstance(status_str, types.StringType): + raise BadArgument("Start response callback requires string as first argument") + if not isinstance(headers_list, types.ListType): + raise BadArgument("Start response callback requires list as second argument") + try: + status_code, status_message_str = status_str.split(" ", 1) + self.http_resp.setStatus(int(status_code)) + except ValueError: + raise BadArgument("Status string must be of the form '<int> <string>'") + self.make_write_object() + try: + for header_name, header_value in headers_list: + header_name_lower = header_name.lower() + if hop_by_hop_headers.has_key(header_name_lower): + raise HopByHopHeaderSet("Under WSGI, it is illegal to set hop-by-hop headers, i.e. '%s'" % header_name) + if header_name_lower == "content-length": + try: + self.set_content_length(int(header_value)) + except ValueError, v: + raise BadArgument("Content-Length header value must be a string containing an integer, not '%s'" % header_value) + else: + final_value = header_value.encode('latin-1') + # Here would be the place to check for control characters, whitespace, etc + self.http_resp.addHeader(header_name, final_value) + except (AttributeError, TypeError), t: + raise BadArgument("Start response callback headers must contain a list of (<string>,<string>) tuples") + except UnicodeError, u: + raise BadArgument("Encoding error: header values may only contain latin-1 characters, not '%s'" % repr(header_value)) + except ValueError, v: + raise BadArgument("Headers list must contain 2-tuples") + self.called += 1 + return self.write_callable + + def set_content_length(self, length): + if self.write_callable.num_writes == 0: + self.content_length = length + self.http_resp.setContentLength(length) + else: + raise ResponseCommitted("Cannot set content-length: response is already commited.") + + def make_write_object(self): + try: + self.write_callable = write_object(self.http_resp.getOutputStream()) + except IOException, iox: + raise IOError(iox) + return self.write_callable Added: branches/modjy/Lib/modjy/modjy_write.py =================================================================== --- branches/modjy/Lib/modjy/modjy_write.py (rev 0) +++ branches/modjy/Lib/modjy/modjy_write.py 2009-03-05 13:18:55 UTC (rev 6067) @@ -0,0 +1,43 @@ +### +# +# Copyright Alan Kennedy. +# +# You may contact the copyright holder at this uri: +# +# http://www.xhaus.com/contact/modjy +# +# The licence under which this code is released is the Apache License v2.0. +# +# The terms and conditions of this license are listed in a file contained +# in the distribution that also contained this file, under the name +# LICENSE.txt. +# +# You may also read a copy of the license at the following web address. +# +# http://modjy.xhaus.com/LICENSE.txt +# +### + +import types + +from modjy_exceptions import * + +class write_object: + + def __init__(self, ostream): + self.ostream = ostream + self.num_writes = 0 + + def __call__(self, *args, **keywords): + if len(args) != 1 or not isinstance(args[0], types.StringTypes): + raise NonStringOutput("Invocation of write callable requires exactly one string argument") + try: + self.ostream.write(args[0]) # Jython implicitly converts the (binary) string to a byte array + # WSGI requires that all output be flushed before returning to the application + # According to the java docs: " The flush method of OutputStream does nothing." + # Still, leave it in place for now: it's in the right place should this + # code ever be ported to another platform. + self.ostream.flush() + self.num_writes += 1 + except Exception, x: + raise ModjyIOException(x) Added: branches/modjy/Lib/modjy/modjy_wsgi.py =================================================================== --- branches/modjy/Lib/modjy/modjy_wsgi.py (rev 0) +++ branches/modjy/Lib/modjy/modjy_wsgi.py 2009-03-05 13:18:55 UTC (rev 6067) @@ -0,0 +1,156 @@ +### +# +# Copyright Alan Kennedy. +# +# You may contact the copyright holder at this uri: +# +# http://www.xhaus.com/contact/modjy +# +# The licence under which this code is released is the Apache License v2.0. +# +# The terms and conditions of this license are listed in a file contained +# in the distribution that also contained this file, under the name +# LICENSE.txt. +# +# You may also read a copy of the license at the following web address. +# +# http://modjy.xhaus.com/LICENSE.txt +# +### + +from java.lang import System + +try: + from org.python.core.util import FileUtil + create_py_file = FileUtil.wrap +except ImportError: + from org.python.core import PyFile + create_py_file = PyFile + +from modjy_exceptions import * + +server_name = "modjy" +server_param_prefix = "%s.param" % server_name +j2ee_ns_prefix = "j2ee" + +cgi_var_char_encoding = "iso-8859-1" + +class modjy_wsgi: + + # + # WSGI constants + # + + empty_pystring = u"" + wsgi_version = (1,0) + + # + # Container-specific constants + # + + modjy_version = (0, 25, 3) + + def set_string_envvar(self, dict, name, value): + if value is None: + value = self.empty_pystring + value = value.encode(cgi_var_char_encoding) + dict[name] = value + + def set_string_envvar_optional(self, dict, name, value, default_value): + if value != default_value: + self.set_string_envvar(dict, name, value) + + def set_int_envvar(self, dict, name, value, default_value): + if value == default_value: + value = self.empty_pystring + else: + value = unicode(value) + self.set_string_envvar(dict, name, value) + + def set_container_specific_wsgi_vars(self, req, resp, dict, params): + dict["%s.version" % server_name] = self.modjy_version + for pname in params.keys(): + dict["%s.%s" % (server_param_prefix, pname)] = params[pname] + + def set_j2ee_specific_wsgi_vars(self, dict, j2ee_ns): + for p in j2ee_ns.keys(): + dict["%s.%s" % (j2ee_ns_prefix, p)] = j2ee_ns[p] + + def set_required_cgi_environ (self, req, resp, dict): + self.set_string_envvar(dict, "REQUEST_METHOD", req.getMethod()) + self.set_string_envvar(dict, "QUERY_STRING", req.getQueryString()) + self.set_string_envvar(dict, "CONTENT_TYPE", req.getContentType()) + self.set_int_envvar(dict, "CONTENT_LENGTH", req.getContentLength(), -1) + self.set_string_envvar(dict, "SERVER_NAME", req.getLocalName()) + self.set_int_envvar(dict, "SERVER_PORT", req.getLocalPort(), 0) + + def set_other_cgi_environ (self, req, resp, dict): + if req.isSecure(): + self.set_string_envvar(dict, "HTTPS", 'on') + else: + self.set_string_envvar(dict, "HTTPS", 'off') + self.set_string_envvar(dict, "SERVER_PROTOCOL", req.getProtocol()) + self.set_string_envvar(dict, "REMOTE_HOST", req.getRemoteHost()) + self.set_string_envvar(dict, "REMOTE_ADDR", req.getRemoteAddr()) + self.set_int_envvar(dict, "REMOTE_PORT", req.getRemotePort(), -1) + self.set_string_envvar_optional(dict, "AUTH_TYPE", req.getAuthType(), None) + self.set_string_envvar_optional(dict, "REMOTE_USER", req.getRemoteUser(), None) + + def set_http_header_environ(self, req, resp, dict): + header_name_enum = req.getHeaderNames() + while header_name_enum.hasMoreElements(): + curr_header_name = header_name_enum.nextElement() + values = None + values_enum = req.getHeaders(curr_header_name) + while values_enum.hasMoreElements(): + next_value = values_enum.nextElement().encode(cgi_var_char_encoding) + if values is None: + values = next_value + else: + if isinstance(values, list): + values.append(next_value) + else: + values = [values] + dict["HTTP_%s" % str(curr_header_name).replace('-', '_').upper()] = values + + def set_required_wsgi_vars(self, req, resp, dict): + dict["wsgi.version"] = self.wsgi_version + dict["wsgi.url_scheme"] = req.getScheme() + dict["wsgi.multithread"] = \ + int(dict["%s.cache_callables" % server_param_prefix]) \ + and \ + int(dict["%s.multithread" % server_param_prefix]) + dict["wsgi.multiprocess"] = self.wsgi_multiprocess = 0 + dict["wsgi.run_once"] = not(dict["%s.cache_callables" % server_param_prefix]) + + def set_wsgi_streams(self, req, resp, dict): + try: + dict["wsgi.input"] = create_py_file(req.getInputStream()) + dict["wsgi.errors"] = create_py_file(System.err) + except IOException, iox: + raise ModjyIOException(iox) + + def set_wsgi_classes(self, req, resp, dict): + # dict["wsgi.file_wrapper"] = modjy_file_wrapper + pass + + def set_user_specified_environment(self, req, resp, wsgi_environ, params): + if not params.has_key('initial_env') or not params['initial_env']: + return + user_env_string = params['initial_env'] + for l in user_env_string.split('\n'): + l = l.strip() + if l: + name, value = l.split(':', 1) + wsgi_environ[name.strip()] = value.strip() + + def set_wsgi_environment(self, req, resp, wsgi_environ, params, j2ee_ns): + self.set_container_specific_wsgi_vars(req, resp, wsgi_environ, params) + self.set_j2ee_specific_wsgi_vars(wsgi_environ, j2ee_ns) + self.set_required_cgi_environ(req, resp, wsgi_environ) + self.set_other_cgi_environ(req, resp, wsgi_environ) + self.set_http_header_environ(req, resp, wsgi_environ) + self.set_required_wsgi_vars(req, resp, wsgi_environ) + self.set_wsgi_streams(req, resp, wsgi_environ) + self.set_wsgi_classes(req, resp, wsgi_environ) + self.set_user_specified_environment(req, resp, wsgi_environ, params) Added: branches/modjy/src/com/xhaus/modjy/ModjyJServlet.java =================================================================== --- branches/modjy/src/com/xhaus/modjy/ModjyJServlet.java (rev 0) +++ branches/modjy/src/com/xhaus/modjy/ModjyJServlet.java 2009-03-05 13:18:55 UTC (rev 6067) @@ -0,0 +1,224 @@ +/*### +# +# Copyright Alan Kennedy. +# +# You may contact the copyright holder at this uri: +# +# http://www.xhaus.com/contact/modjy +# +# The licence under which this code is released is the Apache License v2.0. +# +# The terms and conditions of this license are listed in a file contained +# in the distribution that also contained this file, under the name +# LICENSE.txt. +# +# You may also read a copy of the license at the following web address. +# +# http://modjy.xhaus.com/LICENSE.txt +# +###*/ + +package com.xhaus.modjy; + +import java.io.*; +import java.util.*; +import javax.servlet.*; +import javax.servlet.http.*; +import org.python.core.*; +import org.python.util.*; + +public class ModjyJServlet extends HttpServlet +{ + + protected final static String MODJY_PYTHON_CLASSNAME = "modjy_servlet"; + protected final static String LIB_PYTHON = "/WEB-INF/lib-python"; + protected final static String PTH_FILE_EXTENSION = ".pth"; + + protected PythonInterpreter interp; + protected HttpServlet modjyServlet; + + /** + * Read configuration + * 1. Both context and servlet parameters are included in the set, + * so that the definition of some parameters (e.g python.*) can be shared + * between multiple WSGI servlets. + * 2. servlet params take precedence over context parameters + */ + + protected Properties readConfiguration ( ) + { + Properties props = new Properties(); + // Context parameters + ServletContext context = getServletContext(); + Enumeration e = context.getInitParameterNames(); + while (e.hasMoreElements()) + { + String name = (String) e.nextElement(); + props.put(name, context.getInitParameter(name)); + } + // Servlet parameters override context parameters + e = getInitParameterNames(); + while (e.hasMoreElements()) + { + String name = (String) e.nextElement(); + props.put(name, getInitParameter(name)); + } + return props; + } + + /** + * Initialise the modjy servlet. + * 1. Read the configuration + * 2. Initialise the jython runtime + * 3. Setup, in relation to the J2EE servlet environment + * 4. Create the jython-implemented servlet + * 5. Initialise the jython-implemented servlet + */ + + public void init ( ) + throws ServletException + { + try + { + Properties props = readConfiguration(); + PythonInterpreter.initialize(System.getProperties(), props, new String[0]); + PySystemState systemState = new PySystemState(); + interp = new PythonInterpreter(null, systemState); + String modjyJarLocation = setupEnvironment(interp, props, systemState); + try + { interp.exec("from modjy import "+MODJY_PYTHON_CLASSNAME); } + catch (PyException ix) + { throw new ServletException("Unable to import '"+MODJY_PYTHON_CLASSNAME+"' from "+modjyJarLocation+ + ": do you maybe need to set the 'modjy_jar.location' parameter?", ix);} + PyObject pyServlet = ((PyType)interp.get(MODJY_PYTHON_CLASSNAME)).__call__(); + Object temp = pyServlet.__tojava__(HttpServlet.class); + if (temp == Py.NoConversion) + throw new ServletException("Corrupted modjy file: cannot find definition of '"+MODJY_PYTHON_CLASSNAME+"' class"); + modjyServlet = (HttpServlet) temp; + modjyServlet.init(this); + } + catch (PyException pyx) + { + throw new ServletException("Exception creating modjy servlet: " + pyx.toString(), pyx); + } + } + + /** + * Actually service the incoming request. + * Simply delegate to the jython servlet. + * + * @param request - The incoming HttpServletRequest + * @param response - The outgoing HttpServletResponse + */ + + public void service ( HttpServletRequest req, HttpServletResponse resp ) + throws ServletException, IOException + { + modjyServlet.service(req, resp); + } + + /** + * Setup the modjy environment, i.e. + * 1. Find the location of the modjy.jar file and add it to sys.path + * 2. Process the WEB-INF/lib-python directory, if it exists + * + * @param interp - The PythinInterpreter used to service requests + * @param props - The properties from which config options are found + * @param systemState - The PySystemState corresponding to the interpreter servicing requests + * @returns A String giving the path to the modjy.jar file (which is used only for error reporting) + */ + + protected String setupEnvironment(PythonInterpreter interp, Properties props, PySystemState systemState) + { + String modjyJarLocation = locateModjyJar(props); + systemState.path.append(new PyString(modjyJarLocation)); + processPythonLib(interp, systemState); + return modjyJarLocation; + } + + /** + * Find out the location of "modjy.jar", so that it can + * be added to the sys.path and thus imported + * + * @param The properties from which config options are found + * @returns A String giving the path to the modjy.jar file + */ + + protected String locateModjyJar ( Properties props ) + { + // Give priority to modjy_jar.location + if (props.get("modjy_jar.location") != null) + return (String)props.get("modjy_jar.location"); + // Then try to find it in WEB-INF/lib + String location = getServletContext().getRealPath("/WEB-INF/lib/modjy.jar"); + if (location != null) + { + File f = new File(location); + if (f.exists()) + return location; + } + // Try finding the archive that this class was loaded from + try + { return this.getClass().getProtectionDomain().getCodeSource().getLocation().getFile(); } + catch (Exception x) + { return null;} + } + + /** + * Do all processing in relation to the lib-python subdirectory of WEB-INF + * + * @param interp - The PythinInterpreter used to service requests + * @param systemState - The PySystemState whose path should be updated + */ + + protected void processPythonLib(PythonInterpreter interp, PySystemState systemState) + { + // Add the lib-python directory to sys.path + String pythonLibPath = getServletContext().getRealPath(LIB_PYTHON); + if (pythonLibPath == null) + return; + File pythonLib = new File(pythonLibPath); + if (!pythonLib.exists()) + return; + systemState.path.append(new PyString(pythonLibPath)); + // Now check for .pth files in lib-python and process each one + String[] libPythonContents = pythonLib.list(); + for (int ix = 0 ; ix < libPythonContents.length ; ix++) + if (libPythonContents[ix].endsWith(PTH_FILE_EXTENSION)) + processPthFile(interp, systemState, pythonLibPath, libPythonContents[ix]); + } + + /** + * Process an individual file .pth file in the lib-python directory + * + * @param systemState - The PySystemState whose path should be updated + * @param pythonLibPath - The actual path to the lib-python directory + * @param pthFilename - The PySystemState whose path should be updated + */ + + protected void processPthFile(PythonInterpreter interp, PySystemState systemState, String pythonLibPath, String pthFilename) + { + try + { + LineNumberReader lineReader = new LineNumberReader(new FileReader(new File(pythonLibPath, pthFilename))); + String line; + while ((line = lineReader.readLine()) != null) + { + line = line.trim(); + if (line.length() == 0) + continue; + if (line.startsWith("#")) + continue; + if (line.startsWith("import")) + interp.exec(line); + File archiveFile = new File(pythonLibPath, line); + String archiveRealpath = archiveFile.getAbsolutePath(); + systemState.path.append(new PyString(archiveRealpath)); + } + } + catch (IOException iox) + { + System.err.println("IOException: " + iox.toString()); + } + } +} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fwi...@us...> - 2009-03-06 16:42:05
|
Revision: 6073 http://jython.svn.sourceforge.net/jython/?rev=6073&view=rev Author: fwierzbicki Date: 2009-03-06 16:15:19 +0000 (Fri, 06 Mar 2009) Log Message: ----------- Merged revisions 5752,5756-5758,5761-5763,5765-5775,5778-5816,5818-5840,5842-5847,5854,5857-5859,5863-5865,5869,5875,5877,5884-5885,5889-5893,5900-5901,5903-5906,5908,5912-5918,5920,5923,5925,5927,5930-5932,5934-5947,5950-5951,5953-5957,5959,5961,5965-5966,5971-5976,5978-5979,5981-5983,5992,6001,6003,6006-6014,6023,6031-6037,6039-6040,6045-6047,6049-6052,6061-6065,6071 via svnmerge from https://jython.svn.sourceforge.net/svnroot/jython/trunk/jython Modified Paths: -------------- branches/modjy/.classpath branches/modjy/CPythonLib.includes branches/modjy/CoreExposed.includes branches/modjy/LICENSE.txt branches/modjy/Lib/decimal.py branches/modjy/Lib/grp.py branches/modjy/Lib/marshal.py branches/modjy/Lib/new.py branches/modjy/Lib/os.py branches/modjy/Lib/platform.py branches/modjy/Lib/pwd.py branches/modjy/Lib/pydoc.py branches/modjy/Lib/site.py branches/modjy/Lib/socket.py branches/modjy/Lib/test/regrtest.py branches/modjy/Lib/test/string_tests.py branches/modjy/Lib/test/test_StringIO_jy.py branches/modjy/Lib/test/test_array.py branches/modjy/Lib/test/test_array_jy.py branches/modjy/Lib/test/test_builtin_jy.py branches/modjy/Lib/test/test_class_jy.py branches/modjy/Lib/test/test_cmd_line.py branches/modjy/Lib/test/test_codeop.py branches/modjy/Lib/test/test_descr_jy.py branches/modjy/Lib/test/test_eof_jy.py branches/modjy/Lib/test/test_func_syntax_jy.py branches/modjy/Lib/test/test_genexps_jy.py branches/modjy/Lib/test/test_grammar_jy.py branches/modjy/Lib/test/test_import_jy.py branches/modjy/Lib/test/test_java_integration.py branches/modjy/Lib/test/test_java_visibility.py branches/modjy/Lib/test/test_list_jy.py branches/modjy/Lib/test/test_select.py branches/modjy/Lib/test/test_socket.py branches/modjy/Lib/test/test_support.py branches/modjy/Lib/test/test_sys_jy.py branches/modjy/Lib/test/test_thread_jy.py branches/modjy/Lib/test/test_traceback.py branches/modjy/Lib/test/test_tuple.py branches/modjy/Lib/test/test_unicode_jy.py branches/modjy/Lib/test/test_zlib.py branches/modjy/Lib/threading.py branches/modjy/Lib/zlib.py branches/modjy/README.txt branches/modjy/ast/Python.asdl branches/modjy/ast/asdl_antlr.py branches/modjy/ast/astview.py branches/modjy/bugtests/README.txt branches/modjy/bugtests/test386.py branches/modjy/bugtests/test394.py branches/modjy/bugtests/test394jar/MANIFEST.MF branches/modjy/build.xml branches/modjy/extlibs/jna-posix.jar branches/modjy/grammar/Python.g branches/modjy/grammar/PythonPartial.g branches/modjy/registry branches/modjy/src/com/ziclix/python/sql/handler/RowIdHandler.java branches/modjy/src/org/python/antlr/GrammarActions.java branches/modjy/src/org/python/antlr/PythonTokenSource.java branches/modjy/src/org/python/antlr/adapter/AstAdapters.java branches/modjy/src/org/python/antlr/ast/AssertDerived.java branches/modjy/src/org/python/antlr/ast/AssignDerived.java branches/modjy/src/org/python/antlr/ast/AttributeDerived.java branches/modjy/src/org/python/antlr/ast/AugAssignDerived.java branches/modjy/src/org/python/antlr/ast/BinOpDerived.java branches/modjy/src/org/python/antlr/ast/BoolOpDerived.java branches/modjy/src/org/python/antlr/ast/BreakDerived.java branches/modjy/src/org/python/antlr/ast/CallDerived.java branches/modjy/src/org/python/antlr/ast/ClassDefDerived.java branches/modjy/src/org/python/antlr/ast/CompareDerived.java branches/modjy/src/org/python/antlr/ast/ContinueDerived.java branches/modjy/src/org/python/antlr/ast/DeleteDerived.java branches/modjy/src/org/python/antlr/ast/DictDerived.java branches/modjy/src/org/python/antlr/ast/EllipsisDerived.java branches/modjy/src/org/python/antlr/ast/ExceptHandler.java branches/modjy/src/org/python/antlr/ast/ExceptHandlerDerived.java branches/modjy/src/org/python/antlr/ast/ExecDerived.java branches/modjy/src/org/python/antlr/ast/ExprDerived.java branches/modjy/src/org/python/antlr/ast/ExpressionDerived.java branches/modjy/src/org/python/antlr/ast/ExtSliceDerived.java branches/modjy/src/org/python/antlr/ast/ForDerived.java branches/modjy/src/org/python/antlr/ast/FunctionDefDerived.java branches/modjy/src/org/python/antlr/ast/GeneratorExpDerived.java branches/modjy/src/org/python/antlr/ast/GlobalDerived.java branches/modjy/src/org/python/antlr/ast/IfDerived.java branches/modjy/src/org/python/antlr/ast/IfExpDerived.java branches/modjy/src/org/python/antlr/ast/ImportDerived.java branches/modjy/src/org/python/antlr/ast/ImportFromDerived.java branches/modjy/src/org/python/antlr/ast/IndexDerived.java branches/modjy/src/org/python/antlr/ast/InteractiveDerived.java branches/modjy/src/org/python/antlr/ast/LambdaDerived.java branches/modjy/src/org/python/antlr/ast/ListCompDerived.java branches/modjy/src/org/python/antlr/ast/ListDerived.java branches/modjy/src/org/python/antlr/ast/ModuleDerived.java branches/modjy/src/org/python/antlr/ast/NameDerived.java branches/modjy/src/org/python/antlr/ast/NumDerived.java branches/modjy/src/org/python/antlr/ast/PassDerived.java branches/modjy/src/org/python/antlr/ast/PrintDerived.java branches/modjy/src/org/python/antlr/ast/Raise.java branches/modjy/src/org/python/antlr/ast/RaiseDerived.java branches/modjy/src/org/python/antlr/ast/ReprDerived.java branches/modjy/src/org/python/antlr/ast/ReturnDerived.java branches/modjy/src/org/python/antlr/ast/SliceDerived.java branches/modjy/src/org/python/antlr/ast/StrDerived.java branches/modjy/src/org/python/antlr/ast/SubscriptDerived.java branches/modjy/src/org/python/antlr/ast/SuiteDerived.java branches/modjy/src/org/python/antlr/ast/TryExceptDerived.java branches/modjy/src/org/python/antlr/ast/TryFinallyDerived.java branches/modjy/src/org/python/antlr/ast/TupleDerived.java branches/modjy/src/org/python/antlr/ast/UnaryOpDerived.java branches/modjy/src/org/python/antlr/ast/WhileDerived.java branches/modjy/src/org/python/antlr/ast/WithDerived.java branches/modjy/src/org/python/antlr/ast/YieldDerived.java branches/modjy/src/org/python/antlr/ast/aliasDerived.java branches/modjy/src/org/python/antlr/ast/argumentsDerived.java branches/modjy/src/org/python/antlr/ast/comprehensionDerived.java branches/modjy/src/org/python/antlr/ast/keywordDerived.java branches/modjy/src/org/python/antlr/op/AddDerived.java branches/modjy/src/org/python/antlr/op/AndDerived.java branches/modjy/src/org/python/antlr/op/AugLoadDerived.java branches/modjy/src/org/python/antlr/op/AugStoreDerived.java branches/modjy/src/org/python/antlr/op/BitAndDerived.java branches/modjy/src/org/python/antlr/op/BitOrDerived.java branches/modjy/src/org/python/antlr/op/BitXorDerived.java branches/modjy/src/org/python/antlr/op/DelDerived.java branches/modjy/src/org/python/antlr/op/DivDerived.java branches/modjy/src/org/python/antlr/op/EqDerived.java branches/modjy/src/org/python/antlr/op/FloorDivDerived.java branches/modjy/src/org/python/antlr/op/GtDerived.java branches/modjy/src/org/python/antlr/op/GtEDerived.java branches/modjy/src/org/python/antlr/op/InDerived.java branches/modjy/src/org/python/antlr/op/InvertDerived.java branches/modjy/src/org/python/antlr/op/IsDerived.java branches/modjy/src/org/python/antlr/op/IsNotDerived.java branches/modjy/src/org/python/antlr/op/LShiftDerived.java branches/modjy/src/org/python/antlr/op/LoadDerived.java branches/modjy/src/org/python/antlr/op/LtDerived.java branches/modjy/src/org/python/antlr/op/LtEDerived.java branches/modjy/src/org/python/antlr/op/ModDerived.java branches/modjy/src/org/python/antlr/op/MultDerived.java branches/modjy/src/org/python/antlr/op/NotDerived.java branches/modjy/src/org/python/antlr/op/NotEqDerived.java branches/modjy/src/org/python/antlr/op/NotInDerived.java branches/modjy/src/org/python/antlr/op/OrDerived.java branches/modjy/src/org/python/antlr/op/ParamDerived.java branches/modjy/src/org/python/antlr/op/PowDerived.java branches/modjy/src/org/python/antlr/op/RShiftDerived.java branches/modjy/src/org/python/antlr/op/StoreDerived.java branches/modjy/src/org/python/antlr/op/SubDerived.java branches/modjy/src/org/python/antlr/op/UAddDerived.java branches/modjy/src/org/python/antlr/op/USubDerived.java branches/modjy/src/org/python/compiler/AdapterMaker.java branches/modjy/src/org/python/compiler/ClassFile.java branches/modjy/src/org/python/compiler/Code.java branches/modjy/src/org/python/compiler/CodeCompiler.java branches/modjy/src/org/python/compiler/Constant.java branches/modjy/src/org/python/compiler/Future.java branches/modjy/src/org/python/compiler/JavaMaker.java branches/modjy/src/org/python/compiler/Module.java branches/modjy/src/org/python/compiler/ProxyMaker.java branches/modjy/src/org/python/compiler/ScopeInfo.java branches/modjy/src/org/python/compiler/ScopesCompiler.java branches/modjy/src/org/python/core/AbstractArray.java branches/modjy/src/org/python/core/ArgParser.java branches/modjy/src/org/python/core/AstList.java branches/modjy/src/org/python/core/BaseSet.java branches/modjy/src/org/python/core/BytecodeLoader.java branches/modjy/src/org/python/core/CompilerFlags.java branches/modjy/src/org/python/core/JavaImporter.java branches/modjy/src/org/python/core/Options.java branches/modjy/src/org/python/core/ParserFacade.java branches/modjy/src/org/python/core/Py.java branches/modjy/src/org/python/core/PyArray.java branches/modjy/src/org/python/core/PyArrayDerived.java branches/modjy/src/org/python/core/PyBaseExceptionDerived.java branches/modjy/src/org/python/core/PyBoolean.java branches/modjy/src/org/python/core/PyBooleanDerived.java branches/modjy/src/org/python/core/PyBuiltinMethodNarrow.java branches/modjy/src/org/python/core/PyClassMethod.java branches/modjy/src/org/python/core/PyClassMethodDerived.java branches/modjy/src/org/python/core/PyComplex.java branches/modjy/src/org/python/core/PyComplexDerived.java branches/modjy/src/org/python/core/PyDictionary.java branches/modjy/src/org/python/core/PyDictionaryDerived.java branches/modjy/src/org/python/core/PyEnumerate.java branches/modjy/src/org/python/core/PyEnumerateDerived.java branches/modjy/src/org/python/core/PyException.java branches/modjy/src/org/python/core/PyFile.java branches/modjy/src/org/python/core/PyFileDerived.java branches/modjy/src/org/python/core/PyFloat.java branches/modjy/src/org/python/core/PyFloatDerived.java branches/modjy/src/org/python/core/PyFrame.java branches/modjy/src/org/python/core/PyFrozenSet.java branches/modjy/src/org/python/core/PyFrozenSetDerived.java branches/modjy/src/org/python/core/PyFunction.java branches/modjy/src/org/python/core/PyInstance.java branches/modjy/src/org/python/core/PyInteger.java branches/modjy/src/org/python/core/PyIntegerDerived.java branches/modjy/src/org/python/core/PyIterator.java branches/modjy/src/org/python/core/PyJavaPackage.java branches/modjy/src/org/python/core/PyJavaType.java branches/modjy/src/org/python/core/PyList.java branches/modjy/src/org/python/core/PyListDerived.java branches/modjy/src/org/python/core/PyLong.java branches/modjy/src/org/python/core/PyLongDerived.java branches/modjy/src/org/python/core/PyMethod.java branches/modjy/src/org/python/core/PyMethodDescr.java branches/modjy/src/org/python/core/PyModuleDerived.java branches/modjy/src/org/python/core/PyNewWrapper.java branches/modjy/src/org/python/core/PyObject.java branches/modjy/src/org/python/core/PyObjectDerived.java branches/modjy/src/org/python/core/PyObjectList.java branches/modjy/src/org/python/core/PyProperty.java branches/modjy/src/org/python/core/PyPropertyDerived.java branches/modjy/src/org/python/core/PyReflectedConstructor.java branches/modjy/src/org/python/core/PyReflectedFunction.java branches/modjy/src/org/python/core/PySequence.java branches/modjy/src/org/python/core/PySequenceList.java branches/modjy/src/org/python/core/PySet.java branches/modjy/src/org/python/core/PySetDerived.java branches/modjy/src/org/python/core/PySlice.java branches/modjy/src/org/python/core/PySliceDerived.java branches/modjy/src/org/python/core/PyStaticMethod.java branches/modjy/src/org/python/core/PyString.java branches/modjy/src/org/python/core/PyStringDerived.java branches/modjy/src/org/python/core/PyStringMap.java branches/modjy/src/org/python/core/PySuper.java branches/modjy/src/org/python/core/PySuperDerived.java branches/modjy/src/org/python/core/PySystemState.java branches/modjy/src/org/python/core/PyTableCode.java branches/modjy/src/org/python/core/PyTraceback.java branches/modjy/src/org/python/core/PyTuple.java branches/modjy/src/org/python/core/PyTupleDerived.java branches/modjy/src/org/python/core/PyType.java branches/modjy/src/org/python/core/PyTypeDerived.java branches/modjy/src/org/python/core/PyUnicode.java branches/modjy/src/org/python/core/PyUnicodeDerived.java branches/modjy/src/org/python/core/PyXRange.java branches/modjy/src/org/python/core/ReflectedArgs.java branches/modjy/src/org/python/core/SyspathJavaLoader.java branches/modjy/src/org/python/core/ThreadStateMapping.java branches/modjy/src/org/python/core/__builtin__.java branches/modjy/src/org/python/core/adapter/ClassicPyObjectAdapter.java branches/modjy/src/org/python/core/codecs.java branches/modjy/src/org/python/core/exceptions.java branches/modjy/src/org/python/core/imp.java branches/modjy/src/org/python/core/io/FileIO.java branches/modjy/src/org/python/core/io/IOBase.java branches/modjy/src/org/python/core/io/ServerSocketIO.java branches/modjy/src/org/python/core/packagecache/CachedJarsPackageManager.java branches/modjy/src/org/python/core/packagecache/PackageManager.java branches/modjy/src/org/python/core/packagecache/PathPackageManager.java branches/modjy/src/org/python/expose/BaseTypeBuilder.java branches/modjy/src/org/python/expose/generate/ClassMethodExposer.java branches/modjy/src/org/python/expose/generate/DescriptorExposer.java branches/modjy/src/org/python/expose/generate/ExposeTask.java branches/modjy/src/org/python/expose/generate/ExposedFieldFinder.java branches/modjy/src/org/python/expose/generate/ExposedMethodFinder.java branches/modjy/src/org/python/expose/generate/ExposedTypeProcessor.java branches/modjy/src/org/python/expose/generate/ExposedTypeVisitor.java branches/modjy/src/org/python/expose/generate/Exposer.java branches/modjy/src/org/python/expose/generate/InstanceMethodExposer.java branches/modjy/src/org/python/expose/generate/MethodExposer.java branches/modjy/src/org/python/expose/generate/NewExposer.java branches/modjy/src/org/python/expose/generate/OverridableNewExposer.java branches/modjy/src/org/python/expose/generate/PyTypes.java branches/modjy/src/org/python/expose/generate/RestrictiveAnnotationVisitor.java branches/modjy/src/org/python/expose/generate/TypeExposer.java branches/modjy/src/org/python/modules/ArrayModule.java branches/modjy/src/org/python/modules/Setup.java branches/modjy/src/org/python/modules/_collections/PyDefaultDictDerived.java branches/modjy/src/org/python/modules/_collections/PyDeque.java branches/modjy/src/org/python/modules/_collections/PyDequeDerived.java branches/modjy/src/org/python/modules/_csv/PyDialectDerived.java branches/modjy/src/org/python/modules/_csv/PyWriter.java branches/modjy/src/org/python/modules/_functools/PyPartialDerived.java branches/modjy/src/org/python/modules/_newmodule.java branches/modjy/src/org/python/modules/_py_compile.java branches/modjy/src/org/python/modules/_weakref/GlobalRef.java branches/modjy/src/org/python/modules/_weakref/ReferenceTypeDerived.java branches/modjy/src/org/python/modules/_weakref/WeakrefModule.java branches/modjy/src/org/python/modules/binascii.java branches/modjy/src/org/python/modules/cPickle.java branches/modjy/src/org/python/modules/cStringIO.java branches/modjy/src/org/python/modules/errno.java branches/modjy/src/org/python/modules/imp.java branches/modjy/src/org/python/modules/random/PyRandomDerived.java branches/modjy/src/org/python/modules/random/RandomModule.java branches/modjy/src/org/python/modules/sre/PatternObject.java branches/modjy/src/org/python/modules/struct.java branches/modjy/src/org/python/modules/thread/PyLocal.java branches/modjy/src/org/python/modules/thread/PyLocalDerived.java branches/modjy/src/org/python/modules/time/Time.java branches/modjy/src/org/python/modules/ucnhash.java branches/modjy/src/org/python/modules/zipimport/zipimport.java branches/modjy/src/org/python/modules/zipimport/zipimporter.java branches/modjy/src/org/python/modules/zipimport/zipimporterDerived.java branches/modjy/src/org/python/util/Generic.java branches/modjy/src/org/python/util/InteractiveConsole.java branches/modjy/src/org/python/util/JythoncAntTask.java branches/modjy/src/org/python/util/NameUnionAntType.java branches/modjy/src/org/python/util/jython.java branches/modjy/src/shell/jython branches/modjy/src/shell/jython.bat branches/modjy/src/templates/gderived-defs branches/modjy/src/templates/gderived.py branches/modjy/src/templates/mappings branches/modjy/src/templates/object.derived branches/modjy/tests/java/javatests/ListTest.java branches/modjy/tests/java/javatests/TestSupport.java branches/modjy/tests/java/org/python/expose/generate/DescriptorExposerTest.java branches/modjy/tests/java/org/python/expose/generate/ExposeMethodFinderTest.java branches/modjy/tests/java/org/python/expose/generate/ExposedTypeProcessorTest.java branches/modjy/tests/java/org/python/expose/generate/ExposedTypeVisitorTest.java branches/modjy/tests/java/org/python/expose/generate/MethodExposerTest.java branches/modjy/tests/java/org/python/expose/generate/NewExposerTest.java branches/modjy/tests/java/org/python/expose/generate/OverridableNewExposerTest.java branches/modjy/tests/java/org/python/expose/generate/TypeExposerTest.java branches/modjy/tests/java/org/python/tests/Callbacker.java branches/modjy/tests/java/org/python/tests/Invisible.java branches/modjy/tests/java/org/python/tests/SubVisible.java branches/modjy/tests/java/org/python/tests/VisibilityResults.java branches/modjy/tests/java/org/python/tests/Visible.java branches/modjy/tests/java/org/python/util/InterpreterTest.java Added Paths: ----------- branches/modjy/Lib/asyncore.py branches/modjy/Lib/pycimport.py branches/modjy/Lib/pyexpat.py branches/modjy/Lib/signal.py branches/modjy/Lib/test/access_protected_class.py branches/modjy/Lib/test/access_protected_field.py branches/modjy/Lib/test/anygui.py branches/modjy/Lib/test/bug1239.jar branches/modjy/Lib/test/call_protected_method.py branches/modjy/Lib/test/check_for_initializer_in_syspath.py branches/modjy/Lib/test/classimport.jar branches/modjy/Lib/test/classimport_Lib.jar branches/modjy/Lib/test/eof_fodder7.py branches/modjy/Lib/test/except_in_raising_code.py branches/modjy/Lib/test/import_nonexistent.py branches/modjy/Lib/test/import_star_from_java.py branches/modjy/Lib/test/invalid_utf_8_declared_encoding.py branches/modjy/Lib/test/latin1_no_encoding.py branches/modjy/Lib/test/output/test_signal branches/modjy/Lib/test/python_home.policy branches/modjy/Lib/test/sys_jy_test_module.py branches/modjy/Lib/test/syspath_import.jar branches/modjy/Lib/test/test_classpathimporter.py branches/modjy/Lib/test/test_codeop_jy.py branches/modjy/Lib/test/test_compile_jy.py branches/modjy/Lib/test/test_doctest.py branches/modjy/Lib/test/test_int_jy.py branches/modjy/Lib/test/test_java_subclasses.py branches/modjy/Lib/test/test_jython_initializer.py branches/modjy/Lib/test/test_listcomp_jy.py branches/modjy/Lib/test/test_marshal.py branches/modjy/Lib/test/test_new.py branches/modjy/Lib/test/test_pep263_jy.py branches/modjy/Lib/test/test_sax_jy.py branches/modjy/Lib/test/test_set_jy.py branches/modjy/Lib/test/test_signal.py branches/modjy/Lib/test/test_timeit.py branches/modjy/Lib/test/test_traceback_jy.py branches/modjy/Lib/test/test_xml_etree.py branches/modjy/Lib/test/test_xml_etree_c.py branches/modjy/Lib/test/test_xml_etree_jy.py branches/modjy/Lib/test/test_zipimport_jy.py branches/modjy/Lib/timeit.py branches/modjy/Lib/xml/etree/ branches/modjy/Lib/xml/etree/cElementTree.py branches/modjy/Lib/xml/parsers/ branches/modjy/Lib/xml/parsers/__init__.py branches/modjy/Lib/xml/parsers/expat.py branches/modjy/Misc/make_pydocs.py branches/modjy/Tools/pbcvm/ branches/modjy/Tools/pbcvm/extract.py branches/modjy/extlibs/antlr-3.1.2.jar branches/modjy/extlibs/antlr-runtime-3.1.2.jar branches/modjy/extlibs/cpptasks/ branches/modjy/extlibs/cpptasks/cpptasks.jar branches/modjy/extlibs/modjy_0_25_3.zip branches/modjy/extlibs/xercesImpl-2.9.1.jar branches/modjy/src/org/python/compiler/MTime.java branches/modjy/src/org/python/compiler/pbc/ branches/modjy/src/org/python/compiler/pbc/Bytecode.java branches/modjy/src/org/python/compiler/pbc/BytecodeCompiler.java branches/modjy/src/org/python/core/AnnotationReader.java branches/modjy/src/org/python/core/BuiltinDocs.java branches/modjy/src/org/python/core/ClasspathPyImporter.java branches/modjy/src/org/python/core/ClasspathPyImporterDerived.java branches/modjy/src/org/python/core/JythonInitializer.java branches/modjy/src/org/python/core/Opcode.java branches/modjy/src/org/python/core/PyBaseCode.java branches/modjy/src/org/python/core/PyBytecode.java branches/modjy/src/org/python/core/WrappedIterIterator.java branches/modjy/src/org/python/core/util/importer.java branches/modjy/src/org/python/modules/PyIOFile.java branches/modjy/src/org/python/modules/PyIOFileFactory.java branches/modjy/src/org/python/modules/_marshal.java branches/modjy/src/org/python/util/GlobMatchingTask.java branches/modjy/src/org/python/util/JycompileAntTask.java branches/modjy/src/templates/ClasspathPyImporter.derived branches/modjy/tests/data/ branches/modjy/tests/data/initializer/ branches/modjy/tests/data/initializer/META-INF/ branches/modjy/tests/data/initializer/META-INF/services/ branches/modjy/tests/data/initializer/META-INF/services/org.python.core.JythonInitializer branches/modjy/tests/data/initializer/SyspathAppendingInitializer.java branches/modjy/tests/java/javatests/PySetInJavaTest.java branches/modjy/tests/java/org/python/tests/BadStaticInitializer.java branches/modjy/tests/java/org/python/tests/BeanImplementation.java branches/modjy/tests/java/org/python/tests/BeanInterface.java branches/modjy/tests/java/org/python/tests/Child.java branches/modjy/tests/java/org/python/tests/Coercions.java branches/modjy/tests/java/org/python/tests/CustomizableMapHolder.java branches/modjy/tests/java/org/python/tests/ExceptionTest.java branches/modjy/tests/java/org/python/tests/HiddenSuper.java branches/modjy/tests/java/org/python/tests/Matryoshka.java branches/modjy/tests/java/org/python/tests/OnlySubclassable.java branches/modjy/tests/java/org/python/tests/OtherSubVisible.java branches/modjy/tests/java/org/python/tests/Parent.java branches/modjy/tests/java/org/python/tests/SomePyMethods.java branches/modjy/tests/java/org/python/tests/inbred/ branches/modjy/tests/java/org/python/tests/inbred/Metis.java branches/modjy/tests/java/org/python/tests/inbred/Zeus.java branches/modjy/tests/java/org/python/tests/mro/ branches/modjy/tests/java/org/python/tests/mro/ConfusedOnGetitemAdd.java branches/modjy/tests/java/org/python/tests/mro/ConfusedOnImport.java branches/modjy/tests/java/org/python/tests/mro/FirstAndPost.java branches/modjy/tests/java/org/python/tests/mro/FirstAndSecond.java branches/modjy/tests/java/org/python/tests/mro/FirstPredefinedGetitem.java branches/modjy/tests/java/org/python/tests/mro/GetitemAdder.java branches/modjy/tests/java/org/python/tests/mro/PostAndFirst.java branches/modjy/tests/java/org/python/tests/mro/PostdefinedGetitem.java branches/modjy/tests/java/org/python/tests/mro/SecondAndFirst.java branches/modjy/tests/java/org/python/tests/mro/SecondPredefinedGetitem.java Removed Paths: ------------- branches/modjy/Lib/asyncore.py branches/modjy/Lib/test/test_bool.py branches/modjy/Lib/test/test_exceptions.py branches/modjy/Lib/test/test_jsubclass.py branches/modjy/Lib/test/test_jy_compile.py branches/modjy/Lib/xml/etree/cElementTree.py branches/modjy/Lib/xml/parsers/__init__.py branches/modjy/Lib/xml/parsers/expat.py branches/modjy/Tools/pbcvm/extract.py branches/modjy/bugtests/classes/test090j.java branches/modjy/bugtests/classes/test092m/ branches/modjy/bugtests/classes/test119j.java branches/modjy/bugtests/classes/test121p/ branches/modjy/bugtests/classes/test139j1.java branches/modjy/bugtests/classes/test139j2.java branches/modjy/bugtests/classes/test139j3.java branches/modjy/bugtests/classes/test142j.java branches/modjy/bugtests/classes/test160j1.java branches/modjy/bugtests/classes/test160j2.java branches/modjy/bugtests/classes/test182j.java branches/modjy/bugtests/classes/test202j.java branches/modjy/bugtests/classes/test204j0.java branches/modjy/bugtests/classes/test204j1.java branches/modjy/bugtests/classes/test204j2.java branches/modjy/bugtests/classes/test204j3.java branches/modjy/bugtests/classes/test205j0.java branches/modjy/bugtests/classes/test205j1.java branches/modjy/bugtests/classes/test205j2.java branches/modjy/bugtests/classes/test206j0.java branches/modjy/bugtests/classes/test206j1.java branches/modjy/bugtests/classes/test208j.java branches/modjy/bugtests/classes/test208j0.java branches/modjy/bugtests/classes/test208j1.java branches/modjy/bugtests/classes/test208j2.java branches/modjy/bugtests/classes/test217p/ branches/modjy/bugtests/classes/test219e.java branches/modjy/bugtests/classes/test219i.java branches/modjy/bugtests/classes/test219j.java branches/modjy/bugtests/classes/test220e.java branches/modjy/bugtests/classes/test220i.java branches/modjy/bugtests/classes/test220j.java branches/modjy/bugtests/classes/test231j.java branches/modjy/bugtests/classes/test231j2.java branches/modjy/bugtests/classes/test232p/ branches/modjy/bugtests/classes/test236j1.java branches/modjy/bugtests/classes/test236j2.java branches/modjy/bugtests/classes/test246p/ branches/modjy/bugtests/classes/test248j.java branches/modjy/bugtests/classes/test288i.java branches/modjy/bugtests/classes/test288j.java branches/modjy/bugtests/classes/test395j1.java branches/modjy/bugtests/classes/test395j2.java branches/modjy/bugtests/classes/test396j.java branches/modjy/bugtests/test087.py branches/modjy/bugtests/test087m.py branches/modjy/bugtests/test088.py branches/modjy/bugtests/test088p/ branches/modjy/bugtests/test090.py branches/modjy/bugtests/test091.py branches/modjy/bugtests/test091j.java branches/modjy/bugtests/test092.py branches/modjy/bugtests/test093.py branches/modjy/bugtests/test094.py branches/modjy/bugtests/test100.py branches/modjy/bugtests/test100j.java branches/modjy/bugtests/test101.py branches/modjy/bugtests/test104.py branches/modjy/bugtests/test114.py branches/modjy/bugtests/test116.py branches/modjy/bugtests/test117.py branches/modjy/bugtests/test117j.java branches/modjy/bugtests/test119.py branches/modjy/bugtests/test120.py branches/modjy/bugtests/test121.py branches/modjy/bugtests/test122.py branches/modjy/bugtests/test122p/ branches/modjy/bugtests/test123.py branches/modjy/bugtests/test123j.java branches/modjy/bugtests/test125m.py branches/modjy/bugtests/test129.py branches/modjy/bugtests/test129j.java branches/modjy/bugtests/test132.py branches/modjy/bugtests/test132j.java branches/modjy/bugtests/test132m.py branches/modjy/bugtests/test137.py branches/modjy/bugtests/test137j.java branches/modjy/bugtests/test145.py branches/modjy/bugtests/test146.py branches/modjy/bugtests/test147.py branches/modjy/bugtests/test148.py branches/modjy/bugtests/test149.py branches/modjy/bugtests/test150.py branches/modjy/bugtests/test151.py branches/modjy/bugtests/test152.py branches/modjy/bugtests/test153.py branches/modjy/bugtests/test154.py branches/modjy/bugtests/test154p/ branches/modjy/bugtests/test155.py branches/modjy/bugtests/test156.py branches/modjy/bugtests/test157.py branches/modjy/bugtests/test157j.java branches/modjy/bugtests/test158.py branches/modjy/bugtests/test159.py branches/modjy/bugtests/test160.py branches/modjy/bugtests/test161.py branches/modjy/bugtests/test162.py branches/modjy/bugtests/test162m.py branches/modjy/bugtests/test163.py branches/modjy/bugtests/test164.py branches/modjy/bugtests/test165.py branches/modjy/bugtests/test166.py branches/modjy/bugtests/test167.py branches/modjy/bugtests/test168.py branches/modjy/bugtests/test168p/ branches/modjy/bugtests/test169.py branches/modjy/bugtests/test169c.py branches/modjy/bugtests/test170.py branches/modjy/bugtests/test170p/ branches/modjy/bugtests/test171.py branches/modjy/bugtests/test171p/ branches/modjy/bugtests/test172.py branches/modjy/bugtests/test172j.java branches/modjy/bugtests/test173.py branches/modjy/bugtests/test173p/ branches/modjy/bugtests/test174.py branches/modjy/bugtests/test175.py branches/modjy/bugtests/test176.py branches/modjy/bugtests/test177.py branches/modjy/bugtests/test178.py branches/modjy/bugtests/test179.py branches/modjy/bugtests/test180.py branches/modjy/bugtests/test181.py branches/modjy/bugtests/test182.py branches/modjy/bugtests/test182c.py branches/modjy/bugtests/test183.py branches/modjy/bugtests/test184.py branches/modjy/bugtests/test184s1.py branches/modjy/bugtests/test184s2.py branches/modjy/bugtests/test185.html branches/modjy/bugtests/test185.py branches/modjy/bugtests/test185a.py branches/modjy/bugtests/test185m.py branches/modjy/bugtests/test186.html branches/modjy/bugtests/test186.py branches/modjy/bugtests/test186a.py branches/modjy/bugtests/test187.py branches/modjy/bugtests/test187c.py branches/modjy/bugtests/test188.py branches/modjy/bugtests/test188c.py branches/modjy/bugtests/test189.py branches/modjy/bugtests/test189c.py branches/modjy/bugtests/test190.py branches/modjy/bugtests/test190c.py branches/modjy/bugtests/test191.py branches/modjy/bugtests/test191c.py branches/modjy/bugtests/test192.html branches/modjy/bugtests/test192.py branches/modjy/bugtests/test192c.py branches/modjy/bugtests/test192c1.py branches/modjy/bugtests/test192c2.py branches/modjy/bugtests/test193.py branches/modjy/bugtests/test193c.py branches/modjy/bugtests/test194.html branches/modjy/bugtests/test194.py branches/modjy/bugtests/test194c.py branches/modjy/bugtests/test194m/ branches/modjy/bugtests/test195.py branches/modjy/bugtests/test195c.py branches/modjy/bugtests/test196.py branches/modjy/bugtests/test196c.py branches/modjy/bugtests/test197.py branches/modjy/bugtests/test197c.py branches/modjy/bugtests/test198.py branches/modjy/bugtests/test198c.py branches/modjy/bugtests/test199.py branches/modjy/bugtests/test199c.py branches/modjy/bugtests/test200.py branches/modjy/bugtests/test200p1.py branches/modjy/bugtests/test201.py branches/modjy/bugtests/test201c.py branches/modjy/bugtests/test202.py branches/modjy/bugtests/test203.py branches/modjy/bugtests/test204.py branches/modjy/bugtests/test205.py branches/modjy/bugtests/test206.py branches/modjy/bugtests/test207.py branches/modjy/bugtests/test208.py branches/modjy/bugtests/test209.py branches/modjy/bugtests/test209p/ branches/modjy/bugtests/test210.py branches/modjy/bugtests/test211.py branches/modjy/bugtests/test212.py branches/modjy/bugtests/test213.py branches/modjy/bugtests/test214.html branches/modjy/bugtests/test214.py branches/modjy/bugtests/test214a.py branches/modjy/bugtests/test215.py branches/modjy/bugtests/test216.py branches/modjy/bugtests/test216s1.py branches/modjy/bugtests/test217.py branches/modjy/bugtests/test217c.py branches/modjy/bugtests/test217t.java branches/modjy/bugtests/test218.py branches/modjy/bugtests/test218c.py branches/modjy/bugtests/test219.py branches/modjy/bugtests/test220.py branches/modjy/bugtests/test220c.py branches/modjy/bugtests/test221.py branches/modjy/bugtests/test221c.py branches/modjy/bugtests/test222.py branches/modjy/bugtests/test222s.py branches/modjy/bugtests/test223.py branches/modjy/bugtests/test223s.py branches/modjy/bugtests/test224.py branches/modjy/bugtests/test224s.py branches/modjy/bugtests/test225.py branches/modjy/bugtests/test225s.py branches/modjy/bugtests/test226.py branches/modjy/bugtests/test226c.py branches/modjy/bugtests/test227.py branches/modjy/bugtests/test227c.py branches/modjy/bugtests/test228.py branches/modjy/bugtests/test228s.py branches/modjy/bugtests/test229.py branches/modjy/bugtests/test229c.py branches/modjy/bugtests/test230.py branches/modjy/bugtests/test231.py branches/modjy/bugtests/test232.py branches/modjy/bugtests/test233.py branches/modjy/bugtests/test234.py branches/modjy/bugtests/test235.py branches/modjy/bugtests/test235p/ branches/modjy/bugtests/test237.py branches/modjy/bugtests/test237m1.py branches/modjy/bugtests/test237m2.py branches/modjy/bugtests/test238.py branches/modjy/bugtests/test239.py branches/modjy/bugtests/test240.py branches/modjy/bugtests/test242.py branches/modjy/bugtests/test242c.py branches/modjy/bugtests/test245.py branches/modjy/bugtests/test245j.java branches/modjy/bugtests/test246.py branches/modjy/bugtests/test246c.py branches/modjy/bugtests/test247.py branches/modjy/bugtests/test247j.java branches/modjy/bugtests/test248.py branches/modjy/bugtests/test249.py branches/modjy/bugtests/test249c.py branches/modjy/bugtests/test250.py branches/modjy/bugtests/test250j.java branches/modjy/bugtests/test251.py branches/modjy/bugtests/test251c.py branches/modjy/bugtests/test251c2.py branches/modjy/bugtests/test252.py branches/modjy/bugtests/test252c.py branches/modjy/bugtests/test252c2.py branches/modjy/bugtests/test253.py branches/modjy/bugtests/test253c.py branches/modjy/bugtests/test253c2.py branches/modjy/bugtests/test254.html branches/modjy/bugtests/test254.py branches/modjy/bugtests/test254c.py branches/modjy/bugtests/test255.py branches/modjy/bugtests/test255s1.py branches/modjy/bugtests/test255s2.py branches/modjy/bugtests/test256.html branches/modjy/bugtests/test256.py branches/modjy/bugtests/test256a.py branches/modjy/bugtests/test257.py branches/modjy/bugtests/test258.py branches/modjy/bugtests/test258m1.py branches/modjy/bugtests/test259.py branches/modjy/bugtests/test259s.py branches/modjy/bugtests/test260.py branches/modjy/bugtests/test261.py branches/modjy/bugtests/test261p/ branches/modjy/bugtests/test262.py branches/modjy/bugtests/test262m.py branches/modjy/bugtests/test262p/ branches/modjy/bugtests/test263.py branches/modjy/bugtests/test263m.py branches/modjy/bugtests/test264.py branches/modjy/bugtests/test264c.py branches/modjy/bugtests/test265.py branches/modjy/bugtests/test265j.java branches/modjy/bugtests/test266.py branches/modjy/bugtests/test268.py branches/modjy/bugtests/test268j1.java branches/modjy/bugtests/test268j2.java branches/modjy/bugtests/test269.py branches/modjy/bugtests/test269p/ branches/modjy/bugtests/test270.py branches/modjy/bugtests/test270p/ branches/modjy/bugtests/test271.py branches/modjy/bugtests/test272.py branches/modjy/bugtests/test272c.py branches/modjy/bugtests/test273.py branches/modjy/bugtests/test273p/ branches/modjy/bugtests/test274.py branches/modjy/bugtests/test275.py branches/modjy/bugtests/test275s.py branches/modjy/bugtests/test276.py branches/modjy/bugtests/test276j.java branches/modjy/bugtests/test277.py branches/modjy/bugtests/test277p/ branches/modjy/bugtests/test278.py branches/modjy/bugtests/test278p/ branches/modjy/bugtests/test280.py branches/modjy/bugtests/test280c.py branches/modjy/bugtests/test281.py branches/modjy/bugtests/test281c.py branches/modjy/bugtests/test282.py branches/modjy/bugtests/test284.py branches/modjy/bugtests/test284j1.java branches/modjy/bugtests/test284j2.java branches/modjy/bugtests/test285.py branches/modjy/bugtests/test286.py branches/modjy/bugtests/test286c.py branches/modjy/bugtests/test287.py branches/modjy/bugtests/test288.py branches/modjy/bugtests/test289.py branches/modjy/bugtests/test289c.py branches/modjy/bugtests/test290.py branches/modjy/bugtests/test291.py branches/modjy/bugtests/test292.policy branches/modjy/bugtests/test292.py branches/modjy/bugtests/test293.py branches/modjy/bugtests/test293p/ branches/modjy/bugtests/test294.py branches/modjy/bugtests/test294j.java branches/modjy/bugtests/test295.py branches/modjy/bugtests/test296.py branches/modjy/bugtests/test296p/ branches/modjy/bugtests/test297.py branches/modjy/bugtests/test297c.py branches/modjy/bugtests/test298.py branches/modjy/bugtests/test298m1.py branches/modjy/bugtests/test299.py branches/modjy/bugtests/test300.py branches/modjy/bugtests/test301.py branches/modjy/bugtests/test301c.py branches/modjy/bugtests/test302.py branches/modjy/bugtests/test303.py branches/modjy/bugtests/test303j.java branches/modjy/bugtests/test304.py branches/modjy/bugtests/test304m.py branches/modjy/bugtests/test307.py branches/modjy/bugtests/test307foobar.template branches/modjy/bugtests/test307m.template branches/modjy/bugtests/test307p.template branches/modjy/bugtests/test308.py branches/modjy/bugtests/test308d/ branches/modjy/bugtests/test309.py branches/modjy/bugtests/test310.py branches/modjy/bugtests/test310c.py branches/modjy/bugtests/test311.py branches/modjy/bugtests/test312.py branches/modjy/bugtests/test313.py branches/modjy/bugtests/test313c.py branches/modjy/bugtests/test314.py branches/modjy/bugtests/test314c.py branches/modjy/bugtests/test315.py branches/modjy/bugtests/test315c.py branches/modjy/bugtests/test316.py branches/modjy/bugtests/test317.py branches/modjy/bugtests/test317c.py branches/modjy/bugtests/test318.py branches/modjy/bugtests/test319.py branches/modjy/bugtests/test319j.java branches/modjy/bugtests/test320.py branches/modjy/bugtests/test366.py branches/modjy/bugtests/test373.py branches/modjy/bugtests/test389.py branches/modjy/bugtests/test391.py branches/modjy/bugtests/test395.py branches/modjy/bugtests/test396.py branches/modjy/extlibs/antlr-3.1.1-runtime.jar branches/modjy/extlibs/antlr-3.1.1.jar branches/modjy/extlibs/cpptasks/cpptasks.jar branches/modjy/extlibs/modjy_0_22_3.zip branches/modjy/src/org/python/compiler/pbc/Bytecode.java branches/modjy/src/org/python/compiler/pbc/BytecodeCompiler.java branches/modjy/src/org/python/core/APIReader.java branches/modjy/src/org/python/core/PySetIterator.java branches/modjy/tests/data/initializer/ branches/modjy/tests/data/initializer/META-INF/ branches/modjy/tests/data/initializer/META-INF/services/ branches/modjy/tests/data/initializer/META-INF/services/org.python.core.JythonInitializer branches/modjy/tests/data/initializer/SyspathAppendingInitializer.java branches/modjy/tests/java/javatests/MethodInvokationTest.java branches/modjy/tests/java/org/python/tests/inbred/Metis.java branches/modjy/tests/java/org/python/tests/inbred/Zeus.java branches/modjy/tests/java/org/python/tests/mro/ConfusedOnGetitemAdd.java branches/modjy/tests/java/org/python/tests/mro/ConfusedOnImport.java branches/modjy/tests/java/org/python/tests/mro/FirstAndPost.java branches/modjy/tests/java/org/python/tests/mro/FirstAndSecond.java branches/modjy/tests/java/org/python/tests/mro/FirstPredefinedGetitem.java branches/modjy/tests/java/org/python/tests/mro/GetitemAdder.java branches/modjy/tests/java/org/python/tests/mro/PostAndFirst.java branches/modjy/tests/java/org/python/tests/mro/PostdefinedGetitem.java branches/modjy/tests/java/org/python/tests/mro/SecondAndFirst.java branches/modjy/tests/java/org/python/tests/mro/SecondPredefinedGetitem.java Property Changed: ---------------- branches/modjy/ Property changes on: branches/modjy ___________________________________________________________________ Modified: svn:externals - CPythonLib http://svn.python.org/projects/python/branches/release25-maint/Lib/ + CPythonLib -r70085 http://svn.python.org/projects/python/branches/release25-maint/Lib/ Modified: svnmerge-integrated - /trunk/jython:1-5749 + /trunk/jython:1-6072 Modified: branches/modjy/.classpath =================================================================== --- branches/modjy/.classpath 2009-03-06 15:21:04 UTC (rev 6072) +++ branches/modjy/.classpath 2009-03-06 16:15:19 UTC (rev 6073) @@ -12,8 +12,10 @@ <classpathentry kind="lib" path="extlibs/mysql-connector-java-5.1.6.jar"/> <classpathentry kind="lib" path="extlibs/postgresql-8.3-603.jdbc4.jar"/> <classpathentry kind="lib" path="extlibs/servlet-api-2.5.jar"/> - <classpathentry kind="lib" path="build/jarjar"/> <classpathentry kind="var" path="ANT_HOME/lib/ant.jar"/> - <classpathentry kind="lib" path="extlibs/antlr-3.1.1-runtime.jar"/> + <classpathentry kind="lib" path="extlibs/antlr-runtime-3.1.2.jar"/> + <classpathentry kind="lib" path="extlibs/asm-3.1.jar"/> + <classpathentry kind="lib" path="extlibs/asm-commons-3.1.jar"/> + <classpathentry kind="lib" path="extlibs/constantine-0.4.jar"/> <classpathentry kind="output" path="bugtests/classes"/> </classpath> Modified: branches/modjy/CPythonLib.includes =================================================================== --- branches/modjy/CPythonLib.includes 2009-03-06 15:21:04 UTC (rev 6072) +++ branches/modjy/CPythonLib.includes 2009-03-06 16:15:19 UTC (rev 6073) @@ -8,6 +8,7 @@ encodings/** logging/* test/** +xml/etree/** # Lib files, in alphabetical order: __future__.py @@ -51,6 +52,8 @@ DocXMLRPCServer.py dospath.py dumbdbm.py +dummy_thread.py +dummy_threading.py exceptions.py fileinput.py fnmatch.py Modified: branches/modjy/CoreExposed.includes =================================================================== --- branches/modjy/CoreExposed.includes 2009-03-06 15:21:04 UTC (rev 6072) +++ branches/modjy/CoreExposed.includes 2009-03-06 16:15:19 UTC (rev 6073) @@ -1,4 +1,5 @@ org/python/core/AstList.class +org/python/core/ClasspathPyImporter.class org/python/core/PyArray.class org/python/core/PyBaseString.class org/python/core/PyBaseException.class @@ -33,6 +34,7 @@ org/python/core/PyStaticMethod.class org/python/core/PyString.class org/python/core/PySuper.class +org/python/core/PyTraceback.class org/python/core/PyTuple.class org/python/core/PyType.class org/python/core/PyUnicode.class Modified: branches/modjy/LICENSE.txt =================================================================== --- branches/modjy/LICENSE.txt 2009-03-06 15:21:04 UTC (rev 6072) +++ branches/modjy/LICENSE.txt 2009-03-06 16:15:19 UTC (rev 6073) @@ -53,7 +53,7 @@ Jython 2.0, 2.1 License ================================ -Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Jython Developers +Copyright (c) 2000-2009 Jython Developers. All rights reserved. Redistribution and use in source and binary forms, with or without Deleted: branches/modjy/Lib/asyncore.py =================================================================== --- branches/modjy/Lib/asyncore.py 2009-03-06 15:21:04 UTC (rev 6072) +++ branches/modjy/Lib/asyncore.py 2009-03-06 16:15:19 UTC (rev 6073) @@ -1,561 +0,0 @@ -# -*- Mode: Python -*- -# Id: asyncore.py,v 2.51 2000/09/07 22:29:26 rushing Exp -# Author: Sam Rushing <ru...@ni...> - -# ====================================================================== -# Copyright 1996 by Sam Rushing -# -# All Rights Reserved -# -# Permission to use, copy, modify, and distribute this software and -# its documentation for any purpose and without fee is hereby -# granted, provided that the above copyright notice appear in all -# copies and that both that copyright notice and this permission -# notice appear in supporting documentation, and that the name of Sam -# Rushing not be used in advertising or publicity pertaining to -# distribution of the software without specific, written prior -# permission. -# -# SAM RUSHING DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN -# NO EVENT SHALL SAM RUSHING BE LIABLE FOR ANY SPECIAL, INDIRECT OR -# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS -# OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, -# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN -# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -# ====================================================================== - -"""Basic infrastructure for asynchronous socket service clients and servers. - -There are only two ways to have a program on a single processor do "more -than one thing at a time". Multi-threaded programming is the simplest and -most popular way to do it, but there is another very different technique, -that lets you have nearly all the advantages of multi-threading, without -actually using multiple threads. it's really only practical if your program -is largely I/O bound. If your program is CPU bound, then pre-emptive -scheduled threads are probably what you really need. Network servers are -rarely CPU-bound, however. - -If your operating system supports the select() system call in its I/O -library (and nearly all do), then you can use it to juggle multiple -communication channels at once; doing other work while your I/O is taking -place in the "background." Although this strategy can seem strange and -complex, especially at first, it is in many ways easier to understand and -control than multi-threaded programming. The module documented here solves -many of the difficult problems for you, making the task of building -sophisticated high-performance network servers and clients a snap. -""" - -import exceptions -import select -import socket -import sys -import time - -import os -from errno import EALREADY, EINPROGRESS, EWOULDBLOCK, ECONNRESET, \ - ENOTCONN, ESHUTDOWN, EINTR, EISCONN - -try: - socket_map -except NameError: - socket_map = {} - -class ExitNow(exceptions.Exception): - pass - -def read(obj): - try: - obj.handle_read_event() - except ExitNow: - raise - except: - obj.handle_error() - -def write(obj): - try: - obj.handle_write_event() - except ExitNow: - raise - except: - obj.handle_error() - -def readwrite(obj, flags): - try: - if flags & select.POLLIN: - obj.handle_read_event() - if flags & select.POLLOUT: - obj.handle_write_event() - except ExitNow: - raise - except: - obj.handle_error() - -def poll(timeout=0.0, map=None): - if map is None: - map = socket_map - if map: - r = []; w = []; e = [] - for fd, obj in map.items(): - if obj.readable(): - r.append(fd) - if obj.writable(): - w.append(fd) - if [] == r == w == e: - time.sleep(timeout) - else: - try: - r, w, e = select.select(r, w, e, timeout) - except select.error, err: - if err[0] != EINTR: - raise - else: - return - - for fd in r: - obj = map.get(fd) - if obj is None: - continue - read(obj) - - for fd in w: - obj = map.get(fd) - if obj is None: - continue - write(obj) - -def poll2(timeout=0.0, map=None): - import poll - if map is None: - map = socket_map - if timeout is not None: - # timeout is in milliseconds - timeout = int(timeout*1000) - if map: - l = [] - for fd, obj in map.items(): - flags = 0 - if obj.readable(): - flags = poll.POLLIN - if obj.writable(): - flags = flags | poll.POLLOUT - if flags: - l.append((fd, flags)) - r = poll.poll(l, timeout) - for fd, flags in r: - obj = map.get(fd) - if obj is None: - continue - readwrite(obj, flags) - -def poll3(timeout=0.0, map=None): - # Use the poll() support added to the select module in Python 2.0 - if map is None: - map = socket_map - if timeout is not None: - # timeout is in milliseconds - timeout = int(timeout*1000) - pollster = select.poll() - if map: - for fd, obj in map.items(): - flags = 0 - if obj.readable(): - flags = select.POLLIN - if obj.writable(): - flags = flags | select.POLLOUT - if flags: - pollster.register(fd, flags) - try: - r = pollster.poll(timeout) - except select.error, err: - if err[0] != EINTR: - raise - r = [] - for fd, flags in r: - obj = map.get(fd) - if obj is None: - continue - readwrite(obj, flags) - -def loop(timeout=30.0, use_poll=0, map=None): - if map is None: - map = socket_map - - if use_poll: - if hasattr(select, 'poll'): - poll_fun = poll3 - else: - poll_fun = poll2 - else: - poll_fun = poll - - while map: - poll_fun(timeout, map) - -class dispatcher: - - debug = 0 - connected = 0 - accepting = 0 - closing = 0 - addr = None - - def __init__(self, sock=None, map=None): - if sock: - self.set_socket(sock, map) - # I think it should inherit this anyway - self.socket.setblocking(0) - self.connected = 1 - # XXX Does the constructor require that the socket passed - # be connected? - try: - self.addr = sock.getpeername() - except socket.error: - # The addr isn't crucial - pass - else: - self.socket = None - - def __repr__(self): - status = [self.__class__.__module__+"."+self.__class__.__name__] - if self.accepting and self.addr: - status.append('listening') - elif self.connected: - status.append('connected') - if self.addr is not None: - try: - status.append('%s:%d' % self.addr) - except TypeError: - status.append(repr(self.addr)) - # On some systems (RH10) id() can be a negative number. - # work around this. - MAX = 2L*sys.maxint+1 - return '<%s at %#x>' % (' '.join(status), id(self)&MAX) - - def add_channel(self, map=None): - #self.log_info('adding channel %s' % self) - if map is None: - if hasattr(self, '_map'): - map = self._map - del self._map - else: - map = socket_map - if not hasattr(self, '_fileno'): - self._fileno = self.socket.fileno() - map[self._fileno] = self - - def del_channel(self, map=None): - fd = self._fileno - if map is None: - map = socket_map - if map.has_key(fd): - #self.log_info('closing channel %d:%s' % (fd, self)) - del map[fd] - - def create_socket(self, family, type): - self.family_and_type = family, type - self.socket = socket.socket(family, type) - self.socket.setblocking(0) - - def set_socket(self, sock, map=None): - self.socket = sock -## self.__dict__['socket'] = sock - if sock.fileno(): - self.add_channel(map) - else: - self._map = map - - def set_reuse_addr(self): - # try to re-use a server port if possible - try: - self.socket.setsockopt( - socket.SOL_SOCKET, socket.SO_REUSEADDR, - self.socket.getsockopt(socket.SOL_SOCKET, - socket.SO_REUSEADDR) | 1 - ) - except socket.error: - pass - - # ================================================== - # predicates for select() - # these are used as filters for the lists of sockets - # to pass to select(). - # ================================================== - - def readable(self): - return True - - if os.name == 'mac': - # The macintosh will select a listening socket for - # write if you let it. What might this mean? - def writable(self): - return not self.accepting - else: - def writable(self): - return True - - # ================================================== - # socket object methods. - # ================================================== - - def listen(self, num): - self.accepting = 1 - if os.name == 'nt' and num > 5: - num = 1 - ret = self.socket.listen(num) - self.add_channel() - return ret - - def bind(self, addr): - self.addr = addr - return self.socket.bind(addr) - - def connect(self, address): - self.connected = 0 - err = self.socket.connect_ex(address) - # XXX Should interpret Winsock return values - if err in (EINPROGRESS, EALREADY, EWOULDBLOCK): - return - if err in (0, EISCONN): - self.add_channel() - self.addr = address - self.connected = 1 - self.handle_connect() - else: - raise socket.error, err - - def accept(self): - # XXX can return either an address pair or None - try: - conn, addr = self.socket.accept() - self.add_channel() - return conn, addr - except socket.error, why: - if why[0] == EWOULDBLOCK: - pass - else: - raise socket.error, why - - def send(self, data): - try: - result = self.socket.send(data) - return result - except socket.error, why: - if why[0] == EWOULDBLOCK: - return 0 - else: - raise socket.error, why - return 0 - - def recv(self, buffer_size): - try: - data = self.socket.recv(buffer_size) - if not data: - # a closed connection is indicated by signaling - # a read condition, and having recv() return 0. - self.handle_close() - return '' - else: - return data - except socket.error, why: - # winsock sometimes throws ENOTCONN - if why[0] in [ECONNRESET, ENOTCONN, ESHUTDOWN]: - self.handle_close() - return '' - else: - raise socket.error, why - - def close(self): - self.del_channel() - self.socket.close() - - # cheap inheritance, used to pass all other attribute - # references to the underlying socket object. - def __getattr__(self, attr): - return getattr(self.socket, attr) - - # log and log_info may be overridden to provide more sophisticated - # logging and warning methods. In general, log is for 'hit' logging - # and 'log_info' is for informational, warning and error logging. - - def log(self, message): - sys.stderr.write('log: %s\n' % str(message)) - - def log_info(self, message, type='info'): - if __debug__ or type != 'info': - print '%s: %s' % (type, message) - - def handle_read_event(self): - if self.accepting: - # for an accepting socket, getting a read implies - # that we are connected - if not self.connected: - self.connected = 1 - self.handle_accept() - elif not self.connected: - self.handle_connect() - self.connected = 1 - self.handle_read() - else: - self.handle_read() - - def handle_write_event(self): - # getting a write implies that we are connected - if not self.connected: - self.handle_connect() - self.connected = 1 - self.handle_write() - - def handle_expt_event(self): - self.handle_expt() - - def handle_error(self): - nil, t, v, tbinfo = compact_traceback() - - # sometimes a user repr method will crash. - try: - self_repr = repr(self) - except: - self_repr = '<__repr__(self) failed for object at %0x>' % id(self) - - self.log_info( - 'uncaptured python exception, closing channel %s (%s:%s %s)' % ( - self_repr, - t, - v, - tbinfo - ), - 'error' - ) - self.close() - - def handle_expt(self): - self.log_info('unhandled exception', 'warning') - - def handle_read(self): - self.log_info('unhandled read event', 'warning') - - def handle_write(self): - self.log_info('unhandled write event', 'warning') - - def handle_connect(self): - self.log_info('unhandled connect event', 'warning') - - def handle_accept(self): - self.log_info('unhandled accept event', 'warning') - - def handle_close(self): - self.log_info('unhandled close event', 'warning') - self.close() - -# --------------------------------------------------------------------------- -# adds simple buffered output capability, useful for simple clients. -# [for more sophisticated usage use asynchat.async_chat] -# --------------------------------------------------------------------------- - -class dispatcher_with_send(dispatcher): - - def __init__(self, sock=None): - dispatcher.__init__(self, sock) - self.out_buffer = '' - - def initiate_send(self): - num_sent = 0 - num_sent = dispatcher.send(self, self.out_buffer[... [truncated message content] |