Class: Arrow::Broker
Overview
The broker is the applet manager. It maintains a registry of applets, and delegates transactions based on the request’s URI.
Authors
Michael Granger
Please see the file LICENSE in the top-level directory for licensing details.
Constant Summary
- FILE_SEPARATOR =
A regular expression that matches the file separator on this system
Regexp.new( Regexp.compile(File::SEPARATOR) )
Instance Attribute Summary
-
- (Object) registry
The Hash of RegistryEntry structs keyed by uri.
-
- (Object) start_time
readonly
The Time when the Broker was started.
Instance Method Summary
-
- (Object) builtin_error_handler(applet, txn, err)
protected
The builtin error handler routine.
-
- (Object) builtin_missing_handler(txn, *args)
protected
The builtin missing-applet handler routine.
-
- (Object) delegate(txn)
Dispatch the specified transaction txn to the appropriate handler based on the request’s path_info.
-
- (Broker) initialize(config)
constructor
Create a new Arrow::Broker object from the specified config (an Arrow::Config object).
-
- (Object) run_applet(applet, txn, rest)
Run the specified applet with the given txn (an Arrow::Transaction) and the rest of the path_info split on ’/’.
-
- (Object) run_applet_chain(txn, chain)
protected
Given a chain of applets built from a URI, run the indexth one with the specified transaction (txn).
-
- (Object) run_error_handler(applet, txn, err)
Handle the given applet error err for the specified applet, using the given transaction txn.
-
- (Object) run_missing_applet_handler(txn, uri)
Handle requests that target an applet that doesn’t exist.
-
- (Object) unwrap_chain_link(link)
protected
Check the specified link of an applet chain for sanity and return its constituent bits for assignment.
Methods inherited from Object
deprecate_class_method, deprecate_method, inherited
Methods included from Loggable
Constructor Details
- (Broker) initialize(config)
Create a new Arrow::Broker object from the specified config (an Arrow::Config object).
30 31 32 33 34 |
# File 'lib/arrow/broker.rb', line 30 def initialize( config ) @config = config @registry = Arrow::AppletRegistry.new( config ) @start_time = Time.now end |
Instance Attribute Details
- (Object) registry
The Hash of RegistryEntry structs keyed by uri
42 43 44 |
# File 'lib/arrow/broker.rb', line 42 def registry @registry end |
- (Object) start_time (readonly)
The Time when the Broker was started
45 46 47 |
# File 'lib/arrow/broker.rb', line 45 def start_time @start_time end |
Instance Method Details
- (Object) builtin_error_handler(applet, txn, err) (protected)
The builtin error handler routine. Outputs a plain-text backtrace for the given exception err and applet to the given transaction txn.
239 240 241 242 243 244 245 246 |
# File 'lib/arrow/broker.rb', line 239 def builtin_error_handler( applet, txn, err ) self.log.notice "Using builtin error handler." txn.request.content_type = "text/plain" txn.status = Apache::OK return "Arrow Applet Error in '%s': %s\n\t%s" % [ applet.class.signature.name, err., err.backtrace.join("\n\t") ] end |
- (Object) builtin_missing_handler(txn, *args) (protected)
The builtin missing-applet handler routine. Returns false, which causes the dispatcher to decline the request.
230 231 232 233 |
# File 'lib/arrow/broker.rb', line 230 def builtin_missing_handler( txn, *args ) self.log.notice "Using builtin missing-applet handler." return false end |
- (Object) delegate(txn)
Dispatch the specified transaction txn to the appropriate handler based on the request’s path_info.
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
# File 'lib/arrow/broker.rb', line 51 def delegate( txn ) rval = appletchain = nil self.log.debug "Start of delegation (%s)" % [ txn.unparsed_uri ] # Fetch the path and trim the leading '/' path = txn.path path.sub!( %r{^/}, '' ) self.log.debug "Request's path is %p" % path # Check for updated/deleted/added applets @registry.check_for_updates # Get the chain of applets to execute for the request appletchain = @registry.find_applet_chain( path ) # If the pathinfo doesn't correspond to at least one applet, run # the no-such-applet handler. if appletchain.empty? rval = self.run_missing_applet_handler( txn, path ) else rval = self.run_applet_chain( txn, appletchain ) end # Set the request status to declined if it hasn't been set yet and # the return value is false. if !rval self.log.error "Applet returned false value. " + "Setting status to DECLINED" txn.status = Apache::DECLINED end # self.log.debug "Returning %p" % [ rval ] return rval end |
- (Object) run_applet(applet, txn, rest)
Run the specified applet with the given txn (an Arrow::Transaction) and the rest of the path_info split on ’/’.
89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/arrow/broker.rb', line 89 def run_applet( applet, txn, rest ) self.log.debug "Running '%s' with args: %p" % [ applet.signature.name, rest ] return applet.run( txn, *rest ) rescue ::Exception => err self.log.error "[%s]: Error running %s (%s): %s:\n\t%s" % [ txn.serial, applet.signature.name, applet.class.filename, err., err.backtrace.join("\n\t"), ] return self.run_error_handler( applet, txn, err ) end |
- (Object) run_applet_chain(txn, chain) (protected)
Given a chain of applets built from a URI, run the indexth one with the specified transaction (txn). Applets before the last get called via their #delegate method, while the last one is called via #run.
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 |
# File 'lib/arrow/broker.rb', line 170 def run_applet_chain( txn, chain ) self.log.debug "Running applet chain: #{chain.inspect}" raise Arrow::AppletError, "Malformed applet chain" if chain.empty? || !chain.first.respond_to?( :applet ) res = nil applet, txn.applet_path, args = self.unwrap_chain_link( chain.first ) # If there's only one item left, run it if chain.nitems == 1 self.log.debug "Running final applet in chain" res = self.run_applet( applet, txn, args ) # Otherwise, delegate the transaction to the next applet with the # remainder of the chain. else dchain = chain[ 1..-1 ] self.log.debug "Running applet %s in chain of %d; chain = %p" % [ applet.signature.name, chain.nitems, dchain ] begin res = applet.delegate( txn, dchain, *args ) do |subchain| subchain = dchain if subchain.nil? self.log.debug "Delegated call to appletchain %p" % [ subchain ] self.run_applet_chain( txn, subchain ) end rescue ::Exception => err self.log.error "Error while executing applet chain: %p (/%s): %s:\n\t%s" % [ applet, chain.first[1], err., err.backtrace.join("\n\t"), ] res = self.run_error_handler( applet, txn, err ) end end return res end |
- (Object) run_error_handler(applet, txn, err)
Handle the given applet error err for the specified applet, using the given transaction txn. This will attempt to run whatever applet is configured as the error-handler, or run a builtin handler applet if none is configured or the configured one isn’t loaded.
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
# File 'lib/arrow/broker.rb', line 134 def run_error_handler( applet, txn, err ) rval = nil handlerName = @config.applets.errorApplet.sub( %r{^/}, '' ) unless handlerName == "(builtin)" or !@registry.key?( handlerName ) handler = @registry[handlerName] self.log.notice "Running error handler applet '%s' (%s)" % [ handler.signature.name, handlerName ] begin rval = handler.run( txn, "report_error", applet, err ) rescue ::Exception => err2 self.log.error "Error while attempting to use custom error "\ "handler '%s': %s\n\t%s" % [ handler.signature.name, err2., err2.backtrace.join("\n\t"), ] rval = self.builtin_error_handler( applet, txn, err ) end else rval = self.builtin_error_handler( applet, txn, err ) end return rval end |
- (Object) run_missing_applet_handler(txn, uri)
Handle requests that target an applet that doesn’t exist.
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/arrow/broker.rb', line 106 def run_missing_applet_handler( txn, uri ) rval = appletchain = nil handlerUri = @config.applets.missingApplet args = uri.split( %r{/} ) # Build an applet chain for user-configured handlers if handlerUri != "(builtin)" appletchain = @registry.find_applet_chain( handlerUri ) self.log.error "Configured MissingApplet handler (%s) doesn't exist" % handlerUri if appletchain.empty? end # If the user-configured handler maps to one or more handlers, run # them. Otherwise, run the build-in handler. unless appletchain.nil? || appletchain.empty? rval = self.run_applet_chain( txn, appletchain ) else rval = self.builtin_missing_handler( txn, *args ) end return rval end |
- (Object) unwrap_chain_link(link) (protected)
Check the specified link of an applet chain for sanity and return its constituent bits for assignment. This is necessary to provide sensible errors if a delegating app screws up a chain somehow.
214 215 216 217 218 219 220 221 222 223 224 225 |
# File 'lib/arrow/broker.rb', line 214 def unwrap_chain_link( link ) applet = link.applet or raise Arrow::AppletChainError, "Null applet" path = link.path or raise Arrow::AppletChainError, "Null path" args = link.args or raise Arrow::AppletChainError, "Null argument list" unless args.is_a?( Array ) emsg = "Argument list is a %s: expected an Array" % args.class.name raise Arrow::AppletChainError, emsg end return applet, path, args end |