paulb@599 | 1 | #!/usr/bin/env python |
paulb@599 | 2 | |
paulb@599 | 3 | """ |
paulb@599 | 4 | Resources which "select" other resources, sometimes causing desirable |
paulb@599 | 5 | side-effects. |
paulb@599 | 6 | |
paulb@599 | 7 | Copyright (C) 2007 Paul Boddie <paul@boddie.org.uk> |
paulb@599 | 8 | |
paulb@599 | 9 | This library is free software; you can redistribute it and/or |
paulb@599 | 10 | modify it under the terms of the GNU Lesser General Public |
paulb@599 | 11 | License as published by the Free Software Foundation; either |
paulb@599 | 12 | version 2.1 of the License, or (at your option) any later version. |
paulb@599 | 13 | |
paulb@599 | 14 | This library is distributed in the hope that it will be useful, |
paulb@599 | 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
paulb@599 | 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
paulb@599 | 17 | Lesser General Public License for more details. |
paulb@599 | 18 | |
paulb@599 | 19 | You should have received a copy of the GNU Lesser General Public |
paulb@599 | 20 | License along with this library; if not, write to the Free Software |
paulb@599 | 21 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
paulb@599 | 22 | """ |
paulb@599 | 23 | |
paulb@599 | 24 | class PathSelector: |
paulb@599 | 25 | |
paulb@599 | 26 | "Set a request's current path and processed path info on an attribute." |
paulb@599 | 27 | |
paulb@599 | 28 | def __init__(self, resource, add_slash=1, attribute_name="root", path_encoding="utf-8"): |
paulb@599 | 29 | |
paulb@599 | 30 | """ |
paulb@599 | 31 | Initialise the selector with a 'resource' (to which all requests shall |
paulb@599 | 32 | be forwarded), specifying whether a "/" character shall be added to |
paulb@599 | 33 | stored paths using the optional 'add_slash' parameter (default is true), |
paulb@599 | 34 | along with an optional 'attribute_name' (indicating the name of the |
paulb@599 | 35 | attribute on which the path information shall be stored), and the |
paulb@599 | 36 | optional 'path_encoding' for interpreting URL-encoded path values. |
paulb@599 | 37 | """ |
paulb@599 | 38 | |
paulb@599 | 39 | self.resource = resource |
paulb@599 | 40 | self.add_slash = add_slash |
paulb@599 | 41 | self.attribute_name = attribute_name |
paulb@599 | 42 | self.path_encoding = path_encoding |
paulb@599 | 43 | |
paulb@599 | 44 | def _slash(self): |
paulb@599 | 45 | if self.add_slash: |
paulb@599 | 46 | return "/" |
paulb@599 | 47 | else: |
paulb@599 | 48 | return "" |
paulb@599 | 49 | |
paulb@599 | 50 | def respond(self, trans): |
paulb@599 | 51 | |
paulb@599 | 52 | """ |
paulb@599 | 53 | Respond to the transaction 'trans' by storing the current path and |
paulb@620 | 54 | processed virtual path info on the named transaction attribute, then |
paulb@620 | 55 | forwarding the transaction to the previously specified resource. |
paulb@599 | 56 | """ |
paulb@599 | 57 | |
paulb@599 | 58 | pwi = trans.get_path_without_info(self.path_encoding) |
paulb@599 | 59 | |
paulb@599 | 60 | # Make a note of the path given the following general rule: |
paulb@599 | 61 | # path_without_info + path_info |
paulb@599 | 62 | # == path_without_info + processed_virtual_path_info + virtual_path_info |
paulb@599 | 63 | |
paulb@599 | 64 | attributes = trans.get_attributes() |
paulb@599 | 65 | attributes[self.attribute_name] = trans.encode_path( |
paulb@599 | 66 | pwi + trans.get_processed_virtual_path_info(self.path_encoding) + self._slash(), |
paulb@599 | 67 | self.path_encoding |
paulb@599 | 68 | ) |
paulb@599 | 69 | |
paulb@599 | 70 | self.resource.respond(trans) |
paulb@599 | 71 | |
paulb@620 | 72 | class EncodingSelector: |
paulb@620 | 73 | |
paulb@620 | 74 | """ |
paulb@620 | 75 | Set the default encoding (or "charset") on transactions presented to this |
paulb@620 | 76 | resource. |
paulb@620 | 77 | """ |
paulb@620 | 78 | |
paulb@620 | 79 | def __init__(self, resource, encoding): |
paulb@620 | 80 | |
paulb@620 | 81 | """ |
paulb@620 | 82 | Initialise the selector with a 'resource' (to which all requests shall |
paulb@620 | 83 | be forwarded), specifying the 'encoding' which shall be used as the |
paulb@620 | 84 | default encoding (or "charset") for all transactions handled by this |
paulb@620 | 85 | resource. |
paulb@620 | 86 | """ |
paulb@620 | 87 | |
paulb@620 | 88 | self.resource = resource |
paulb@620 | 89 | self.encoding = encoding |
paulb@620 | 90 | |
paulb@620 | 91 | def respond(self, trans): |
paulb@620 | 92 | |
paulb@620 | 93 | """ |
paulb@620 | 94 | Respond to the transaction 'trans' by setting the default encoding (or |
paulb@620 | 95 | "charset") on 'trans', then forwarding the transaction to the previously |
paulb@620 | 96 | specified resource. |
paulb@620 | 97 | """ |
paulb@620 | 98 | |
paulb@620 | 99 | trans.default_charset = self.encoding |
paulb@620 | 100 | self.resource.respond(trans) |
paulb@620 | 101 | |
paulb@746 | 102 | class StoreSelector: |
paulb@746 | 103 | |
paulb@746 | 104 | """ |
paulb@746 | 105 | Maintain an attribute for a data store on transactions, performing an |
paulb@746 | 106 | automatic rollback after the transaction has finished. The data store can be |
paulb@746 | 107 | a DB-API connection object or any object providing a 'rollback' method. |
paulb@746 | 108 | """ |
paulb@746 | 109 | |
paulb@746 | 110 | def __init__(self, resource, store): |
paulb@746 | 111 | |
paulb@746 | 112 | """ |
paulb@746 | 113 | Initialise the selector with a 'resource' (to which all requests shall |
paulb@746 | 114 | be forwarded), providing a 'store' which shall be maintained as an |
paulb@746 | 115 | attribute. |
paulb@746 | 116 | """ |
paulb@746 | 117 | |
paulb@746 | 118 | self.resource = resource |
paulb@746 | 119 | self.store = store |
paulb@746 | 120 | |
paulb@746 | 121 | def respond(self, trans): |
paulb@746 | 122 | |
paulb@746 | 123 | """ |
paulb@746 | 124 | Respond to the transaction 'trans' by setting the "store" attribute to |
paulb@746 | 125 | refer to the 'store' attribute on this object, then forwarding the |
paulb@746 | 126 | transaction to the previously specified resource. |
paulb@746 | 127 | |
paulb@746 | 128 | Regardless of how the resource completes its processing, the 'rollback' |
paulb@746 | 129 | method of the store will then be called in order to terminate any |
paulb@746 | 130 | unfinished, uncommitted transactions. |
paulb@746 | 131 | """ |
paulb@746 | 132 | |
paulb@746 | 133 | trans.get_attributes()["store"] = self.store |
paulb@746 | 134 | try: |
paulb@746 | 135 | self.resource.respond(trans) |
paulb@746 | 136 | finally: |
paulb@746 | 137 | self.store.rollback() |
paulb@746 | 138 | |
paulb@599 | 139 | # vim: tabstop=4 expandtab shiftwidth=4 |