| ### |
| # |
| # 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 self.app_directory is not None and 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: |
| for name_val in query_string.split('&'): |
| if name_val.find('=') != -1: |
| name, value = name_val.split('=', 1) |
| else: |
| name, value = name_val, '' |
| if name == self.params['callable_query_name']: |
| callable_name = value |
| else: |
| callable_name = '' |
| 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']: |
| 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)) ) |
| |