lib/trinidad/server.rb in trinidad-1.4.4 vs lib/trinidad/server.rb in trinidad-1.4.5.B1
- old
+ new
@@ -1,245 +1,485 @@
require 'trinidad/configuration'
require 'trinidad/web_app'
module Trinidad
class Server
- attr_reader :config, :tomcat, :web_apps
+ attr_reader :config
def initialize(config = Trinidad.configuration)
- load_config(config)
- configure_logging(@config[:log])
- load_tomcat_server
- @web_apps = create_web_apps
- load_host_monitor(@web_apps)
+ configure(config)
end
- def load_config(config)
- add_default_web_app! config
+ def configure(config = Trinidad.configuration)
+ configure_logging config[:log]
@config = config.freeze
end
+ # @deprecated replaced with {#configure}
+ def load_config(config); configure(config); end
- def load_tomcat_server
- load_default_system_properties
-
- @tomcat = Trinidad::Tomcat::Tomcat.new
- @tomcat.base_dir = Dir.pwd
- @tomcat.hostname = @config[:address] || 'localhost'
- @tomcat.server.address = @config[:address]
- @tomcat.port = @config[:port].to_i
- create_hosts
- @tomcat.enable_naming
-
- add_http_connector if http_configured?
- add_ssl_connector if ssl_enabled?
- add_ajp_connector if ajp_enabled?
-
- @tomcat = Trinidad::Extensions.configure_server_extensions(@config[:extensions], @tomcat)
+ def hosts
+ @hosts ||= @config[:hosts]
end
+ attr_writer :hosts
+
+ def app_base
+ @app_base ||= @config[:app_base] || @config[:apps_base]
+ end
+ attr_writer :app_base
- def load_host_monitor(apps)
- @tomcat.engine.find_children.each do |host|
- host.add_lifecycle_listener(Trinidad::Lifecycle::Host.new(self, *apps))
- end
+ def web_apps
+ @web_apps ||= @config[:web_apps] || @config[:webapps]
end
+ attr_writer :web_apps
+
+ def trap?
+ @trap ||= @config[:trap] if ! defined?(@trap) || @trap.nil?
+ @trap
+ end
+ attr_writer :trap
def ssl_enabled?
- !! @config[:ssl] && ! @config[:ssl].empty?
+ if ! defined?(@ssl_enabled) || @ssl_enabled.nil?
+ @ssl_enabled ||= ( !! @config[:ssl] && ! @config[:ssl].empty? )
+ end
+ @ssl_enabled
end
+ attr_writer :ssl_enabled
def ajp_enabled?
- !! @config[:ajp] && ! @config[:ajp].empty?
+ if ! defined?(@ajp_enabled) || @ajp_enabled.nil?
+ @ajp_enabled ||= ( !! @config[:ajp] && ! @config[:ajp].empty? )
+ end
+ @ajp_enabled
end
+ attr_writer :ajp_enabled
def http_configured?
- (!! @config[:http] && ! @config[:http].empty?) || @config[:address] != 'localhost'
+ if ! defined?(@http_configured) || @http_configured.nil?
+ @http_configured ||=
+ ( ( !! @config[:http] && ! @config[:http].empty? ) || @config[:address] != 'localhost' )
+ end
+ @http_configured
end
+ attr_writer :http_configured
- def add_ajp_connector
- add_service_connector(@config[:ajp], 'AJP/1.3')
+ def tomcat; @tomcat ||= initialize_tomcat; end
+
+ def initialize_tomcat
+ set_system_properties
+
+ tomcat = Trinidad::Tomcat::Tomcat.new
+ tomcat.base_dir = config[:base_dir] || Dir.pwd
+ tomcat.hostname = config[:address] || 'localhost'
+ tomcat.server.address = config[:address]
+ tomcat.port = config[:port].to_i
+ default_host(tomcat)
+ create_hosts(tomcat)
+ tomcat.enable_naming
+
+ add_http_connector(tomcat) if http_configured?
+ add_ssl_connector(tomcat) if ssl_enabled?
+ add_ajp_connector(tomcat) if ajp_enabled?
+
+ Trinidad::Extensions.configure_server_extensions(config[:extensions], tomcat)
end
+ protected :initialize_tomcat
+ # #deprecated renamed to {#initialize_tomcat}
+ def load_tomcat_server; initialize_tomcat; end
- def add_http_connector
- options = @config[:http] || {}
+ def add_host_monitor(app_holders)
+ for host in tomcat.engine.find_children
+ host_apps = select_host_apps(app_holders, host)
+ host.add_lifecycle_listener(Trinidad::Lifecycle::Host.new(self, *host_apps))
+ end
+ end
+ protected :add_host_monitor
+ # @deprecated replaced with {#setup_host_monitor}
+ def load_host_monitor(web_apps); add_host_monitor(web_apps); end
+
+ def add_ajp_connector(tomcat = @tomcat)
+ add_service_connector(@config[:ajp], 'AJP/1.3', tomcat)
+ end
+
+ def add_http_connector(tomcat = @tomcat)
+ options = config[:http] || {}
options[:address] ||= @config[:address] if @config[:address] != 'localhost'
options[:port] = @config[:port]
options[:protocol_handler] = 'org.apache.coyote.http11.Http11NioProtocol' if options[:nio]
if options[:apr]
- @tomcat.server.add_lifecycle_listener(Trinidad::Tomcat::AprLifecycleListener.new)
+ tomcat.server.add_lifecycle_listener(Trinidad::Tomcat::AprLifecycleListener.new)
end
- connector = add_service_connector(options, options[:protocol_handler] || 'HTTP/1.1')
- @tomcat.connector = connector
+ connector = add_service_connector(options, options[:protocol_handler] || 'HTTP/1.1', tomcat)
+ tomcat.connector = connector
end
- def add_ssl_connector
- options = @config[:ssl].merge({
+ def add_ssl_connector(tomcat = @tomcat)
+ options = config[:ssl].merge({
:scheme => 'https',
:secure => true,
:SSLEnabled => 'true'
})
options[:keystoreFile] ||= options.delete(:keystore)
- if !options[:keystoreFile] && !options[:SSLCertificateFile]
+ if ! options[:keystoreFile] && ! options[:SSLCertificateFile]
options[:keystoreFile] = 'ssl/keystore'
options[:keystorePass] = 'waduswadus42'
generate_default_keystore(options)
end
- add_service_connector(options)
+ add_service_connector(options, nil, tomcat)
end
- def add_service_connector(options, protocol = nil)
- connector = Trinidad::Tomcat::Connector.new(protocol)
+ def add_service_connector(options, protocol = nil, tomcat = @tomcat)
opts = options.dup
+ connector = Trinidad::Tomcat::Connector.new(protocol)
connector.scheme = opts.delete(:scheme) if opts[:scheme]
connector.secure = opts.delete(:secure) || false
connector.port = opts.delete(:port).to_i
connector.protocol_handler_class_name = opts.delete(:protocol_handler) if opts[:protocol_handler]
- opts.each do |key, value|
- connector.setProperty(key.to_s, value.to_s)
- end
+ opts.each { |key, value| connector.setProperty(key.to_s, value.to_s) }
- @tomcat.service.add_connector(connector)
+ tomcat.service.add_connector(connector)
connector
end
+ private :add_service_connector
- def add_web_app(web_app, host = nil)
- host ||= web_app.config[:host] || @tomcat.host
- context = @tomcat.addWebapp(host, web_app.context_path, web_app.root_dir)
- Trinidad::Extensions.configure_webapp_extensions(web_app.extensions, @tomcat, context)
- context.add_lifecycle_listener(web_app.define_lifecycle)
+ def add_web_app(web_app, host = nil, start = nil)
+ host ||= begin
+ name = web_app.host_name
+ name ? find_host(name, tomcat) : tomcat.host
+ end
+ prev_start = host.start_children
+ context = begin
+ host.start_children = start unless start.nil?
+ # public Context addWebapp(Host host, String url, String name, String docBase)
+ tomcat.addWebapp(host, web_app.context_path, web_app.context_name, web_app.root_dir)
+ rescue java.lang.IllegalArgumentException => e
+ if e.message =~ /addChild\:/
+ context_name = web_app.context_name
+ logger.error "could not add application #{context_name.inspect} from #{web_app.root_dir}\n" <<
+ " (same context name is used for #{host.find_child(context_name).doc_base})"
+ raise "there's already an application named #{context_name.inspect} for host #{host.name.inspect}"
+ end
+ raise e
+ ensure
+ host.start_children = prev_start unless start.nil?
+ end
+ Trinidad::Extensions.configure_webapp_extensions(web_app.extensions, tomcat, context)
+ if lifecycle = web_app.define_lifecycle
+ context.add_lifecycle_listener(lifecycle)
+ end
context
end
+ def deploy_web_apps(tomcat = self.tomcat)
+ add_host_monitor web_apps = create_web_apps
+ web_apps
+ end
+
def start
+ deploy_web_apps(tomcat)
+
trap_signals if trap?
- @tomcat.start
- @tomcat.server.await
+ tomcat.start
+ tomcat.server.await
end
+ def start!
+ if defined?(@tomcat) && @tomcat
+ @tomcat.destroy; @tomcat = nil
+ end
+ start
+ end
+
def stop
- @tomcat.stop
+ if defined?(@tomcat) && @tomcat
+ @tomcat.stop; true
+ end
end
def stop!
- stop
- @tomcat.destroy
+ (@tomcat.destroy; true) if stop
end
protected
-
- def trap?
- !!@config[:trap]
- end
-
+
def create_web_apps
- apps = [ create_from_web_apps ]
- apps << create_from_apps_base
- apps.flatten!; apps.compact!
- apps
- end
-
- def create_from_web_apps
- @config[:web_apps].map do |name, app_config|
- app_config[:context_name] ||= name
- create_web_app(app_config)
- end if @config[:web_apps]
- end
+ # add default web app if needed :
+ if ! web_apps && ! app_base && ! hosts
+ default_app = { :context_path => config[:context_path] }
+ root_dir = web_app_root_dir(config) || Dir.pwd
+ default_app[:root_dir] = root_dir if root_dir != false
+ default_app[:rackup] = config[:rackup] if config[:rackup]
- def create_from_apps_base
- if @config[:apps_base] || @config[:hosts]
- @tomcat.engine.find_children.map do |host|
- apps_base = host.app_base
+ self.web_apps = { :default => default_app }
+ end
- apps_path = Dir.glob(File.join(apps_base, '*')).
- select { |path| !(path =~ /tomcat\.\d+$/) }
+ apps = []
- apps_path.reject! { |path| apps_path.include?(path + '.war') }
+ # configured :web_apps
+ web_apps.each do |name, app_config|
+ app_config[:context_name] ||= name
+ apps << ( app_holder = create_web_app(app_config) ); app = app_holder.web_app
+ logger.info "Deploying from #{app.root_dir} as #{app.context_path}"
+ end if web_apps
- apps_path.map do |path|
- if File.directory?(path) || path =~ /\.war$/
- create_web_app({
- :context_name => File.basename(path),
- :root_dir => File.expand_path(path),
- :host => host
- })
+ # configured :app_base or :hosts - scan for applications in host's app_base directory :
+ tomcat.engine.find_children.each do |host|
+ apps_path = java.io.File.new(host.app_base).list.to_a
+ if host.deploy_ignore # respect deploy ignore pattern (even if not deploying on startup)
+ deploy_ignore_pattern = Regexp.new(host.deploy_ignore)
+ apps_path.reject! { |path| path =~ deploy_ignore_pattern }
+ end
+ # we do a bit of "default" filtering for hosts of our own :
+ work_dir = host.work_dir
+ apps_path.reject! do |path|
+ if path[0, 1] == '.' then true # ignore "hidden" files
+ elsif work_dir && work_dir == path then true
+ elsif ! work_dir && path =~ /tomcat\.\d+$/ then true # [host_base]/tomcat.8080
+ elsif path[-4..-1] == '.war' && apps_path.include?(path[0...-4]) # only keep expanded .war
+ logger.info "Expanded .war at #{path} - only deploying directory (.war ignored)"
+ true
+ end
+ end
+
+ apps_path.each do |path| # host web apps (from dir or .war files)
+ app_root = File.expand_path(path, host.app_base)
+ if File.directory?(app_root) || ( app_root[-4..-1] == '.war' )
+ app_base_name = File.basename(app_root)
+ deployed = apps.find do |app_holder|; web_app = app_holder.web_app
+ web_app.root_dir == app_root ||
+ web_app.context_path == Trinidad::Tomcat::ContextName.new(app_base_name).path
end
+ if deployed
+ logger.debug "Skipping auto-deploy from #{app_root} (already deployed)"
+ else
+ apps << ( app_holder = create_web_app({
+ :context_name => path, :root_dir => app_root, :host_name => host.name
+ }) ); app = app_holder.web_app
+ logger.info "Auto-Deploying from #{app.root_dir} as #{app.context_path}"
+ end
end
- end.flatten
- end
+ end
+ end if app_base || hosts
+
+ apps
end
def create_web_app(app_config)
+ host_name = app_config[:host_name] || 'localhost'
+ host = tomcat.engine.find_child(host_name)
+ app_config[:root_dir] = web_app_root_dir(app_config, host)
+
web_app = WebApp.create(app_config, config)
WebApp::Holder.new(web_app, add_web_app(web_app))
end
-
- def create_hosts
- if @config[:hosts]
- @config[:hosts].each do |apps_base, names|
- create_host(apps_base, names)
+
+ def create_hosts(tomcat = @tomcat)
+ hosts.each do |app_base, host_config|
+ next if app_base == :default # @see #default_host
+ if host = find_host(app_base, host_config, tomcat)
+ setup_host(app_base, host_config, host)
+ else
+ create_host(app_base, host_config, tomcat)
end
- elsif @config[:web_apps]
- # create the hosts when they are specified for each app into web_apps.
- # We must create them before creating the applications.
- @config[:web_apps].each do |_, app_config|
- if host_names = app_config.delete(:hosts)
- dir = web_app_root_dir(app_config)
- apps_base = File.dirname(dir) == '.' ? dir : File.dirname(dir)
- app_config[:host] = create_host(apps_base, host_names)
+ end if hosts
+
+ default_host = tomcat.host
+ default_app_base = ( default_host.app_base == DEFAULT_HOST_APP_BASE )
+ if self.app_base ||
+ ( default_app_base && ! File.exists?(DEFAULT_HOST_APP_BASE) )
+ tomcat.host.app_base = self.app_base || Dir.pwd
+ end
+
+ web_app_hosts = []
+ # create hosts as they are specified for each app in :web_apps :
+ # e.g. :app1 => { :root_dir => 'app1', :host => 'virtual.host' }
+ web_apps.each do |_, app_config|
+ if host_names = app_config[:hosts] || app_config[:host]
+ if host = find_host(host_names, tomcat)
+ app_root = web_app_root_dir(app_config, host)
+ set_host_app_base(app_root, host, default_host, web_app_hosts)
+ else
+ app_root = web_app_root_dir(app_config)
+ raise "no root for app #{app_config.inspect}" unless app_root
+ app_root = File.expand_path(app_root)
+ # for created hosts -> web-app per host by default
+ # thus new host's app_base will point to root_dir :
+ host = create_host(app_root, host_names, tomcat)
+ web_app_hosts << host
end
+ app_config[:host_name] = host.name
end
- else
- @tomcat.host.app_base = @config[:apps_base] || Dir.pwd
- end
+ end if web_apps
end
-
- def create_host(apps_base, names)
- host_names = Array(names)
- host_name = host_names.shift
- unless host = @tomcat.engine.find_child(host_name)
- host = Trinidad::Tomcat::StandardHost.new
- host.name = host_name
- host.app_base = apps_base || Dir.pwd
- host_names.each { |name| host.add_alias(name) }
- @tomcat.engine.add_child host
- end
+ def create_host(app_base, host_config, tomcat = @tomcat)
+ host = Trinidad::Tomcat::StandardHost.new
+ host.app_base = nil # reset default app_base
+ host.deployXML = false # disabled by default
+ setup_host(app_base, host_config, host)
+ tomcat.engine.add_child host if tomcat
host
end
- def load_default_system_properties
- java.lang.System.set_property("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE", 'true')
+ def setup_host(app_base, host_config, host)
+ if host_config.is_a?(Array)
+ name = host_config.shift
+ host_config = { :name => name, :aliases => host_config }
+ elsif host_config.is_a?(String) || host_config.is_a?(Symbol)
+ host_config = { :name => host_config }
+ else
+ host_config[:name] ||= app_base
+ end
+ host_config[:app_base] ||= app_base if app_base.is_a?(String)
+
+ host_config.each do |name, value|
+ case (name = name.to_sym)
+ when :app_base
+ host.app_base = value if default_host_base?(host)
+ when :aliases
+ aliases = host.find_aliases || []
+ value.each do |name|
+ next if (name = name.to_s) == host.name
+ host.add_alias(name) unless aliases.include?(name)
+ end if host_config[:aliases]
+ else
+ value = value.to_s if value.is_a?(Symbol)
+ host.send("#{name}=", value) # e.g. host.name = value
+ end
+ end
end
+
+ def set_system_properties(system = Java::JavaLang::System)
+ system.set_property("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE", 'true')
+ end
+ # @deprecated renamed to {#set_system_properties}
+ def load_default_system_properties; set_system_properties; end
def configure_logging(log_level)
Trinidad::Logging.configure(log_level)
end
-
+
+ def logger; @logger ||= self.class.logger; end
+
+ def self.logger
+ Logging::LogFactory.getLog('org.apache.catalina.startup.Tomcat')
+ end
+
private
-
- def add_default_web_app!(config)
- if ! config[:web_apps] && ! config[:apps_base] && ! config[:hosts]
- default_app = {
- :context_path => config[:context_path],
- :root_dir => web_app_root_dir(config),
- :log => config[:log]
- }
- default_app[:rackup] = config[:rackup] if config[:rackup]
- config[:web_apps] = { :default => default_app }
+ def default_host(tomcat = @tomcat)
+ host = tomcat.host # make sure we initialize default host
+ host.deployXML = false
+ host_config = @config[:host] || ( @config[:hosts] && @config[:hosts][:default] )
+ host_config.each { |name, value| host.send("#{name}=", value) } if host_config
+ host
+ end
+
+ DEFAULT_HOST_APP_BASE = 'webapps' # :nodoc:
+
+ def default_host_base?(host)
+ host.app_base.nil? || ( host.app_base == DEFAULT_HOST_APP_BASE && host.name == 'localhost' )
+ end
+
+ def set_host_app_base(app_root, host, default_host, web_app_hosts)
+ if host.app_base # we'll try setting a common parent :
+ require 'pathname'; app_path = Pathname.new(app_root)
+ base_path = Pathname.new(host.app_base)
+ unless app_path.exist?
+ app_path = app_path.relative_path_from(base_path) rescue app_path
+ end
+ app_real_path = begin; app_path.realpath.to_s; rescue
+ logger.warn "Application root #{app_root} does not exist !"
+ return
+ end
+ base_parent = false
+ 2.times do
+ begin
+ break if base_parent = ( app_real_path.index(base_path.realpath.to_s) == 0 )
+ rescue => e
+ logger.warn "Host #{host.name.inspect} app_base does not exist," <<
+ " try configuring an absolute path or create it\n (#{e.message})"
+ return
+ end
+ base_path = base_path.parent
+ end
+ if base_parent
+ return if base_path.to_s == host.app_base
+ host.app_base = base_path.realpath.to_s
+ unless web_app_hosts.include?(host)
+ logger.info "Changing (configured) app_base for host #{host.name.inspect}" <<
+ " (#{host.app_base}) to include application root: #{app_path}"
+ end
+ else
+ logger.warn "Host #{host.name.inspect} app_base #{host.app_base.inspect}" <<
+ " is not a parent directory for application root: #{app_path}"
+ end
+ else
+ host.app_base = app_path.parent.realpath.to_s
end
end
-
- def web_app_root_dir(config, default = Dir.pwd)
- config[:root_dir] || config[:web_app_dir] || default
+
+ def select_host_apps(app_holders, host)
+ app_holders.select do |app_holder|
+ host_name = app_holder.web_app.host_name
+ ( host_name || 'localhost' ) == host.name
+ end
+ end
+
+ def find_host(name, host_config, tomcat = nil)
+ if tomcat.nil? # assume 2 args (host_config, tomcat)
+ tomcat = host_config; host_config = name
+ end
+
+ if host_config.is_a?(Array)
+ names = host_config
+ elsif host_config.is_a?(String) || host_config.is_a?(Symbol)
+ names = [ host_config ]
+ elsif host_config # :localhost => { :aliases => 'local,127.0.0.1' ... }
+ names = [ host_config[:name] ||= name ]
+ aliases = host_config[:aliases]
+ if aliases && ! aliases.is_a?(Array)
+ aliases = aliases.split(',').each(&:strip!)
+ host_config[:aliases] = aliases
+ end
+ else # only name passed :
+ return tomcat.engine.find_child(name.to_s)
+ end
+
+ hosts = tomcat.engine.find_children
+ for name in names # host_names
+ host = hosts.find do |host|
+ host.name == name || (host.aliases || []).include?(name)
+ end
+ return host if host
+ end
+ nil
+ end
+
+ def web_app_root_dir(config, host = nil)
+ path = config[:root_dir] || config[:web_app_dir] || begin
+ path = config[:context_path]
+ ( path && path[0, 1] == '/' ) ? path[1..-1] : path
+ end || ( config[:context_name] ? config[:context_name].to_s : nil )
+
+ return nil if path.nil?
+ return File.expand_path(path) if File.exist?(path)
+
+ if host
+ base = host.app_base
+ ( path && base ) ? File.join(base, path) : path
+ else
+ path
+ end
end
def generate_default_keystore(config)
keystore_file = java.io.File.new(config[:keystoreFile])