arrow 1.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (198) hide show
  1. data/ChangeLog +1590 -0
  2. data/LICENSE +28 -0
  3. data/README +75 -0
  4. data/Rakefile +366 -0
  5. data/Rakefile.local +63 -0
  6. data/data/arrow/applets/TEMPLATE.rb.tpl +53 -0
  7. data/data/arrow/applets/args.rb +50 -0
  8. data/data/arrow/applets/config.rb +55 -0
  9. data/data/arrow/applets/error.rb +63 -0
  10. data/data/arrow/applets/files.rb +46 -0
  11. data/data/arrow/applets/inspect.rb +46 -0
  12. data/data/arrow/applets/nosuchapplet.rb +31 -0
  13. data/data/arrow/applets/status.rb +92 -0
  14. data/data/arrow/applets/test.rb +133 -0
  15. data/data/arrow/applets/tutorial/counter.rb +96 -0
  16. data/data/arrow/applets/tutorial/dingus.rb +67 -0
  17. data/data/arrow/applets/tutorial/hello.rb +34 -0
  18. data/data/arrow/applets/tutorial/hello2.rb +73 -0
  19. data/data/arrow/applets/tutorial/imgtext.rb +90 -0
  20. data/data/arrow/applets/tutorial/imgtext2.rb +286 -0
  21. data/data/arrow/applets/tutorial/index.rb +36 -0
  22. data/data/arrow/applets/tutorial/logo.rb +98 -0
  23. data/data/arrow/applets/tutorial/memcache.rb +61 -0
  24. data/data/arrow/applets/tutorial/missing.rb +37 -0
  25. data/data/arrow/applets/tutorial/protected.rb +100 -0
  26. data/data/arrow/applets/tutorial/redirector.rb +52 -0
  27. data/data/arrow/applets/tutorial/rndimages.rb +159 -0
  28. data/data/arrow/applets/tutorial/sharenotes.rb +83 -0
  29. data/data/arrow/applets/tutorial/subclassed-hello.rb +32 -0
  30. data/data/arrow/applets/tutorial/superhello.rb +72 -0
  31. data/data/arrow/applets/tutorial/timeclock.rb +78 -0
  32. data/data/arrow/applets/view-applet.rb +123 -0
  33. data/data/arrow/applets/view-template.rb +85 -0
  34. data/data/arrow/applets/wiki.rb +274 -0
  35. data/data/arrow/templates/TEMPLATE.tmpl.tpl +36 -0
  36. data/data/arrow/templates/applet-status.tmpl +153 -0
  37. data/data/arrow/templates/args-display.tmpl +120 -0
  38. data/data/arrow/templates/config/display-table.tmpl +36 -0
  39. data/data/arrow/templates/config/display.tmpl +36 -0
  40. data/data/arrow/templates/counter-deleted.tmpl +33 -0
  41. data/data/arrow/templates/counter.tmpl +59 -0
  42. data/data/arrow/templates/dingus.tmpl +55 -0
  43. data/data/arrow/templates/enumtable.tmpl +8 -0
  44. data/data/arrow/templates/error-display.tmpl +92 -0
  45. data/data/arrow/templates/filemap.tmpl +89 -0
  46. data/data/arrow/templates/hello-world-src.tmpl +34 -0
  47. data/data/arrow/templates/hello-world.tmpl +60 -0
  48. data/data/arrow/templates/imgtext/fontlist.tmpl +46 -0
  49. data/data/arrow/templates/imgtext/form.tmpl +70 -0
  50. data/data/arrow/templates/imgtext/reload-error.tmpl +40 -0
  51. data/data/arrow/templates/imgtext/reload.tmpl +55 -0
  52. data/data/arrow/templates/inspect/display.tmpl +80 -0
  53. data/data/arrow/templates/loginform.tmpl +64 -0
  54. data/data/arrow/templates/logout.tmpl +32 -0
  55. data/data/arrow/templates/memcache/display.tmpl +41 -0
  56. data/data/arrow/templates/navbar.incl +27 -0
  57. data/data/arrow/templates/nosuchapplet.tmpl +32 -0
  58. data/data/arrow/templates/printsource.tmpl +35 -0
  59. data/data/arrow/templates/protected.tmpl +36 -0
  60. data/data/arrow/templates/rndimages.tmpl +38 -0
  61. data/data/arrow/templates/service-response.tmpl +13 -0
  62. data/data/arrow/templates/sharenotes/display.tmpl +38 -0
  63. data/data/arrow/templates/status.tmpl +120 -0
  64. data/data/arrow/templates/templateviewer.tmpl +43 -0
  65. data/data/arrow/templates/test/harness.tmpl +57 -0
  66. data/data/arrow/templates/test/list.tmpl +48 -0
  67. data/data/arrow/templates/test/problem.tmpl +42 -0
  68. data/data/arrow/templates/tutorial/index.tmpl +37 -0
  69. data/data/arrow/templates/tutorial/missingapplet.tmpl +29 -0
  70. data/data/arrow/templates/view-applet-nosuch.tmpl +32 -0
  71. data/data/arrow/templates/view-applet.tmpl +40 -0
  72. data/data/arrow/templates/view-template.tmpl +83 -0
  73. data/data/arrow/templates/wiki/formerror.tmpl +47 -0
  74. data/data/arrow/templates/wiki/markup_help.incl +6 -0
  75. data/data/arrow/templates/wiki/new.tmpl +56 -0
  76. data/data/arrow/templates/wiki/new_system.tmpl +122 -0
  77. data/data/arrow/templates/wiki/sectionlist.tmpl +43 -0
  78. data/data/arrow/templates/wiki/show.tmpl +34 -0
  79. data/docs/manual/layouts/default.page +43 -0
  80. data/docs/manual/lib/api-filter.rb +81 -0
  81. data/docs/manual/lib/editorial-filter.rb +64 -0
  82. data/docs/manual/lib/examples-filter.rb +244 -0
  83. data/docs/manual/lib/links-filter.rb +117 -0
  84. data/lib/apache/fakerequest.rb +448 -0
  85. data/lib/apache/logger.rb +33 -0
  86. data/lib/arrow.rb +51 -0
  87. data/lib/arrow/acceptparam.rb +207 -0
  88. data/lib/arrow/applet.rb +725 -0
  89. data/lib/arrow/appletmixins.rb +218 -0
  90. data/lib/arrow/appletregistry.rb +590 -0
  91. data/lib/arrow/applettestcase.rb +503 -0
  92. data/lib/arrow/broker.rb +255 -0
  93. data/lib/arrow/cache.rb +176 -0
  94. data/lib/arrow/config-loaders/yaml.rb +75 -0
  95. data/lib/arrow/config.rb +615 -0
  96. data/lib/arrow/constants.rb +24 -0
  97. data/lib/arrow/cookie.rb +359 -0
  98. data/lib/arrow/cookieset.rb +108 -0
  99. data/lib/arrow/dispatcher.rb +368 -0
  100. data/lib/arrow/dispatcherloader.rb +50 -0
  101. data/lib/arrow/exceptions.rb +61 -0
  102. data/lib/arrow/fallbackhandler.rb +48 -0
  103. data/lib/arrow/formvalidator.rb +631 -0
  104. data/lib/arrow/htmltokenizer.rb +343 -0
  105. data/lib/arrow/logger.rb +488 -0
  106. data/lib/arrow/logger/apacheoutputter.rb +69 -0
  107. data/lib/arrow/logger/arrayoutputter.rb +63 -0
  108. data/lib/arrow/logger/coloroutputter.rb +111 -0
  109. data/lib/arrow/logger/fileoutputter.rb +96 -0
  110. data/lib/arrow/logger/htmloutputter.rb +54 -0
  111. data/lib/arrow/logger/outputter.rb +123 -0
  112. data/lib/arrow/mixins.rb +425 -0
  113. data/lib/arrow/monkeypatches.rb +94 -0
  114. data/lib/arrow/object.rb +117 -0
  115. data/lib/arrow/path.rb +196 -0
  116. data/lib/arrow/service.rb +447 -0
  117. data/lib/arrow/session.rb +289 -0
  118. data/lib/arrow/session/dbstore.rb +100 -0
  119. data/lib/arrow/session/filelock.rb +160 -0
  120. data/lib/arrow/session/filestore.rb +132 -0
  121. data/lib/arrow/session/id.rb +98 -0
  122. data/lib/arrow/session/lock.rb +253 -0
  123. data/lib/arrow/session/md5id.rb +42 -0
  124. data/lib/arrow/session/nulllock.rb +42 -0
  125. data/lib/arrow/session/posixlock.rb +166 -0
  126. data/lib/arrow/session/sha1id.rb +54 -0
  127. data/lib/arrow/session/store.rb +366 -0
  128. data/lib/arrow/session/usertrackid.rb +52 -0
  129. data/lib/arrow/spechelpers.rb +73 -0
  130. data/lib/arrow/template.rb +713 -0
  131. data/lib/arrow/template/attr.rb +31 -0
  132. data/lib/arrow/template/call.rb +31 -0
  133. data/lib/arrow/template/comment.rb +33 -0
  134. data/lib/arrow/template/container.rb +118 -0
  135. data/lib/arrow/template/else.rb +41 -0
  136. data/lib/arrow/template/elsif.rb +44 -0
  137. data/lib/arrow/template/escape.rb +53 -0
  138. data/lib/arrow/template/export.rb +87 -0
  139. data/lib/arrow/template/for.rb +145 -0
  140. data/lib/arrow/template/if.rb +78 -0
  141. data/lib/arrow/template/import.rb +119 -0
  142. data/lib/arrow/template/include.rb +206 -0
  143. data/lib/arrow/template/iterator.rb +208 -0
  144. data/lib/arrow/template/nodes.rb +734 -0
  145. data/lib/arrow/template/parser.rb +571 -0
  146. data/lib/arrow/template/prettyprint.rb +53 -0
  147. data/lib/arrow/template/render.rb +191 -0
  148. data/lib/arrow/template/selectlist.rb +94 -0
  149. data/lib/arrow/template/set.rb +87 -0
  150. data/lib/arrow/template/timedelta.rb +81 -0
  151. data/lib/arrow/template/unless.rb +78 -0
  152. data/lib/arrow/template/urlencode.rb +51 -0
  153. data/lib/arrow/template/yield.rb +139 -0
  154. data/lib/arrow/templatefactory.rb +125 -0
  155. data/lib/arrow/testcase.rb +567 -0
  156. data/lib/arrow/transaction.rb +608 -0
  157. data/rake/191_compat.rb +26 -0
  158. data/rake/dependencies.rb +76 -0
  159. data/rake/documentation.rb +114 -0
  160. data/rake/helpers.rb +502 -0
  161. data/rake/hg.rb +282 -0
  162. data/rake/manual.rb +787 -0
  163. data/rake/packaging.rb +129 -0
  164. data/rake/publishing.rb +278 -0
  165. data/rake/style.rb +62 -0
  166. data/rake/svn.rb +668 -0
  167. data/rake/testing.rb +187 -0
  168. data/rake/verifytask.rb +64 -0
  169. data/spec/arrow/acceptparam_spec.rb +157 -0
  170. data/spec/arrow/applet_spec.rb +575 -0
  171. data/spec/arrow/appletmixins_spec.rb +409 -0
  172. data/spec/arrow/appletregistry_spec.rb +294 -0
  173. data/spec/arrow/broker_spec.rb +153 -0
  174. data/spec/arrow/config_spec.rb +224 -0
  175. data/spec/arrow/cookieset_spec.rb +164 -0
  176. data/spec/arrow/dispatcher_spec.rb +137 -0
  177. data/spec/arrow/dispatcherloader_spec.rb +65 -0
  178. data/spec/arrow/formvalidator_spec.rb +781 -0
  179. data/spec/arrow/logger_spec.rb +346 -0
  180. data/spec/arrow/mixins_spec.rb +120 -0
  181. data/spec/arrow/service_spec.rb +645 -0
  182. data/spec/arrow/session_spec.rb +121 -0
  183. data/spec/arrow/template/iterator_spec.rb +222 -0
  184. data/spec/arrow/templatefactory_spec.rb +185 -0
  185. data/spec/arrow/transaction_spec.rb +319 -0
  186. data/spec/arrow_spec.rb +37 -0
  187. data/spec/lib/appletmatchers.rb +281 -0
  188. data/spec/lib/constants.rb +77 -0
  189. data/spec/lib/helpers.rb +41 -0
  190. data/spec/lib/matchers.rb +44 -0
  191. data/tests/cookie.tests.rb +310 -0
  192. data/tests/path.tests.rb +157 -0
  193. data/tests/session.tests.rb +111 -0
  194. data/tests/session_id.tests.rb +82 -0
  195. data/tests/session_lock.tests.rb +191 -0
  196. data/tests/session_store.tests.rb +53 -0
  197. data/tests/template.tests.rb +1360 -0
  198. metadata +339 -0
@@ -0,0 +1,368 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'benchmark'
4
+ require 'tmpdir'
5
+ require 'configurability'
6
+
7
+ require 'arrow/object'
8
+ require 'arrow/config'
9
+ require 'arrow/applet'
10
+ require 'arrow/transaction'
11
+ require 'arrow/broker'
12
+ require 'arrow/template'
13
+ require 'arrow/templatefactory'
14
+
15
+ require 'arrow/fallbackhandler'
16
+
17
+
18
+ # The Arrow::Dispatcher class -- the mod_ruby handler frontend for Arrow.
19
+ #
20
+ # == Synopsis
21
+ #
22
+ # Simple configuration:
23
+ #
24
+ # RubyRequire 'arrow'
25
+ # RubyChildInitHandler "Arrow::Dispatcher.create( 'myapp.yaml' )"
26
+ #
27
+ # <Location /arrow>
28
+ # Handler ruby-object
29
+ # RubyHandler Arrow::Dispatcher.instance
30
+ # </Location>
31
+ #
32
+ # More-complex setup; run two Arrow dispatchers with different configurations
33
+ # from different Locations:
34
+ #
35
+ # RubyRequire 'arrow'
36
+ # RubyChildInitHandler "Arrow::Dispatcher.create( :myapp => 'myapp.yml', :help => 'help.yml' )"
37
+ #
38
+ # <Location /myapp>
39
+ # Handler ruby-object
40
+ # RubyHandler Arrow::Dispatcher.instance(:myapp)
41
+ # </Location>
42
+ #
43
+ # <Location /help>
44
+ # Handler ruby-object
45
+ # RubyHandler Arrow::Dispatcher.instance(:help)
46
+ # </Location>
47
+ #
48
+ # Same thing, but use a YAML file to control the dispatchers and where their configs are:
49
+ #
50
+ # RubyRequire 'arrow'
51
+ # RubyChildInitHandler "Arrow.load_dispatchers('/Library/WebServer/arrow-hosts.yml')"
52
+ #
53
+ # <Location /myapp>
54
+ # Handler ruby-object
55
+ # RubyHandler Arrow::Dispatcher.instance(:myapp)
56
+ # </Location>
57
+ #
58
+ # <Location /help>
59
+ # Handler ruby-object
60
+ # RubyHandler Arrow::Dispatcher.instance(:help)
61
+ # </Location>
62
+ #
63
+ # arrow-hosts.yml:
64
+ #
65
+ # myapp:
66
+ # /some/directory/myapp.yml
67
+ # help:
68
+ # /other/directory/help.yml
69
+ #
70
+ # == Authors
71
+ #
72
+ # * Michael Granger <ged@FaerieMUD.org>
73
+ #
74
+ # Please see the file LICENSE in the top-level directory for licensing details.
75
+ #
76
+ class Arrow::Dispatcher < Arrow::Object
77
+
78
+
79
+ #################################################################
80
+ ### C L A S S M E T H O D S
81
+ #################################################################
82
+
83
+ @@Instance = {}
84
+
85
+ ### Get the instance of the Dispatcher set up under the given +key+, which
86
+ ### can either be a Symbol or a String containing the path to a
87
+ ### configfile. If no key is given, it defaults to :__default__, which is
88
+ ### the key assigned when .create is given just a configfile argument.
89
+ def self::instance( key=:__default__ )
90
+ rval = nil
91
+
92
+ # Fetch the instance which corresponds to the given key
93
+ if key.is_a?( Symbol )
94
+ Arrow::Logger.debug "Returning instance for key %p (one of %p): %p" %
95
+ [key, @@Instance.keys, @@Instance[key]]
96
+ rval = @@Instance[ key ]
97
+ else
98
+ Arrow::Logger.debug "Returning instance for configfile %p" % [key]
99
+ configfile = File.expand_path( key )
100
+ self.create( configfile )
101
+ rval = @@Instance[ configfile ]
102
+ end
103
+
104
+ # Return either a configured Dispatcher instance or a FallbackHandler if
105
+ # no Dispatcher corresponds to the given key.
106
+ return rval || Arrow::FallbackHandler.new( key, @@Instance )
107
+ end
108
+
109
+
110
+ ### Set up one or more new Arrow::Dispatcher objects. The +configspec+
111
+ ### argument can either be the path to a config file, or a hash of config
112
+ ### files. See the .instance method for more about how to use this method.
113
+ def self::create( configspec )
114
+
115
+ # Normalize configurations. Expected either a configfile path in a
116
+ # String, or a Hash of configfiles
117
+ case configspec
118
+ when String
119
+ configs = { :__default__ => configspec }
120
+ when Hash
121
+ configs = configspec
122
+ else
123
+ raise ArgumentError, "Invalid config hash %p" % [configspec]
124
+ end
125
+
126
+ # Create the dispatchers and return the first one to support the
127
+ # old-style create, i.e.,
128
+ # dispatcher = Arrow::Dispatcher.create( configfile )
129
+ @@Instance = create_configured_dispatchers( configs )
130
+ @@Instance.values.first
131
+ rescue ::Exception => err
132
+
133
+ # Try to log fatal errors to both the Apache server log and a crashfile
134
+ # before passing the exception along.
135
+ errmsg = "%s failed to start (%s): %s: %s" % [
136
+ self.name,
137
+ err.class.name,
138
+ err.message,
139
+ err.backtrace.join("\n ")
140
+ ]
141
+
142
+ logfile = File.join( Dir.tmpdir, "arrow-fatal.log.#{$$}" )
143
+ File.open( logfile, IO::WRONLY|IO::TRUNC|IO::CREAT ) {|ofh|
144
+ ofh.puts( errmsg )
145
+ ofh.flush
146
+ }
147
+
148
+ if defined?( Apache )
149
+ Apache.request.server.log_crit( errmsg )
150
+ end
151
+
152
+ Kernel.raise( err )
153
+ end
154
+
155
+
156
+ ### Create one or more dispatchers from the specified +hosts_file+, which is
157
+ ### a YAML file that maps arrow configurations onto a symbol that can be
158
+ ### used to refer to it.
159
+ def self::create_from_hosts_file( hosts_file )
160
+ configs = nil
161
+
162
+ if hosts_file.respond_to?( :read )
163
+ configs = YAML.load( hosts_file.read )
164
+ else
165
+ hosts_file.untaint
166
+ configs = YAML.load_file( hosts_file )
167
+ end
168
+
169
+ # Convert the keys to Symbols and the values to untainted Strings.
170
+ configs.each do |key,config|
171
+ sym = key.to_s.dup.untaint.to_sym
172
+ configs[ sym ] = configs.delete( key )
173
+ configs[ sym ].untaint
174
+ end
175
+
176
+ @@Instance = self.create_configured_dispatchers( configs )
177
+ return @@Instance
178
+ end
179
+
180
+
181
+ ### Create dispatchers for the config files given in +configspec+ and return
182
+ ### them in a Hash keyed by both the configname key and the expanded path to
183
+ ### the configuration file.
184
+ def self::create_configured_dispatchers( configspec )
185
+ instances = {}
186
+
187
+ # Load a dispatcher for each config
188
+ configspec.each do |key, configfile|
189
+
190
+ # Normalize the path to the config file and make sure it's not
191
+ # loaded yet. If it is, link it to the current key and skip to the
192
+ # next.
193
+ configfile = File.expand_path( configfile )
194
+ if instances.key?( configfile )
195
+ instances[ key ] = instances[ configfile ]
196
+ next
197
+ end
198
+
199
+ # If a config file is given, load it. If it's not, just use the
200
+ # default config.
201
+ if configfile
202
+ config = Arrow::Config.load( configfile )
203
+ else
204
+ config = Arrow::Config.new
205
+ end
206
+
207
+ # Create a dispatcher and put it in the table by both its key and
208
+ # the normalized path to its configfile.
209
+ msg = "Creating dispatcher %p from %p" % [ key, configfile ]
210
+ Apache.request.server.log_notice( msg ) if defined?( Apache )
211
+ instances[ key ] = instances[ configfile ] = new( key, config )
212
+ end
213
+
214
+ return instances
215
+ end
216
+
217
+
218
+ #############################################################
219
+ ### I N S T A N C E M E T H O D S
220
+ #############################################################
221
+
222
+ ### Set up an Arrow::Dispatcher object based on the specified +config+
223
+ ### (an Arrow::Config object).
224
+ def initialize( name, config )
225
+ @name = name
226
+ @config = config
227
+
228
+ @broker = Arrow::Broker.new( config )
229
+ self.configure( config )
230
+ rescue ::Exception => err
231
+ msg = "%s while creating dispatcher: %s\n%s" %
232
+ [ err.class.name, err.message, err.backtrace.join("\n\t") ]
233
+ self.log.error( msg )
234
+ msg.gsub!( /%/, '%%' )
235
+ Apache.request.server.log_crit( msg ) unless !defined?( Apache )
236
+ end
237
+
238
+
239
+ ######
240
+ public
241
+ ######
242
+
243
+ ### The key used to indentify this dispatcher
244
+ attr_reader :name
245
+
246
+
247
+ ### (Re)configure the dispatcher based on the values in the given
248
+ ### +config+ (an Arrow::Config object).
249
+ def configure( config )
250
+ self.log.notice "Configuring a dispatcher for '%s' from '%s': child server %d" %
251
+ [ Apache.request.server.hostname, config.name, Process.pid ]
252
+
253
+ # Configure any modules that have mixed in Configurability
254
+ if defined?( Apache )
255
+ require 'apache/logger'
256
+ Configurability.logger = Logger.new( Apache::LogDevice.new )
257
+ Configurability.logger.formatter = Apache::LogFormatter.new
258
+ else
259
+ Configurability.reset_logger
260
+ end
261
+
262
+ Configurability.configure_objects( config )
263
+ end
264
+
265
+
266
+ ### mod_ruby Handlers
267
+
268
+ ### Child init mod_ruby handler
269
+ def child_init( req ) # :nodoc
270
+ self.log.notice "Dispatcher configured for %s" % [ req.server.hostname ]
271
+ return Apache::OK
272
+ end
273
+
274
+
275
+ ### The content handler method. Dispatches requests to registered
276
+ ### applets based on the requests PATH_INFO.
277
+ def handler( req )
278
+ self.log.info "--- Dispatching request %p ---------------" % [req]
279
+ self.log.debug "Request headers are: %s" % [untable(req.headers_in)]
280
+
281
+ if (( reason = @config.changed_reason ))
282
+ self.log.notice "** Reloading configuration: #{reason} ***"
283
+ @config.reload
284
+ @broker = Arrow::Broker.new( @config )
285
+ self.configure( @config )
286
+ end
287
+
288
+ if ! @broker
289
+ self.log.error "Fatal: No broker."
290
+ return Apache::SERVER_ERROR
291
+ end
292
+
293
+ txn = Arrow::Transaction.new( req, @config, @broker )
294
+
295
+ self.log.debug "Delegating transaction %p" % [txn]
296
+ unless output = @broker.delegate( txn )
297
+ self.log.info "Declining transaction (Applets returned: %p)" % output
298
+ return Apache::DECLINED
299
+ end
300
+
301
+ # If the transaction succeeded, set up the Apache::Request object, add
302
+ # headers, add session state, etc. If it failed, log the failure and let
303
+ # the status be returned as-is.
304
+ response_body = nil
305
+ self.log.debug "Transaction has status %d" % [txn.status]
306
+
307
+ # Render the output before anything else, as there might be
308
+ # session/header manipulation left to be done somewhere in the
309
+ # render. If the response is true, the applets have handled output
310
+ # themselves.
311
+ if output && output != true
312
+ rendertime = Benchmark.measure do
313
+ response_body = output.to_s
314
+ end
315
+ self.log.debug "Output render time: %s" %
316
+ rendertime.format( '%8.4us usr %8.4ys sys %8.4ts wall %8.4r' )
317
+ req.headers_out['content-length'] = response_body.length.to_s unless
318
+ req.headers_out['content-length']
319
+ end
320
+
321
+ # If the transaction has a session, save it
322
+ txn.session.save if txn.session?
323
+
324
+ # Add cookies to the response headers
325
+ txn.add_cookie_headers
326
+
327
+ self.log.debug "HTTP response status is: %d" % [txn.status]
328
+ self.log.debug "Response headers were: %s" % [untable(req.headers_out)]
329
+ txn.send_http_header
330
+ txn.print( response_body ) if response_body
331
+
332
+ self.log.info "--- Done with request %p (%s)---------------" %
333
+ [ req, req.status_line ]
334
+
335
+ req.sync = true
336
+ return txn.handler_status
337
+ rescue ::Exception => err
338
+ self.log.error "Dispatcher caught an unhandled %s: %s:\n\t%s" %
339
+ [ err.class.name, err.message, err.backtrace.join("\n\t") ]
340
+ return Apache::SERVER_ERROR
341
+
342
+ ensure
343
+ # Make sure session locks are released
344
+ txn.session.finish if txn && txn.session?
345
+ end
346
+
347
+
348
+ ### Return a human-readable representation of the receiver as a String.
349
+ def inspect
350
+ return "#<%s:0x%x config: %s>" % [
351
+ self.class.name,
352
+ self.object_id,
353
+ @config.name,
354
+ ]
355
+ end
356
+
357
+
358
+ def untable( table )
359
+ lines = []
360
+ table.each do |k,v|
361
+ lines << "%s: %s" % [ k, v ]
362
+ end
363
+
364
+ return lines.join( "; " )
365
+ end
366
+
367
+ end # class Arrow::Dispatcher
368
+
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'arrow'
4
+ require 'arrow/dispatcher'
5
+
6
+
7
+ ### A +RubyChildInitHandler+ class which loads one or more dispatchers
8
+ ### when a child server starts. This can eliminate the startup lag for
9
+ ### the first request each child handles. See the docs for dispatcher.rb
10
+ ### for an example of how to use this.
11
+ class Arrow::DispatcherLoader
12
+
13
+ ### Create a loader that will create dispatchers from the given
14
+ ### +hostsfile+, which is a YAML hash that maps dispatcher names to
15
+ ### a configfile path.
16
+ def initialize( hostsfile )
17
+ require 'arrow/applet'
18
+ require 'arrow/dispatcher'
19
+ require 'arrow/broker'
20
+
21
+ @hostsfile = hostsfile
22
+ end
23
+
24
+
25
+ ### Load the dispatchers according to the registered hosts file.
26
+ def child_init( req )
27
+ req.server.log_info( "Loading dispatcher configs from " + @hostsfile + "." )
28
+ Arrow::Dispatcher.create_from_hosts_file( @hostsfile )
29
+
30
+ return Apache::OK
31
+ rescue ::Exception => err
32
+ errmsg = "%s failed to load dispatchers (%s): %s: %s" % [
33
+ self.class.name,
34
+ err.class.name,
35
+ err.message,
36
+ err.backtrace.join("\n ")
37
+ ]
38
+
39
+ logfile = Pathname.new( Dir.tmpdir ) + 'arrow-dispatcher-failure.log'
40
+ logfile.open( IO::WRONLY|IO::TRUNC|IO::CREAT ) do |ofh|
41
+ ofh.puts( errmsg )
42
+ ofh.flush
43
+ end
44
+
45
+ Apache.request.server.log_crit( errmsg )
46
+ raise
47
+ end
48
+
49
+ end # class Arrow::DispatcherLoader
50
+
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env ruby
2
+ module Arrow # :nodoc:
3
+
4
+ ### Base exception class
5
+ class Exception < StandardError
6
+ Message = "Arrow framework error"
7
+
8
+ def initialize( message=nil )
9
+ message ||= self.class.const_get( "Message" )
10
+ super( message )
11
+ end
12
+ end
13
+
14
+ ### Define an exception class with the specified <tt>name</tt> (a Symbol)
15
+ ### with the specified <tt>message</tt>. The new exception class will
16
+ ### inherit from the specified <tt>superclass</tt>, if specified, or
17
+ ### <tt>StandardError</tt> if not specified.
18
+ def Arrow.def_exception( name, message, superclass=Arrow::Exception )
19
+ name = name.id2name if name.kind_of?( Fixnum )
20
+ eClass = Class.new( superclass )
21
+ eClass.module_eval %Q{
22
+ def initialize( *args )
23
+ if ! args.empty?
24
+ msg = args.collect {|a| a.to_s}.join
25
+ super( msg )
26
+ else
27
+ super( message )
28
+ end
29
+ end
30
+ }
31
+
32
+ const_set( name, eClass )
33
+ end
34
+
35
+
36
+ # System exceptions
37
+ def_exception :ConfigError, "Configuration error"
38
+ def_exception :LockingError, "Locking error"
39
+ def_exception :SessionError, "Error in session"
40
+
41
+ # Templating errors
42
+ def_exception :TemplateError, "Error in templating system"
43
+ def_exception :ParseError, "Error while parsing",
44
+ TemplateError
45
+ def_exception :ScopeError, "Error in rendering scope",
46
+ TemplateError
47
+
48
+ # Signal exceptions
49
+ def_exception :Reload, "Configuration out of date"
50
+ def_exception :Shutdown, "Server shutdown"
51
+
52
+ # Applet errors
53
+ def_exception :AppletError, "Applet error"
54
+ def_exception :AppletChainError, "Malformed applet chain"
55
+
56
+ # Datasource errors
57
+ def_exception :TypeError, "Data type incompatible"
58
+ def_exception :LoadError, "Loading failed"
59
+
60
+ end # module Arrow
61
+