trinidad 1.4.1 → 1.4.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,6 @@
1
+ require 'trinidad/lifecycle/base'
2
+ require 'trinidad/lifecycle/web_app/shared'
3
+
1
4
  module Trinidad
2
5
  module Lifecycle
3
6
  module WebApp
@@ -15,7 +18,7 @@ module Trinidad
15
18
  end
16
19
 
17
20
  def configure(context)
18
- super
21
+ super # TODO assuming warbler .war !
19
22
  configure_class_loader(context)
20
23
  end
21
24
 
@@ -32,7 +35,7 @@ module Trinidad
32
35
  def expand_war_app(context)
33
36
  unless File.exist?(context.doc_base)
34
37
  host = context.parent
35
- war_file = java.io.File.new(web_app.web_app_dir)
38
+ war_file = java.io.File.new(web_app.root_dir)
36
39
  war = java.net.URL.new("jar:" + war_file.toURI.toURL.to_s + "!/")
37
40
  path_name = File.basename(context.doc_base)
38
41
 
@@ -42,7 +45,7 @@ module Trinidad
42
45
 
43
46
  def remove_war_app(context)
44
47
  require 'fileutils'
45
- FileUtils.rm_rf web_app.web_app_dir.gsub(/\.war$/, '')
48
+ FileUtils.rm_rf web_app.root_dir.gsub(/\.war$/, '')
46
49
  end
47
50
 
48
51
  end
@@ -1,3 +1,6 @@
1
+ require 'trinidad/configuration'
2
+ require 'trinidad/web_app'
3
+
1
4
  module Trinidad
2
5
  class Server
3
6
  attr_reader :config, :tomcat, :web_apps
@@ -40,15 +43,15 @@ module Trinidad
40
43
  end
41
44
 
42
45
  def ssl_enabled?
43
- @config[:ssl] && !@config[:ssl].empty?
46
+ !! @config[:ssl] && ! @config[:ssl].empty?
44
47
  end
45
48
 
46
49
  def ajp_enabled?
47
- @config[:ajp] && !@config[:ajp].empty?
50
+ !! @config[:ajp] && ! @config[:ajp].empty?
48
51
  end
49
52
 
50
53
  def http_configured?
51
- (@config[:http] && !@config[:http].empty?) || @config[:address] != 'localhost'
54
+ (!! @config[:http] && ! @config[:http].empty?) || @config[:address] != 'localhost'
52
55
  end
53
56
 
54
57
  def add_ajp_connector
@@ -107,10 +110,10 @@ module Trinidad
107
110
 
108
111
  def add_web_app(web_app, host = nil)
109
112
  host ||= web_app.config[:host] || @tomcat.host
110
- app_context = @tomcat.addWebapp(host, web_app.context_path, web_app.web_app_dir)
111
- Trinidad::Extensions.configure_webapp_extensions(web_app.extensions, @tomcat, app_context)
112
- app_context.add_lifecycle_listener(web_app.define_lifecycle)
113
- app_context
113
+ context = @tomcat.addWebapp(host, web_app.context_path, web_app.root_dir)
114
+ Trinidad::Extensions.configure_webapp_extensions(web_app.extensions, @tomcat, context)
115
+ context.add_lifecycle_listener(web_app.define_lifecycle)
116
+ context
114
117
  end
115
118
 
116
119
  def start
@@ -144,9 +147,7 @@ module Trinidad
144
147
 
145
148
  def create_from_web_apps
146
149
  @config[:web_apps].map do |name, app_config|
147
- app_config[:context_path] ||= (name.to_s == 'default' ? '' : "/#{name}")
148
- app_config[:web_app_dir] ||= Dir.pwd
149
-
150
+ app_config[:context_name] ||= name
150
151
  create_web_app(app_config)
151
152
  end if @config[:web_apps]
152
153
  end
@@ -163,11 +164,10 @@ module Trinidad
163
164
 
164
165
  apps_path.map do |path|
165
166
  if File.directory?(path) || path =~ /\.war$/
166
- name = File.basename(path)
167
167
  create_web_app({
168
- :context_path => (name.to_s == 'default' ? '' : "/#{name}"),
169
- :web_app_dir => File.expand_path(path),
170
- :host => host
168
+ :context_name => File.basename(path),
169
+ :root_dir => File.expand_path(path),
170
+ :host => host
171
171
  })
172
172
  end
173
173
  end
@@ -1,3 +1,3 @@
1
1
  module Trinidad
2
- VERSION = '1.4.1'
2
+ VERSION = '1.4.3'
3
3
  end
@@ -1,6 +1,10 @@
1
+ require 'trinidad/configuration'
2
+
1
3
  module Trinidad
2
4
  class WebApp
3
5
 
6
+ @@defaults = Trinidad::Configuration::DEFAULTS
7
+
4
8
  attr_reader :config, :default_config
5
9
 
6
10
  def self.create(config, default_config = Trinidad.configuration)
@@ -17,22 +21,98 @@ module Trinidad
17
21
 
18
22
  def [](key)
19
23
  key = key.to_sym
20
- config.has_key?(key) ? config[key] : default_config[key]
24
+ config.key?(key) ? config[key] : default_config[key]
25
+ end
26
+
27
+ def key?(key, use_default = true)
28
+ key = key.to_sym
29
+ return true if config.has_key?(key)
30
+ use_default ? default_config.key?(key) : false
21
31
  end
22
32
 
23
- %w{ context_path web_app_dir libs_dir classes_dir async_supported
24
- jruby_min_runtimes jruby_max_runtimes jruby_compat_version rackup log
25
- reload_strategy }.each do |method|
33
+ %w{ root_dir jruby_compat_version
34
+ rackup log async_supported reload_strategy }.each do |method|
26
35
  class_eval "def #{method}; self[:'#{method}']; end"
27
36
  end
37
+ alias_method :web_app_dir, :root_dir # is getting deprecated soon
38
+
39
+ def context_path
40
+ path = self[:context_path] || self[:path]
41
+ path ? path.to_s : path
42
+ end
43
+
44
+ def context_name
45
+ name = self[:context_name] || self[:name]
46
+ name ? name.to_s : name
47
+ end
48
+
49
+ # NOTE: should be set to application root (base) directory thus
50
+ # JRuby-Rack correctly resolves relative paths for the context!
51
+ def doc_base; self[:doc_base] || root_dir; end
28
52
 
53
+ def jruby_min_runtimes
54
+ if min = config[:jruby_min_runtimes]
55
+ return min.to_i # min specified overrides :threadsafe
56
+ else # but :threadsafe takes precendence over default :
57
+ self[:threadsafe] ? 1 : default_config[:jruby_min_runtimes]
58
+ end
59
+ end
60
+
61
+ def jruby_max_runtimes
62
+ if max = config[:jruby_max_runtimes]
63
+ return max.to_i # max specified overrides :threadsafe
64
+ else # but :threadsafe takes precendence over default :
65
+ self[:threadsafe] ? 1 : default_config[:jruby_max_runtimes]
66
+ end
67
+ end
68
+
69
+ def jruby_runtime_acquire_timeout
70
+ self[:jruby_runtime_acquire_timeout] || 5.0 # default 10s seems too high
71
+ end
72
+
73
+ def environment; self[:environment] || @@defaults[:environment]; end # TODO check web.xml
74
+
75
+ def public_dir
76
+ @public_dir ||= expand_path(public_root)
77
+ end
78
+
79
+ # by (a "Rails") convention use '[RAILS_ROOT]/tmp'
80
+ def work_dir
81
+ @work_dir ||= self[:work_dir] || File.join(root_dir, 'tmp')
82
+ end
83
+
84
+ # by a "Rails" convention defaults to '[RAILS_ROOT]/log'
85
+ def log_dir
86
+ @log_dir ||= self[:log_dir] || File.join(root_dir, 'log')
87
+ end
88
+
89
+ def monitor
90
+ File.expand_path(self[:monitor] || 'restart.txt', work_dir)
91
+ end
92
+
93
+ def context_xml; self[:context_xml] || self[:default_context_xml]; end
29
94
  def web_xml; self[:web_xml] || self[:default_web_xml]; end
30
95
  def default_web_xml; self[:default_web_xml]; end
31
96
 
32
- def public_root; self[:public] || 'public'; end
33
- def environment; self[:environment] || 'development'; end
34
- def work_dir; self[:work_dir] || web_app_dir; end
35
- def log_dir; self[:log_dir] || File.join(work_dir, 'log'); end
97
+ def java_lib
98
+ # accepts #deprecated :libs_dir syntax
99
+ self[:java_lib] || self[:libs_dir] || @@defaults[:java_lib]
100
+ end
101
+
102
+ def java_classes
103
+ # accepts #deprecated :classes_dir syntax
104
+ self[:java_classes] || self[:classes_dir] || File.join(java_lib, 'classes')
105
+ end
106
+
107
+ def java_lib_dir
108
+ @java_lib_dir ||= self[:java_lib_dir] || expand_path(java_lib)
109
+ end
110
+ alias_method :libs_dir, :java_lib_dir # #deprecated
111
+
112
+ def java_classes_dir
113
+ @java_classes_dir ||= self[:java_classes_dir] || expand_path(java_classes)
114
+ end
115
+ alias_method :classes_dir, :java_classes_dir # #deprecated
36
116
 
37
117
  def extensions
38
118
  @extensions ||= begin
@@ -40,16 +120,13 @@ module Trinidad
40
120
  extensions.merge(config[:extensions] || {})
41
121
  end
42
122
  end
43
-
44
- def monitor
45
- File.expand_path(self[:monitor] || 'tmp/restart.txt', work_dir)
46
- end
47
123
 
48
124
  def context_params
49
125
  @context_params ||= {}
50
126
  add_context_param 'jruby.min.runtimes', jruby_min_runtimes
51
127
  add_context_param 'jruby.max.runtimes', jruby_max_runtimes
52
128
  add_context_param 'jruby.initial.runtimes', jruby_min_runtimes
129
+ add_context_param 'jruby.runtime.acquire.timeout', jruby_runtime_acquire_timeout
53
130
  add_context_param 'jruby.compat.version', jruby_compat_version || RUBY_VERSION
54
131
  add_context_param 'public.root', File.join('/', public_root)
55
132
  @context_params
@@ -65,22 +142,80 @@ module Trinidad
65
142
  end
66
143
 
67
144
  def deployment_descriptor
68
- @deployment_descriptor ||= if web_xml
69
- file = File.expand_path(File.join(work_dir, web_xml))
70
- File.exist?(file) ? file : nil
71
- end
145
+ return nil if @deployment_descriptor == false
146
+ @deployment_descriptor ||= expand_path(web_xml) || false
72
147
  end
73
148
 
74
149
  # @deprecated use {#deployment_descriptor}
75
150
  def default_deployment_descriptor
76
- @default_deployment_descriptor ||= if default_web_xml
77
- file = File.expand_path(File.join(work_dir, default_web_xml))
78
- File.exist?(file) ? file : nil
151
+ return nil if @default_deployment_descriptor == false
152
+ @default_deployment_descriptor ||= expand_path(default_web_xml) || false
153
+ end
154
+
155
+ def public_root
156
+ @public_root ||= ( public_config[:root] || @@defaults[:public] )
157
+ end
158
+ alias_method :public, :public_root
159
+
160
+ # we do support nested :public configuration e.g. :
161
+ # public:
162
+ # root: /assets
163
+ # cache: true
164
+ # cache_ttl: 60000
165
+ def public_config
166
+ @public_config ||=
167
+ self[:public].is_a?(String) ?
168
+ { :root => self[:public] } :
169
+ ( self[:public] || {} )
170
+ end
171
+
172
+ def aliases # :public => { :aliases => ... }
173
+ return nil unless aliases = ( self[:aliases] || public_config[:aliases] )
174
+ return aliases if aliases.is_a?(String)
175
+ # "/aliasPath1=docBase1,/aliasPath2=docBase2"
176
+ @aliases ||= aliases.map do |path, base|
177
+ path = path.to_s
178
+ if (root = '/') != path[0, 1]
179
+ path = (root << path)
180
+ end
181
+ "#{path}=#{File.expand_path(base, root_dir)}"
182
+ end.join(',')
183
+ end
184
+
185
+ def caching_allowed? # :public => { :cached => ... }
186
+ # ((BaseDirContext) resources).setCached(isCachingAllowed())
187
+ return @caching_allowed unless @caching_allowed.nil?
188
+ @caching_allowed = self[:caching_allowed]
189
+ if @caching_allowed.nil?
190
+ @caching_allowed = public_config[:cached]
191
+ if @caching_allowed.nil?
192
+ @caching_allowed = environment != 'development'
193
+ end
79
194
  end
195
+ @caching_allowed = !! @caching_allowed
196
+ end
197
+
198
+ # The cache max size in kB
199
+ def cache_max_size # :public => { :cache_max_size => ... }
200
+ # ((BaseDirContext) resources).setCacheMaxSize
201
+ self[:cache_max_size] || public_config[:cache_max_size]
202
+ end
203
+
204
+ # The max size for a cached object in kB
205
+ def cache_object_max_size # :public => { :cache_object_max_size => ... }
206
+ # ((BaseDirContext) resources).setCacheObjectMaxSize
207
+ self[:cache_object_max_size] || public_config[:cache_object_max_size]
208
+ end
209
+
210
+ # Cache entry time-to-live in millis
211
+ def cache_ttl # :public => { :cache_ttl => ... }
212
+ # ((BaseDirContext) resources).setCacheTTL
213
+ self[:cache_ttl] || public_config[:cache_ttl]
80
214
  end
81
215
 
82
216
  def class_loader
83
- @class_loader ||= org.jruby.util.JRubyClassLoader.new(JRuby.runtime.jruby_class_loader)
217
+ @class_loader ||=
218
+ org.jruby.util.JRubyClassLoader.new(JRuby.runtime.jruby_class_loader)
84
219
  end
85
220
 
86
221
  def class_loader!
@@ -94,29 +229,108 @@ module Trinidad
94
229
  end
95
230
 
96
231
  # Reset the hold web application state so it gets re-initialized.
97
- # Please note that the received configuration object are not cleared.
232
+ # Please note that the configuration objects are not cleared.
98
233
  def reset!
99
234
  vars = instance_variables.map(&:to_sym)
100
235
  vars = vars - [ :'@config', :'@default_config' ]
101
236
  vars.each { |var| instance_variable_set(var, nil) }
102
237
  end
103
238
 
239
+ DEFAULT_SERVLET_CLASS = nil # by default we resolve by it's name
240
+ DEFAULT_SERVLET_NAME = 'default'
241
+
242
+ # Returns a servlet config for the DefaultServlet.
243
+ # This servlet is setup for each and every Tomcat context and is named
244
+ # 'default' and mapped to '/' we allow fine tunning of this servlet.
245
+ # Return values should be interpreted as follows :
246
+ # true - do nothing leave the servlet as set-up (by default)
247
+ # false - remove the set-up default (e.g. configured in web.xml)
248
+ def default_servlet
249
+ return @default_servlet unless @default_servlet.nil?
250
+ @default_servlet ||= begin
251
+ if ! web_xml_servlet?(DEFAULT_SERVLET_CLASS, DEFAULT_SERVLET_NAME)
252
+ default_servlet = self[:default_servlet]
253
+ if default_servlet.is_a?(javax.servlet.Servlet)
254
+ { :instance => default_servlet }
255
+ elsif default_servlet == false
256
+ false # forced by user to remove
257
+ elsif default_servlet == true
258
+ true # forced by user to leave as is
259
+ else
260
+ default_servlet = {} if default_servlet.nil?
261
+ unless default_servlet.key?(:class)
262
+ # we use a custom class by default to server /public assets :
263
+ default_servlet[:class] = 'rb.trinidad.servlets.DefaultServlet'
264
+ end
265
+ default_servlet
266
+ end
267
+ else
268
+ false # configured in web.xml thus remove the (default) "default"
269
+ end
270
+ end
271
+ end
272
+
273
+ JSP_SERVLET_CLASS = nil # by default we resolve by it's name
274
+ JSP_SERVLET_NAME = 'jsp'
275
+
276
+ # Returns a servlet config for the JspServlet.
277
+ # This servlet is setup by default for every Tomcat context and is named
278
+ # 'jsp' with '*.jsp' and '*.jspx' mappings.
279
+ # Return values should be interpreted as follows :
280
+ # true - do nothing leave the servlet as set-up (by default)
281
+ # false - remove the set-up servlet (by default we do not need jsp support)
282
+ def jsp_servlet
283
+ return @jsp_servlet unless @jsp_servlet.nil?
284
+ @jsp_servlet ||= begin
285
+ if ! web_xml_servlet?(JSP_SERVLET_CLASS, JSP_SERVLET_NAME)
286
+ jsp_servlet = self[:jsp_servlet]
287
+ if jsp_servlet.is_a?(javax.servlet.Servlet)
288
+ { :instance => jsp_servlet }
289
+ else
290
+ jsp_servlet || false # remove jsp support unless specified
291
+ end
292
+ else
293
+ false # configured in web.xml thus remove the default "jsp"
294
+ end
295
+ end
296
+ end
297
+
298
+ RACK_SERVLET_CLASS = 'org.jruby.rack.RackServlet'
299
+ RACK_SERVLET_NAME = 'rack' # in-case of a "custom" rack servlet class
300
+ RACK_FILTER_CLASS = 'org.jruby.rack.RackFilter'
301
+ RACK_FILTER_NAME = 'rack'
302
+
303
+ # Returns a config for the RackServlet or nil if no need to set-up one.
304
+ # (to be used for dispatching to this Rack / Rails web application)
104
305
  def rack_servlet
105
306
  return nil if @rack_servlet == false
106
307
  @rack_servlet ||= begin
107
- servlet_config = self[:servlet] || {}
108
- servlet_class = servlet_config[:class] || 'org.jruby.rack.RackServlet'
109
- servlet_name = servlet_config[:name] || 'RackServlet'
110
-
111
- if ! web_xml_servlet?(servlet_class, servlet_name) &&
112
- ! web_xml_filter?('org.jruby.rack.RackFilter')
113
- {
114
- :class => servlet_class, :name => servlet_name,
115
- :async_supported => !! servlet_config[:async_supported],
116
- :instance => servlet_config[:instance]
117
- }
308
+ rack_servlet = self[:rack_servlet] || self[:servlet] || {}
309
+
310
+ if rack_servlet.is_a?(javax.servlet.Servlet)
311
+ { :instance => rack_servlet, :name => RACK_SERVLET_NAME, :mapping => '/*' }
118
312
  else
119
- false # no need to setup a rack servlet
313
+ servlet_class = rack_servlet[:class] || RACK_SERVLET_CLASS
314
+ servlet_name = rack_servlet[:name] || RACK_SERVLET_NAME
315
+
316
+ if ! web_xml_servlet?(servlet_class, servlet_name) &&
317
+ ! web_xml_filter?(RACK_FILTER_CLASS, RACK_FILTER_NAME)
318
+ {
319
+ :instance => rack_servlet[:instance],
320
+ :class => servlet_class, :name => servlet_name,
321
+ :init_params => rack_servlet[:init_params],
322
+ :async_supported => !! ( rack_servlet.has_key?(:async_supported) ?
323
+ rack_servlet[:async_supported] : async_supported ),
324
+ :load_on_startup => ( rack_servlet[:load_on_startup] || 2 ).to_i,
325
+ :mapping => rack_servlet[:mapping] || '/*'
326
+ }
327
+ else
328
+ if ! rack_servlet.empty?
329
+ logger.info "ignoring :rack_servlet configuration for " +
330
+ "#{context_path} due #{deployment_descriptor}"
331
+ end
332
+ false # no need to setup a rack servlet
333
+ end
120
334
  end
121
335
  end || nil
122
336
  end
@@ -132,9 +346,9 @@ module Trinidad
132
346
  def solo?
133
347
  ! is_a?(WarWebApp) && config[:solo]
134
348
  end
135
-
349
+
136
350
  def threadsafe?
137
- jruby_min_runtimes.to_i == 1 && jruby_max_runtimes.to_i == 1
351
+ jruby_min_runtimes == 1 && jruby_max_runtimes == 1
138
352
  end
139
353
 
140
354
  protected
@@ -144,34 +358,56 @@ module Trinidad
144
358
  end
145
359
 
146
360
  def complete_config!
147
- config[:web_app_dir] ||= default_config[:web_app_dir] || Dir.pwd
361
+ config[:root_dir] ||= self.class.root_dir(config, default_config)
362
+ config[:context_path] = self.class.context_path(config, default_config)
148
363
  end
149
364
 
150
365
  public
151
366
 
367
+ # Returns true if there's a servlet with the given servlet-class name
368
+ # configured or if the optional name second argument is given it also
369
+ # checks for a servlet with the given name.
152
370
  def web_xml_servlet?(servlet_class, servlet_name = nil)
153
- !!( web_xml_doc && (
154
- web_xml_doc.root.elements["/web-app/servlet[servlet-class = '#{servlet_class}']"]
155
- )
156
- )
371
+ return nil unless web_xml_doc
372
+ if servlet_class
373
+ servlet_xpath = "/web-app/servlet[servlet-class = '#{servlet_class}']"
374
+ return true if web_xml_doc.root.elements[servlet_xpath] # else try name
375
+ end
376
+ if servlet_name
377
+ servlet_xpath = "/web-app/servlet[servlet-name = '#{servlet_name}']"
378
+ return !! web_xml_doc.root.elements[servlet_xpath]
379
+ end
380
+
381
+ return false if servlet_class || servlet_name
382
+ raise ArgumentError, "nor servlet_class nor servlet_name given"
157
383
  end
158
384
 
159
- def web_xml_filter?(filter_class)
160
- !!( web_xml_doc && (
161
- web_xml_doc.root.elements["/web-app/filter[filter-class = '#{filter_class}']"]
162
- )
163
- )
385
+ # Returns true if a filter definition with a given filter-class is found.
386
+ def web_xml_filter?(filter_class, filter_name = nil)
387
+ return nil unless web_xml_doc
388
+ if filter_class
389
+ filter_xpath = "/web-app/filter[filter-class = '#{filter_class}']"
390
+ return true if web_xml_doc.root.elements[filter_xpath] # else try name
391
+ end
392
+ if filter_name
393
+ filter_xpath = "/web-app/filter[filter-name = '#{filter_name}']"
394
+ return !! web_xml_doc.root.elements[filter_xpath]
395
+ end
396
+
397
+ return false if filter_class || filter_name
398
+ raise ArgumentError, "nor filter_class nor filter_name given"
164
399
  end
165
400
 
401
+ # Returns true if a listener definition with a given listener-class is found.
166
402
  def web_xml_listener?(listener_class)
167
- !!( web_xml_doc &&
168
- web_xml_doc.root.elements["/web-app/listener[listener-class = '#{listener_class}']"]
169
- )
403
+ return nil unless web_xml_doc
404
+ !! web_xml_doc.root.elements["/web-app/listener[listener-class = '#{listener_class}']"]
170
405
  end
171
406
 
407
+ # Returns a param-value for a context-param with a given param-name.
172
408
  def web_xml_context_param(name)
173
- if web_xml_doc &&
174
- param = web_xml_doc.root.elements["/web-app/context-param[param-name = '#{name}']"]
409
+ return nil unless web_xml_doc
410
+ if param = web_xml_doc.root.elements["/web-app/context-param[param-name = '#{name}']"]
175
411
  param.elements['param-value'].text
176
412
  end
177
413
  end
@@ -180,54 +416,99 @@ module Trinidad
180
416
 
181
417
  def web_xml_doc
182
418
  return @web_xml_doc || nil unless @web_xml_doc.nil?
183
- if deployment_descriptor
419
+ descriptor = deployment_descriptor
420
+ if descriptor && File.exist?(descriptor)
184
421
  begin
185
422
  require 'rexml/document'
186
- @web_xml_doc = REXML::Document.new(File.read(deployment_descriptor))
423
+ @web_xml_doc = REXML::Document.new(File.read(descriptor))
187
424
  rescue REXML::ParseException => e
188
- log = Trinidad::Logging::LogFactory.getLog('')
189
- log.warn "invalid deployment descriptor:[#{deployment_descriptor}]\n #{e.message}"
425
+ logger.warn "invalid deployment descriptor:[#{descriptor}]\n #{e.message}"
190
426
  @web_xml_doc = false
191
427
  end
192
428
  @web_xml_doc || nil
193
429
  end
194
430
  end
195
431
 
432
+ def expand_path(path)
433
+ if path
434
+ path_file = java.io.File.new(path)
435
+ if path_file.absolute?
436
+ path_file.absolute_path
437
+ else
438
+ File.expand_path(path, root_dir)
439
+ end
440
+ end
441
+ end
442
+
443
+ def logger
444
+ @logger ||= Trinidad::Logging::LogFactory.getLog('')
445
+ end
446
+
196
447
  protected
197
448
 
198
449
  def self.rackup?(config, default_config = nil)
199
450
  return true if config.has_key?(:rackup)
200
- web_app_dir = config[:web_app_dir] ||
201
- (default_config && default_config[:web_app_dir]) || Dir.pwd
451
+ root_dir = root_dir(config, default_config)
202
452
  config_ru = (default_config && default_config[:rackup]) || 'config.ru'
203
453
  # check for rackup (but still use config/environment.rb for rails 3)
204
- if File.exists?(File.join(web_app_dir, config_ru)) &&
454
+ if File.exists?(File.join(root_dir, config_ru)) &&
205
455
  ! rails?(config, default_config) # do not :rackup a rails app
206
456
  config[:rackup] = config_ru
207
457
  end
208
- config[:rackup] || ! Dir[File.join(web_app_dir, 'WEB-INF/**/config.ru')].empty?
458
+ config[:rackup] || ! Dir[File.join(root_dir, 'WEB-INF/**/config.ru')].empty?
209
459
  end
210
460
 
211
461
  def self.rails?(config, default_config = nil)
212
- web_app_dir = config[:web_app_dir] ||
213
- (default_config && default_config[:web_app_dir]) || Dir.pwd
462
+ root_dir = root_dir(config, default_config)
214
463
  # standart Rails 3.x `class Application < Rails::Application`
215
- if File.exists?(application = File.join(web_app_dir, 'config/application.rb'))
216
- application_rb = File.read(application)
217
- return true if application_rb =~ /^[^#]*Rails::Application/
464
+ if File.exists?(application = File.join(root_dir, 'config/application.rb'))
465
+ return true if file_line_match?(application, /^[^#]*Rails::Application/)
218
466
  end
219
- if File.exists?(environment = File.join(web_app_dir, 'config/environment.rb'))
220
- environment_rb = File.read(environment)
221
- # customized Rails 3.x, expect a `Rails::Application` subclass
222
- return true if environment_rb =~ /^[^#]*Rails::Application/
223
- # plain-old Rails 2.3 `RAILS_GEM_VERSION = '2.3.14'` ...
224
- return true if environment_rb =~ /^[^#]*RAILS_GEM_VERSION/
467
+ if File.exists?(environment = File.join(root_dir, 'config/environment.rb'))
468
+ return true if file_line_match?(environment) do |line|
469
+ # customized Rails 3.x, expects a `Rails::Application` subclass
470
+ # or a plain-old Rails 2.3 with `RAILS_GEM_VERSION = '2.3.14'`
471
+ line =~ /^[^#]*Rails::Application/ || line =~ /^[^#]*RAILS_GEM_VERSION/
472
+ end
225
473
  end
226
474
  false
227
475
  end
228
476
 
229
477
  def self.war?(config, default_config = nil)
230
- config[:context_path] && config[:context_path][-4..-1] == '.war'
478
+ config[:context_path] && config[:context_path].to_s[-4..-1] == '.war'
479
+ end
480
+
481
+ private
482
+
483
+ def self.root_dir(config, default_config)
484
+ # for backwards compatibility accepts the :web_app_dir "alias"
485
+ config[:root_dir] || config[:web_app_dir] ||
486
+ ( default_config &&
487
+ ( default_config[:root_dir] || default_config[:web_app_dir] ) ) ||
488
+ Dir.pwd
489
+ end
490
+
491
+ def self.context_path(config, default_config = nil)
492
+ path = config[:context_path] ||
493
+ ( default_config && default_config[:context_path] )
494
+ unless path
495
+ name = config[:context_name] ||
496
+ ( default_config && default_config[:context_name] )
497
+ path = name.to_s == 'default' ? '/' : "/#{name}"
498
+ end
499
+ path = "/#{path}" if path.to_s[0, 1] != '/'
500
+ path.to_s
501
+ end
502
+
503
+ def self.file_line_match?(path, pattern = nil)
504
+ File.open(path) do |file|
505
+ if block_given?
506
+ file.each_line { |line| return true if yield(line) }
507
+ else
508
+ file.each_line { |line| return true if line =~ pattern }
509
+ end
510
+ end
511
+ false
231
512
  end
232
513
 
233
514
  class Holder
@@ -251,7 +532,7 @@ module Trinidad
251
532
  def lock; @lock = true; end
252
533
  def unlock; @lock = false; end
253
534
 
254
- # @deprecated behaves Hash like for (<= 1.3.5) compatibility
535
+ # #deprecated behaves Hash like for (<= 1.3.5) compatibility
255
536
  def [](key)
256
537
  case key.to_sym
257
538
  when :app then
@@ -268,7 +549,7 @@ module Trinidad
268
549
  end
269
550
  end
270
551
 
271
- # @deprecated behaves Hash like for (<= 1.3.5) compatibility
552
+ # #deprecated behaves Hash like for (<= 1.3.5) compatibility
272
553
  def []=(key, val)
273
554
  case key.to_sym
274
555
  when :context then
@@ -317,9 +598,9 @@ module Trinidad
317
598
  def complete_config!
318
599
  super
319
600
  # detect threadsafe! in config/environments/environment.rb :
320
- if self.class.threadsafe?(web_app_dir, environment)
321
- config[:jruby_min_runtimes] = 1
322
- config[:jruby_max_runtimes] = 1
601
+ if ! key?(:threadsafe) && self.class.threadsafe?(root_dir, environment)
602
+ config[:jruby_min_runtimes] = 1 unless key?(:jruby_min_runtimes, false)
603
+ config[:jruby_max_runtimes] = 1 unless key?(:jruby_max_runtimes, false)
323
604
  end
324
605
  end
325
606
 
@@ -331,7 +612,7 @@ module Trinidad
331
612
  end
332
613
 
333
614
  def self.threadsafe_match?(file)
334
- File.exist?(file) && File.readlines(file).any? { |l| l =~ /^[^#]*threadsafe!/ }
615
+ File.exist?(file) && file_line_match?(file, /^[^#]*threadsafe!/)
335
616
  end
336
617
 
337
618
  end
@@ -343,12 +624,16 @@ module Trinidad
343
624
  super.gsub(/\.war$/, '')
344
625
  end
345
626
 
627
+ def log_dir
628
+ @log_dir ||= self[:log_dir] || File.join(work_dir, 'log')
629
+ end
630
+
346
631
  def work_dir
347
- File.join(web_app_dir.gsub(/\.war$/, ''), 'WEB-INF')
632
+ @work_dir ||= File.join(root_dir.gsub(/\.war$/, ''), 'WEB-INF')
348
633
  end
349
634
 
350
635
  def monitor
351
- File.expand_path(web_app_dir)
636
+ File.expand_path(root_dir)
352
637
  end
353
638
 
354
639
  def define_lifecycle