1"""Abstract servlets""" 2 3import os 4 5from MiscUtils import AbstractError 6from MiscUtils.Funcs import asclocaltime, excstr 7 8 9class Servlet(object): 10 """A general servlet. 11 12 A servlet is a key portion of a server-based application that implements 13 the semantics of a particular request by providing a response. 14 This abstract class defines servlets at a very high level. 15 Most often, developers will subclass HTTPServlet or even Page. 16 17 Servlets can be created once, then used and destroyed, or they may be 18 reused several times over (it's up to the server). Therefore, servlet 19 developers should take the proper actions in awake() and sleep() 20 so that reuse can occur. 21 22 Objects that participate in a transaction include: 23 * Application 24 * Request 25 * Transaction 26 * Session 27 * Servlet 28 * Response 29 30 The awake(), respond() and sleep() methods form a message sandwich. 31 Each is passed an instance of Transaction which gives further access 32 to all the objects involved. 33 """ 34 35 36 ## Init ## 37 38 def __init__(self): 39 """Subclasses must invoke super.""" 40 self._serverSidePath = None 41 self._factory = None 42 self._busy = False 43 44 45 ## Access ## 46 47 def name(self): 48 """Return the name which is simple the name of the class. 49 50 Subclasses should *not* override this method. 51 It is used for logging and debugging. 52 """ 53 return self.__class__.__name__ 54 55 56 ## Request-response cycles ## 57 58 @staticmethod 59 def runTransaction(trans): 60 try: 61 trans.awake() 62 trans.respond() 63 except Exception as first: 64 try: 65 trans.sleep() 66 except Exception as second: 67 # The first exception is more important than the *second* one 68 # that comes from sleep(). In fact, without this little trick 69 # the first exception gets hidden by the second which is often 70 # just a result of the first. Then you're stuck scratching your 71 # head wondering what the first might have been. 72 raise Exception('Two exceptions. first=%s; second=%s' 73 % (excstr(first), excstr(second))) 74 else: 75 raise # no problems with sleep() so raise the one and only exception 76 else: 77 trans.sleep() 78 79 def runMethodForTransaction(self, trans, method, *args, **kw): 80 self.awake(trans) 81 result = getattr(self, method)(*args, **kw) 82 self.sleep(trans) 83 return result 84 85 def awake(self, trans): 86 """Send the awake message. 87 88 This message is sent to all objects that participate in the 89 request-response cycle in a top-down fashion, prior to respond(). 90 Subclasses must invoke super. 91 """ 92 self._transaction = trans 93 94 def respond(self, trans): 95 """Respond to a request.""" 96 raise AbstractError(self.__class__) 97 98 def sleep(self, trans): 99 """Send the sleep message.""" 100 pass 101 102 103 ## Log ## 104 105 def log(self, message): 106 """Log a message. 107 108 This can be invoked to print messages concerning the servlet. 109 This is often used by self to relay important information back 110 to developers. 111 """ 112 print '[%s] [msg] %s' % (asclocaltime(), message) 113 114 115 ## Abilities ## 116 117 @staticmethod 118 def canBeThreaded(): 119 """Return whether the servlet can be multithreaded. 120 121 This value should not change during the lifetime of the object. 122 The default implementation returns False. 123 Note: This is not currently used. 124 """ 125 return False 126 127 @staticmethod 128 def canBeReused(): 129 """Returns whether a single servlet instance can be reused. 130 131 The default is True, but subclasses con override to return False. 132 Keep in mind that performance may seriously be degraded if instances 133 can't be reused. Also, there's no known good reasons not to reuse 134 an instance. Remember the awake() and sleep() methods are invoked 135 for every transaction. But just in case, your servlet can refuse 136 to be reused. 137 """ 138 return True 139 140 141 ## Server side filesystem ## 142 143 def serverSidePath(self, path=None): 144 """Return the filesystem path of the page on the server.""" 145 if self._serverSidePath is None: 146 self._serverSidePath = self._transaction.request().serverSidePath() 147 if path: 148 if path.startswith('/'): 149 path = path[1:] 150 return os.path.normpath(os.path.join( 151 os.path.dirname(self._serverSidePath), path)) 152 else: 153 return self._serverSidePath 154 155 156 ## Private ## 157 158 def open(self): 159 self._busy = True 160 161 def close(self): 162 if self._busy and self._factory: 163 self._busy = False 164 self._factory.returnServlet(self) 165 166 def setFactory(self, factory): 167 self._factory = factory 168