trinidad 1.3.5 → 1.4.0.RC

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.
@@ -0,0 +1,53 @@
1
+ module Trinidad
2
+ module Lifecycle
3
+ module WebApp
4
+ # Shared web application lifecycle hook,
5
+ # does #configure before the context starts.
6
+ module Shared
7
+
8
+ attr_reader :web_app
9
+ alias_method :webapp, :web_app
10
+
11
+ def initialize(web_app)
12
+ @web_app = web_app
13
+ end
14
+
15
+ # @see Trinidad::Lifecycle::Base#before_start
16
+ def before_start(event)
17
+ super
18
+ configure(event.lifecycle)
19
+ end
20
+
21
+ # Configure the web application before it's started.
22
+ def configure(context)
23
+ remove_defaults(context)
24
+ configure_logging(context)
25
+ end
26
+
27
+ protected
28
+
29
+ def configure_logging(context)
30
+ Trinidad::Logging.configure_web_app(web_app, context)
31
+ end
32
+
33
+ private
34
+
35
+ def remove_defaults(context)
36
+ context.remove_welcome_file('index.jsp')
37
+ context.remove_welcome_file('index.htm')
38
+ context.remove_welcome_file('index.html')
39
+
40
+ jsp_servlet = context.find_child('jsp')
41
+ context.remove_child(jsp_servlet) if jsp_servlet
42
+
43
+ context.remove_servlet_mapping('*.jspx')
44
+ context.remove_servlet_mapping('*.jsp')
45
+
46
+ context.process_tlds = false
47
+ context.xml_validation = false
48
+ end
49
+
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,52 @@
1
+ module Trinidad
2
+ module Lifecycle
3
+ module WebApp
4
+ class War < Base
5
+ include Shared
6
+
7
+ def before_start(event)
8
+ expand_war_app(event.lifecycle)
9
+ super # Shared#before_start
10
+ end
11
+
12
+ def after_start(event)
13
+ super
14
+ remove_war_app(event.lifecycle)
15
+ end
16
+
17
+ def configure(context)
18
+ super
19
+ configure_class_loader(context)
20
+ end
21
+
22
+ protected
23
+
24
+ def configure_class_loader(context)
25
+ loader = Trinidad::Tomcat::WebappLoader.new(web_app.class_loader)
26
+ loader.container = context
27
+ context.loader = loader
28
+ end
29
+
30
+ private
31
+
32
+ def expand_war_app(context)
33
+ unless File.exist?(context.doc_base)
34
+ host = context.parent
35
+ war_file = java.io.File.new(web_app.web_app_dir)
36
+ war = java.net.URL.new("jar:" + war_file.toURI.toURL.to_s + "!/")
37
+ path_name = File.basename(context.doc_base)
38
+
39
+ Trinidad::Tomcat::ExpandWar.expand(host, war, path_name)
40
+ end
41
+ end
42
+
43
+ def remove_war_app(context)
44
+ require 'fileutils'
45
+ FileUtils.rm_rf web_app.web_app_dir.gsub(/\.war$/, '')
46
+ end
47
+
48
+ end
49
+ end
50
+ War = Trinidad::Lifecycle::WebApp::War # backwards compatibility
51
+ end
52
+ end
@@ -0,0 +1,282 @@
1
+ require 'jruby'
2
+ require 'fileutils'
3
+
4
+ module Trinidad
5
+ module Logging
6
+
7
+ JUL = Java::JavaUtilLogging
8
+ LogFactory = Java::OrgApacheJuliLogging::LogFactory
9
+
10
+ @@configured = nil
11
+
12
+ # Configure the "global" Trinidad logging.
13
+ def self.configure(log_level = nil)
14
+ return false if @@configured
15
+
16
+ root_logger = JUL::Logger.getLogger('')
17
+ level = parse_log_level(log_level, :INFO)
18
+
19
+ out_handler = JUL::ConsoleHandler.new
20
+ out_handler.setOutputStream JRuby.runtime.out
21
+ out_handler.formatter = console_formatter
22
+
23
+ err_handler = JUL::ConsoleHandler.new
24
+ err_handler.setOutputStream JRuby.runtime.err
25
+ err_handler.formatter = console_formatter
26
+ err_handler.level = level.intValue > JUL::Level::WARNING.intValue ?
27
+ level : JUL::Level::WARNING # only >= WARNING on STDERR
28
+
29
+ root_logger.synchronized do
30
+ root_logger.handlers.to_a.each do |handler|
31
+ root_logger.remove_handler(handler) if handler.is_a?(JUL::ConsoleHandler)
32
+ end
33
+
34
+ root_logger.add_handler(out_handler)
35
+ root_logger.add_handler(err_handler)
36
+ root_logger.level = level
37
+ end
38
+ adjust_tomcat_loggers
39
+
40
+ @@configured = true
41
+ root_logger
42
+ end
43
+
44
+ # Force logging (re-)configuration.
45
+ # @see #configure
46
+ def self.configure!(log_level = nil)
47
+ @@configured = false
48
+ configure(log_level)
49
+ end
50
+
51
+ # Configure logging for a web application.
52
+ def self.configure_web_app(web_app, context)
53
+ param_name, param_value = 'jruby.rack.logging', 'JUL'
54
+ # 1. delegate (jruby-rack) servlet log to JUL
55
+ if set_value = context.find_parameter(param_name)
56
+ return nil if set_value.upcase != param_value
57
+ else
58
+ context.add_parameter(param_name, param_value)
59
+ end
60
+ # 2. use Tomcat's JUL logger name (unless set) :
61
+ param_name = 'jruby.rack.logging.name'
62
+ unless logger_name = context.find_parameter(param_name)
63
+ # for a context path e.g. '/foo' most likely smt of the following :
64
+ # org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/foo]
65
+ context.add_parameter(param_name, logger_name = context.send(:logName))
66
+ end
67
+ configure # make sure 'global' logging if configured
68
+
69
+ logger = JUL::Logger.getLogger(logger_name) # exclusive for web app
70
+ # avoid duplicate calls - do not configure our FileHandler twice :
71
+ return false if logger.handlers.find { |h| h.is_a?(FileHandler) }
72
+ level = parse_log_level(web_app.log, nil)
73
+ logger.level = level # inherits level from parent if nil
74
+ # delegate to root (console) output only in development mode :
75
+ logger.use_parent_handlers = ( web_app.environment == 'development' )
76
+
77
+ prefix, suffix = web_app.environment, '.log' # {prefix}{date}{suffix}
78
+ file_handler = FileHandler.new(web_app.log_dir, prefix, suffix)
79
+ file_handler.rotatable = true # {prefix}{date}{suffix}
80
+ file_handler.formatter = web_app_formatter
81
+ logger.add_handler(file_handler)
82
+ logger
83
+ end
84
+
85
+ protected
86
+
87
+ def self.console_formatter
88
+ MessageFormatter.new
89
+ end
90
+
91
+ def self.web_app_formatter
92
+ # format used by Rails "2012-06-13 16:42:21 +0200"
93
+ DefaultFormatter.new("yyyy-MM-dd HH:mm:ss Z")
94
+ end
95
+
96
+ private
97
+
98
+ def self.parse_log_level(log_level, default = nil)
99
+ log_level = log_level && log_level.to_s.upcase
100
+ unless JUL::Level.constants.find { |level| level.to_s == log_level }
101
+ log_level = { # try mapping common level names to JUL names
102
+ 'ERROR' => 'SEVERE', 'WARN' => 'WARNING', 'DEBUG' => 'FINE'
103
+ }[log_level]
104
+ log_level = default ? default.to_s.upcase : nil unless log_level
105
+ end
106
+ JUL::Level.parse(log_level) if log_level
107
+ end
108
+
109
+ def self.adjust_tomcat_loggers
110
+ # org.apache.coyote.http11.Http11Protocol INFO: Initializing ProtocolHandler ["http-bio-3000"]
111
+ # org.apache.catalina.core.StandardService INFO: Starting service Tomcat
112
+ # org.apache.catalina.core.StandardEngine INFO: Starting Servlet Engine: Apache Tomcat/7.0.27
113
+ # org.apache.catalina.startup.ContextConfig INFO: No global web.xml found
114
+ # org.apache.coyote.http11.Http11Protocol INFO: Starting ProtocolHandler ["http-bio-3000"]
115
+ logger = JUL::Logger.get_logger('org.apache.catalina.core.StandardService')
116
+ logger.level = JUL::Level::WARNING if logger
117
+ logger = JUL::Logger.get_logger('org.apache.catalina.startup.ContextConfig')
118
+ logger.level = JUL::Level::WARNING if logger
119
+ end
120
+
121
+ # we'd achieve logging to a production.log file while rotating it (daily)
122
+ class FileHandler < Java::OrgApacheJuli::FileHandler # :nodoc
123
+
124
+ field_reader :directory, :prefix, :suffix
125
+ field_accessor :rotatable, :bufferSize => :buffer_size
126
+
127
+ # JULI::FileHandler internals :
128
+ field_accessor :date => :_date # current date string e.g. 2012-06-26
129
+
130
+ def initialize(directory, prefix, suffix)
131
+ super(directory, prefix, suffix)
132
+ self._date = '' # to openWriter on first #publish(record)
133
+ end
134
+
135
+ def openWriter
136
+ # NOTE: following code is heavily based on super's internals !
137
+ synchronized do
138
+ # we're normally in the lock here (from #publish)
139
+ # thus we do not perform any more synchronization
140
+ prev_rotatable = self.rotatable
141
+ begin
142
+ self.rotatable = false
143
+ # thus current file name will be always {prefix}{suffix} :
144
+ # due super's `prefix + (rotatable ? _date : "") + suffix`
145
+ super
146
+ ensure
147
+ self.rotatable = prev_rotatable
148
+ end
149
+ end
150
+ end
151
+
152
+ def close
153
+ @_close = true
154
+ super
155
+ @_close = nil
156
+ end
157
+
158
+ def closeWriter
159
+ super
160
+ # the additional trick here is to rotate the closed file
161
+ synchronized do
162
+ # we're normally in the lock here (from #publish)
163
+ # thus we do not perform any more synchronization
164
+ dir = java.io.File.new(directory).getAbsoluteFile
165
+ log = java.io.File.new(dir, prefix + "" + suffix)
166
+ if log.exists
167
+ date = _date
168
+ if date.empty?
169
+ date = log.lastModified
170
+ # we're abuse Timestamp to get a date formatted !
171
+ # just like the super does internally (just in case)
172
+ date = java.sql.Timestamp.new(date).toString[0, 10]
173
+ end
174
+ today = java.lang.System.currentTimeMillis
175
+ today = java.sql.Timestamp.new(today).toString[0, 10]
176
+ return if date == today # no need to rotate just yet
177
+ to_file = java.io.File.new(dir, prefix + date + suffix)
178
+ if to_file.exists
179
+ file = java.io.RandomAccessFile.new(to_file, 'rw')
180
+ file.seek(file.length)
181
+ log_channel = java.io.FileInputStream.new(log).getChannel
182
+ log_channel.transferTo(0, log_channel.size, file.getChannel)
183
+ file.close
184
+ log_channel.close
185
+ log.delete
186
+ else
187
+ log.renameTo(to_file)
188
+ end
189
+ end
190
+ end if rotatable && ! @_close
191
+ end
192
+
193
+ end
194
+
195
+ # We're truly missing a #formatThrown exception helper method.
196
+ JUL::Formatter.class_eval do
197
+
198
+ LINE_SEP = java.lang.System.getProperty("line.separator")
199
+
200
+ protected
201
+ def formatThrown(record)
202
+ if record.thrown
203
+ writer = java.io.StringWriter.new(1024)
204
+ print_writer = java.io.PrintWriter.new(writer)
205
+ print_writer.println
206
+ record.thrown.printStackTrace(print_writer)
207
+ print_writer.close
208
+ return writer.toString
209
+ end
210
+ end
211
+
212
+ end
213
+
214
+ # A message formatter only prints the log message (and the thrown value).
215
+ class MessageFormatter < JUL::Formatter # :nodoc
216
+
217
+ def format(record)
218
+ msg = formatMessage(record)
219
+ msg << formatThrown(record).to_s
220
+ # since we're going to print Rails.logger logs and they tend
221
+ # to already have the ending "\n" handle such cases nicely :
222
+ if web_app_path(record.getLoggerName)
223
+ (lns = LINE_SEP) == msg[-1, 1] ? msg : msg << lns
224
+ else
225
+ msg << LINE_SEP
226
+ end
227
+ end
228
+
229
+ # e.g. org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/foo]
230
+ WEB_APP_LOGGER_NAME = /org\.apache\.catalina\.core\.ContainerBase.*?\[(\/.*?)\]$/
231
+
232
+ private
233
+ def web_app_path(name)
234
+ ( match = (name || '').match(WEB_APP_LOGGER_NAME) ) && match[1]
235
+ end
236
+
237
+ end
238
+
239
+ # A formatter that formats application file logs (e.g. production.log).
240
+ class DefaultFormatter < JUL::Formatter # :nodoc
241
+
242
+ # Allows customizing the date format + the time zone to be used.
243
+ def initialize(format = nil, time_zone = nil)
244
+ super()
245
+ @format = format ?
246
+ Java::JavaText::SimpleDateFormat.new(format) :
247
+ Java::JavaText::SimpleDateFormat.new
248
+ case time_zone
249
+ when Java::JavaUtil::Calendar then
250
+ @format.calendar = time_zone
251
+ when Java::JavaUtil::TimeZone then
252
+ @format.time_zone = time_zone
253
+ when String then
254
+ time_zone = Java::JavaUtil::TimeZone.getTimeZone(time_zone)
255
+ @format.time_zone = time_zone
256
+ when Numeric then
257
+ time_zones = Java::JavaUtil::TimeZone.getAvailableIDs(time_zone)
258
+ if time_zones.length > 0
259
+ time_zone = Java::JavaUtil::TimeZone.getTimeZone(time_zones[0])
260
+ @format.time_zone = time_zone
261
+ end
262
+ end if time_zone
263
+ end
264
+
265
+ JDate = Java::JavaUtil::Date
266
+
267
+ def format(record)
268
+ timestamp = @format.synchronized do
269
+ @format.format JDate.new(record.millis)
270
+ end
271
+ level = record.level.name
272
+ message = formatMessage(record)
273
+
274
+ out = "#{timestamp} #{level}: #{message}"
275
+ out << formatThrown(record).to_s
276
+ (lns = "\n") == out[-1, 1] ? out : out << lns
277
+ end
278
+
279
+ end
280
+ end
281
+ LogFormatter = Logging::DefaultFormatter # backwards compatibility
282
+ end
@@ -1,10 +1,10 @@
1
1
  module Trinidad
2
-
3
2
  class Server
4
3
  attr_reader :tomcat, :config
5
4
 
6
5
  def initialize(config = Trinidad.configuration)
7
6
  load_config(config)
7
+ configure_logging(@config[:log])
8
8
  load_tomcat_server
9
9
  apps = create_web_apps
10
10
  load_host_monitor(apps)
@@ -33,133 +33,28 @@ module Trinidad
33
33
  @tomcat = Trinidad::Extensions.configure_server_extensions(@config[:extensions], @tomcat)
34
34
  end
35
35
 
36
- def create_hosts
37
- if @config[:hosts]
38
- @config[:hosts].each do |apps_base, names|
39
- create_host(apps_base, names)
40
- end
41
-
42
- set_default_host
43
- elsif @config[:web_apps]
44
- # create the hosts when they are specified for each app into web_apps.
45
- # We must create them before creating the applications.
46
- @config[:web_apps].each do |name, app_config|
47
- if host_names = app_config.delete(:hosts)
48
- dir = app_config[:web_app_dir] || Dir.pwd
49
- apps_base = File.dirname(dir) == '.' ? dir : File.dirname(dir)
50
- app_config[:host] = create_host(apps_base, host_names)
51
- end
52
-
53
- set_default_host
54
- end
55
- else
56
- @tomcat.host.app_base = @config[:apps_base] || Dir.pwd
57
- end
58
- end
59
-
60
- def create_web_apps
61
- apps = []
62
- apps << create_from_web_apps
63
- apps << create_from_apps_base
64
-
65
- apps.flatten.compact
66
- end
67
-
68
36
  def load_host_monitor(apps)
69
37
  @tomcat.engine.find_children.each do |host|
70
- host.add_lifecycle_listener(Trinidad::Lifecycle::Host.new(@tomcat, *apps))
71
- end
72
- end
73
-
74
- def create_from_web_apps
75
- if @config[:web_apps]
76
- @config[:web_apps].map do |name, app_config|
77
- app_config[:context_path] ||= (name.to_s == 'default' ? '' : "/#{name.to_s}")
78
- app_config[:web_app_dir] ||= Dir.pwd
79
-
80
- create_web_app(app_config)
81
- end
38
+ host.add_lifecycle_listener(Trinidad::Lifecycle::Host.new(self, *apps))
82
39
  end
83
40
  end
84
41
 
85
- def create_from_apps_base
86
- if @config[:apps_base] || @config[:hosts]
87
- @tomcat.engine.find_children.map do |host|
88
- apps_base = host.app_base
89
-
90
- apps_path = Dir.glob(File.join(apps_base, '*')).
91
- select {|path| !(path =~ /tomcat\.\d+$/) }
92
-
93
- apps_path.reject! {|path| apps_path.include?(path + '.war') }
94
-
95
- apps_path.map do |path|
96
- if (File.directory?(path) || path =~ /\.war$/)
97
- name = File.basename(path)
98
- app_config = {
99
- :context_path => (name == 'default' ? '' : "/#{name.to_s}"),
100
- :web_app_dir => File.expand_path(path),
101
- :host => host
102
- }
103
-
104
- create_web_app(app_config)
105
- end
106
- end
107
- end.flatten
108
- end
42
+ def ssl_enabled?
43
+ @config[:ssl] && !@config[:ssl].empty?
109
44
  end
110
45
 
111
- def create_web_app(app_config)
112
- web_app = WebApp.create(@config, app_config)
113
-
114
- app_context = @tomcat.addWebapp(app_config[:host] || @tomcat.host, web_app.context_path, web_app.web_app_dir)
115
-
116
- Trinidad::Extensions.configure_webapp_extensions(web_app.extensions, @tomcat, app_context)
117
-
118
- app_context.add_lifecycle_listener(web_app.define_lifecycle)
119
-
120
- {:context => app_context, :app => web_app, :monitor => web_app.monitor}
46
+ def ajp_enabled?
47
+ @config[:ajp] && !@config[:ajp].empty?
121
48
  end
122
49
 
123
- def add_service_connector(options, protocol = nil)
124
- connector = Trinidad::Tomcat::Connector.new(protocol)
125
- opts = options.dup
126
-
127
- connector.scheme = opts.delete(:scheme) if opts[:scheme]
128
- connector.secure = opts.delete(:secure) || false
129
- connector.port = opts.delete(:port).to_i
130
-
131
- connector.protocol_handler_class_name = opts.delete(:protocol_handler) if opts[:protocol_handler]
132
-
133
- opts.each do |key, value|
134
- connector.setProperty(key.to_s, value.to_s)
135
- end
136
-
137
- @tomcat.service.add_connector(connector)
138
- connector
50
+ def http_configured?
51
+ (@config[:http] && !@config[:http].empty?) || @config[:address] != 'localhost'
139
52
  end
140
-
53
+
141
54
  def add_ajp_connector
142
55
  add_service_connector(@config[:ajp], 'AJP/1.3')
143
56
  end
144
57
 
145
- def add_ssl_connector
146
- options = @config[:ssl].merge({
147
- :scheme => 'https',
148
- :secure => true,
149
- :SSLEnabled => 'true'
150
- })
151
-
152
- options[:keystoreFile] ||= options.delete(:keystore)
153
-
154
- if !options[:keystoreFile] && !options[:SSLCertificateFile]
155
- options[:keystoreFile] = 'ssl/keystore'
156
- options[:keystorePass] = 'waduswadus'
157
- create_default_keystore(options)
158
- end
159
-
160
- add_service_connector(options)
161
- end
162
-
163
58
  def add_http_connector
164
59
  options = @config[:http] || {}
165
60
  options[:address] ||= @config[:address] if @config[:address] != 'localhost'
@@ -173,40 +68,51 @@ module Trinidad
173
68
  connector = add_service_connector(options, options[:protocol_handler] || 'HTTP/1.1')
174
69
  @tomcat.connector = connector
175
70
  end
71
+
72
+ def add_ssl_connector
73
+ options = @config[:ssl].merge({
74
+ :scheme => 'https',
75
+ :secure => true,
76
+ :SSLEnabled => 'true'
77
+ })
176
78
 
177
- def ssl_enabled?
178
- @config[:ssl] && !@config[:ssl].empty?
179
- end
79
+ options[:keystoreFile] ||= options.delete(:keystore)
180
80
 
181
- def ajp_enabled?
182
- @config[:ajp] && !@config[:ajp].empty?
183
- end
81
+ if !options[:keystoreFile] && !options[:SSLCertificateFile]
82
+ options[:keystoreFile] = 'ssl/keystore'
83
+ options[:keystorePass] = 'waduswadus42'
84
+ generate_default_keystore(options)
85
+ end
184
86
 
185
- def http_configured?
186
- (@config[:http] && !@config[:http].empty?) || @config[:address] != 'localhost'
87
+ add_service_connector(options)
187
88
  end
89
+
90
+ def add_service_connector(options, protocol = nil)
91
+ connector = Trinidad::Tomcat::Connector.new(protocol)
92
+ opts = options.dup
188
93
 
189
- def create_default_keystore(config)
190
- keystore_file = java.io.File.new(config[:keystoreFile])
94
+ connector.scheme = opts.delete(:scheme) if opts[:scheme]
95
+ connector.secure = opts.delete(:secure) || false
96
+ connector.port = opts.delete(:port).to_i
191
97
 
192
- if (!keystore_file.parent_file.exists &&
193
- !keystore_file.parent_file.mkdir)
194
- raise "Unable to create keystore folder: " + keystore_file.parent_file.canonical_path
195
- end
98
+ connector.protocol_handler_class_name = opts.delete(:protocol_handler) if opts[:protocol_handler]
196
99
 
197
- keytool_args = ["-genkey",
198
- "-alias", "localhost",
199
- "-dname", "CN=localhost, OU=Trinidad, O=Trinidad, C=ES",
200
- "-keyalg", "RSA",
201
- "-validity", "365",
202
- "-storepass", "key",
203
- "-keystore", config[:keystoreFile],
204
- "-storepass", config[:keystorePass],
205
- "-keypass", config[:keystorePass]]
100
+ opts.each do |key, value|
101
+ connector.setProperty(key.to_s, value.to_s)
102
+ end
206
103
 
207
- Trinidad::Tomcat::KeyTool.main(keytool_args.to_java(:string))
104
+ @tomcat.service.add_connector(connector)
105
+ connector
208
106
  end
209
107
 
108
+ def add_web_app(web_app, host = nil)
109
+ 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
114
+ end
115
+
210
116
  def start
211
117
  trap_signals if @config[:trap]
212
118
 
@@ -219,12 +125,73 @@ module Trinidad
219
125
  @tomcat.destroy
220
126
  end
221
127
 
222
- def load_default_system_properties
223
- java.lang.System.set_property("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE", 'true')
128
+ protected
129
+
130
+ def create_web_apps
131
+ apps = []
132
+ apps << create_from_web_apps
133
+ apps << create_from_apps_base
134
+ apps.flatten.compact
135
+ end
136
+
137
+ def create_from_web_apps
138
+ @config[:web_apps].map do |name, app_config|
139
+ app_config[:context_path] ||= (name.to_s == 'default' ? '' : "/#{name}")
140
+ app_config[:web_app_dir] ||= Dir.pwd
141
+
142
+ create_web_app(app_config)
143
+ end if @config[:web_apps]
224
144
  end
225
145
 
226
- private
146
+ def create_from_apps_base
147
+ if @config[:apps_base] || @config[:hosts]
148
+ @tomcat.engine.find_children.map do |host|
149
+ apps_base = host.app_base
150
+
151
+ apps_path = Dir.glob(File.join(apps_base, '*')).
152
+ select { |path| !(path =~ /tomcat\.\d+$/) }
227
153
 
154
+ apps_path.reject! { |path| apps_path.include?(path + '.war') }
155
+
156
+ apps_path.map do |path|
157
+ if File.directory?(path) || path =~ /\.war$/
158
+ name = File.basename(path)
159
+ create_web_app({
160
+ :context_path => (name.to_s == 'default' ? '' : "/#{name}"),
161
+ :web_app_dir => File.expand_path(path),
162
+ :host => host
163
+ })
164
+ end
165
+ end
166
+ end.flatten
167
+ end
168
+ end
169
+
170
+ def create_web_app(app_config)
171
+ web_app = WebApp.create(app_config, config)
172
+ WebApp::Holder.new(web_app, add_web_app(web_app))
173
+ end
174
+
175
+ def create_hosts
176
+ if @config[:hosts]
177
+ @config[:hosts].each do |apps_base, names|
178
+ create_host(apps_base, names)
179
+ end
180
+ elsif @config[:web_apps]
181
+ # create the hosts when they are specified for each app into web_apps.
182
+ # We must create them before creating the applications.
183
+ @config[:web_apps].each do |_, app_config|
184
+ if host_names = app_config.delete(:hosts)
185
+ dir = app_config[:web_app_dir] || Dir.pwd
186
+ apps_base = File.dirname(dir) == '.' ? dir : File.dirname(dir)
187
+ app_config[:host] = create_host(apps_base, host_names)
188
+ end
189
+ end
190
+ else
191
+ @tomcat.host.app_base = @config[:apps_base] || Dir.pwd
192
+ end
193
+ end
194
+
228
195
  def create_host(apps_base, names)
229
196
  host_names = Array(names)
230
197
  host_name = host_names.shift
@@ -232,21 +199,25 @@ module Trinidad
232
199
  host = Trinidad::Tomcat::StandardHost.new
233
200
  host.name = host_name
234
201
  host.app_base = apps_base || Dir.pwd
235
- host_names.each {|h| host.add_alias(h) } unless host_names.empty?
202
+ host_names.each { |name| host.add_alias(name) }
236
203
 
237
204
  @tomcat.engine.add_child host
238
205
  end
239
206
  host
240
207
  end
241
-
242
- def set_default_host
243
- # FIXME: Remove when the issue below is solved.
244
- # workaround to solve this Tomcat issue: https://issues.apache.org/bugzilla/show_bug.cgi?id=52387
245
- @tomcat.host = @tomcat.engine.find_children.first
208
+
209
+ def load_default_system_properties
210
+ java.lang.System.set_property("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE", 'true')
246
211
  end
247
-
212
+
213
+ def configure_logging(log_level)
214
+ Trinidad::Logging.configure(log_level)
215
+ end
216
+
217
+ private
218
+
248
219
  def add_default_web_app!(config)
249
- if (!config[:web_apps] && !config[:apps_base] && !config[:hosts])
220
+ if !config[:web_apps] && !config[:apps_base] && !config[:hosts]
250
221
  default_app = {
251
222
  :context_path => config[:context_path],
252
223
  :web_app_dir => config[:web_app_dir] || Dir.pwd,
@@ -257,7 +228,29 @@ module Trinidad
257
228
  config[:web_apps] = { :default => default_app }
258
229
  end
259
230
  end
231
+
232
+ def generate_default_keystore(config)
233
+ keystore_file = java.io.File.new(config[:keystoreFile])
234
+
235
+ if (!keystore_file.parent_file.exists &&
236
+ !keystore_file.parent_file.mkdir)
237
+ raise "Unable to create keystore folder: " + keystore_file.parent_file.canonical_path
238
+ end
260
239
 
240
+ key_tool_args = ["-genkey",
241
+ "-alias", "localhost",
242
+ "-dname", "CN=localhost, OU=Trinidad, O=Trinidad, C=ES",
243
+ "-keyalg", "RSA",
244
+ "-validity", "365",
245
+ "-storepass", "key",
246
+ "-keystore", config[:keystoreFile],
247
+ "-storepass", config[:keystorePass],
248
+ "-keypass", config[:keystorePass]]
249
+
250
+ key_tool = Java::SunSecurityTools::KeyTool
251
+ key_tool.main key_tool_args.to_java(:string)
252
+ end
253
+
261
254
  def trap_signals
262
255
  trap('INT') { stop }
263
256
  trap('TERM') { stop }