import types from WebUtils import Funcs class Component: """ Subclasses of Component are the public view of components, i.e., the objects that go in the CPage.components class variable. However, CPage instances actually work with ServletComponents, which are bound to a specific servlet. So in most cases this factory class need only be used like:: class SomeServletComponent(ServletComponent): # real work... class SomeComponent(Component): _componentClass = SomeServletComponent """ def __init__(self, *args, **kw): self._args = args self._kw = kw def componentFor(self, servlet): return self.createComponent() def createComponent(self): return self._componentClass(*self._args, **self._kw) class ServletComponent: """ The real workhorse of the component system are the subclasses of ServletComponent. These are where you implement your component functionality. To hook your class to the servlet, you may wish to define: ``*Event`` methods: Events are fired by name, such as the 'awake' event (fired in the awake() method). Appending 'Event' gives the method name for that event, e.g., 'awakeEvent'. If the class defines an appropriate method, then it will be automatically called. Different events take different arguments. ``_servletMethods``: Class variable, a list. The names of methods which should be added to the servlet. E.g.:: class BrowserServletComponent(ServletComponent): _servletMethods = ['browser'] def browser(self): req = self.servlet().request() # ... code that returns an object encapsulating # browser compatibility information ... Then servlets that used this component would have a method ``self.browser()``. self is still bound to the ServletComponent instance, not the servlet instance. ``_handleExceptions``: Class variable, a list. The exceptions (or names of exceptions) that this class handles. E.g.:: class SearchOn404(ServletComponent): _handleExceptions = ['HTTPNotFound'] def exceptionHTTPNotFoundEvent(self, exc): self.servlet().write('...') # returning 'break' means the exception has been # handled and needn't be propagated up: return 'break' Actual exceptions are simply fired as 'exception' events, i.e., calling exceptionEvent. By using _handleExceptions you can catch subclasses of these exceptions, and ignore other exceptions. In your methods, you'll probably want to take advantage of these useful methods: ``servlet()``: The servlet this instance is bound to. ``optionalMethod(methodName, defaultValue, *args, **kw)``: Call the method `methodName` of our servlet, with *args and **kw. If the servlet does not define such a method, return `defaultValue`. """ def __init__(self): if self.handleExceptions(): self.exceptionEvent = self.handleExceptionEvent _servletMethods = [] _handleExceptions = [] def addComponentTo(self, servlet): """ Modify the servlet in some way specific to this component. General hook for the component to add functionality and methods to the servlet. By default it adds any methods named in the _servletMethods attribute to the servlet. """ self._servlet = servlet hide_vars = getattr(servlet, '__traceback_supplement_hide_vars__', None) for method in self._servletMethods: if not getattr(servlet, method, None): setattr(servlet, method, getattr(self, method)) if (hide_vars is not None and method not in hide_vars and isinstance(getattr(self, method), types.MethodType)): hide_vars.append(method) def actions(self): return [] def servlet(self): return self._servlet def optionalMethod(self, methodName, default, *args, **kw): """ Calls a method of the servlet. If the method does not exist, returns default. """ try: meth = getattr(self._servlet, methodName) except AttributeError: return default else: return meth(*args, **kw) def handleExceptions(self): return self._handleExceptions def handleExceptionEvent(self, exc): for handled in self.handleExceptions(): if type(handled) is type(""): handled = eval(handled) if isinstance(exc, handled): meth = getattr(self, '%sEvent' % handled.__name__) if not meth(exc): return 0 return 1 def htmlEncode(self, v): return Funcs.htmlEncode(v) def urlEncode(self, v): return Funcs.urlEncode(v) # Some null, standard event handlers: awakeEvent = None sleepEvent = None exceptionEvent = None