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.
- data/Gemfile +8 -2
- data/History.txt +43 -0
- data/LICENSE +3 -2
- data/README.md +121 -51
- data/Rakefile +2 -3
- data/lib/trinidad.rb +6 -10
- data/lib/trinidad/command_line_parser.rb +65 -65
- data/lib/trinidad/configuration.rb +103 -26
- data/lib/trinidad/lifecycle/base.rb +70 -0
- data/lib/trinidad/lifecycle/host.rb +87 -0
- data/lib/trinidad/lifecycle/host/restart_reload.rb +13 -0
- data/lib/trinidad/lifecycle/host/rolling_reload.rb +72 -0
- data/lib/trinidad/lifecycle/web_app/default.rb +94 -0
- data/lib/trinidad/lifecycle/web_app/shared.rb +53 -0
- data/lib/trinidad/lifecycle/web_app/war.rb +52 -0
- data/lib/trinidad/logging.rb +282 -0
- data/lib/trinidad/server.rb +142 -149
- data/lib/trinidad/version.rb +1 -1
- data/lib/trinidad/web_app.rb +278 -106
- data/rakelib/tomcat.rake +41 -10
- data/src/java/org/apache/juli/FileHandler.java +401 -0
- data/trinidad.gemspec +5 -9
- metadata +29 -19
- data/lib/trinidad/core_ext.rb +0 -42
- data/lib/trinidad/lifecycle/lifecycle_listener_base.rb +0 -88
- data/lib/trinidad/lifecycle/lifecycle_listener_default.rb +0 -84
- data/lib/trinidad/lifecycle/lifecycle_listener_host.rb +0 -81
- data/lib/trinidad/lifecycle/lifecycle_listener_war.rb +0 -43
- data/lib/trinidad/lifecycle/takeover.rb +0 -25
- data/lib/trinidad/log_formatter.rb +0 -18
- data/lib/trinidad/rackup_web_app.rb +0 -16
- data/lib/trinidad/rails_web_app.rb +0 -13
- data/lib/trinidad/war_web_app.rb +0 -19
@@ -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
|
data/lib/trinidad/server.rb
CHANGED
@@ -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(
|
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
|
86
|
-
|
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
|
112
|
-
|
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
|
124
|
-
|
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
|
-
|
178
|
-
@config[:ssl] && !@config[:ssl].empty?
|
179
|
-
end
|
79
|
+
options[:keystoreFile] ||= options.delete(:keystore)
|
180
80
|
|
181
|
-
|
182
|
-
|
183
|
-
|
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
|
-
|
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
|
-
|
190
|
-
|
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
|
-
|
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
|
-
|
198
|
-
|
199
|
-
|
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
|
-
|
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
|
-
|
223
|
-
|
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
|
-
|
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 {|
|
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
|
243
|
-
|
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
|
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 }
|