class Trinidad::Server

Constants

DEFAULT_HOST_APP_BASE

@private

DEFAULT_KEYSTORE_FILE

@private

Attributes

ajp_enabled[W]
app_base[W]
config[R]
hosts[W]
https_enabled=[W]
ssl_enabled[W]
trap[W]
web_apps[W]

Public Class Methods

new(config = Trinidad.configuration) click to toggle source
# File lib/trinidad/server.rb, line 8
def initialize(config = Trinidad.configuration)
  configure(config)
end

Protected Class Methods

logger() click to toggle source
# File lib/trinidad/server.rb, line 441
def self.logger
  Logging::LogFactory.getLog('org.apache.catalina.startup.Tomcat')
end

Public Instance Methods

add_ajp_connector(options = config[:ajp], tomcat = nil) click to toggle source
# File lib/trinidad/server.rb, line 125
def add_ajp_connector(options = config[:ajp], tomcat = nil)
  # backwards compatibility - single argument (tomcat = @tomcat)
  if options && ! options.respond_to?(:[])
    tomcat = options; options = config[:ajp]
  else
    tomcat = @tomcat
  end if tomcat.nil?

  options = options.respond_to?(:[]) ? options.dup : {}
  options[:address] = config[:address] unless options.key?(:address)

  add_service_connector(options, 'AJP/1.3', tomcat)
end
add_http_connector(options = config[:http], tomcat = nil) click to toggle source
# File lib/trinidad/server.rb, line 139
def add_http_connector(options = config[:http], tomcat = nil)
  # backwards compatibility - single argument (tomcat = @tomcat)
  if options && ! options.respond_to?(:[])
    tomcat = options; options = config[:http]
  else
    tomcat = @tomcat
  end if tomcat.nil?

  options = options.respond_to?(:[]) ? options.dup : {}
  options[:port] = config[:port] || 3000 unless options.key?(:port)
  options[:address] = config[:address] unless options.key?(:address)

  if options.delete(:nio)
    options[:protocol_handler] ||= 'org.apache.coyote.http11.Http11NioProtocol'
  end

  if options.delete(:apr)
    tomcat.server.add_lifecycle_listener(Tomcat::AprLifecycleListener.new)
  end

  add_service_connector(options, 'HTTP/1.1', tomcat)
end
add_ssl_connector(options = config[:ssl], tomcat = nil) click to toggle source
# File lib/trinidad/server.rb, line 165
def add_ssl_connector(options = config[:ssl], tomcat = nil)
  # backwards compatibility - single argument (tomcat = @tomcat)
  if options && ! options.respond_to?(:[])
    tomcat = options; options = config[:ssl]
  else
    tomcat = @tomcat
  end if tomcat.nil?

  options = { :scheme => 'https', :secure => true }.merge!( options.respond_to?(:[]) ? options : {} )
  options[:address] = config[:address] unless options.key?(:address)

  if keystore_file = options.delete(:keystore) || options.delete(:keystore_file)
    options[:keystoreFile] ||= keystore_file
  end
  options[:keystorePass] ||= options.delete(:keystore_pass) if options.key?(:keystore_pass)
  # handle "custom" alternative SSL (casing) options :
  options[:SSLEnabled] = options.delete(:ssl_enabled) || true # always true
  options[:SSLCertificateFile] ||= options.delete(:ssl_certificate_file) if options.key?(:ssl_certificate_file)
  options[:SSLCertificateKeyFile] ||= options.delete(:ssl_certificate_key_file) if options.key?(:ssl_certificate_key_file)
  options[:SSLVerifyClient] ||= options.delete(:ssl_verify_client) if options.key?(:ssl_verify_client)
  options[:SSLProtocol] ||= options.delete(:ssl_protocol) if options.key?(:ssl_protocol)
  # NOTE: there's quite more SSL prefixed options with APR ...

  if ! options[:keystoreFile] && ! options[:SSLCertificateFile]
    # generate one for development/testing SSL :
    options[:keystoreFile] = DEFAULT_KEYSTORE_FILE
    options[:keystorePass] ||= 'waduswadus42' # NOTE change/ask for default
    if File.exist?(DEFAULT_KEYSTORE_FILE)
      logger.info "Using (default) keystore at #{DEFAULT_KEYSTORE_FILE.inspect}"
    else
      generate_default_keystore(options)
    end
  end

  add_service_connector(options, 'HTTP/1.1', tomcat)
end
add_web_app(web_app, host = nil, start = nil) click to toggle source
# File lib/trinidad/server.rb, line 220
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::JavaLang::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
  Extensions.configure_webapp_extensions(web_app.extensions, tomcat, context)
  if lifecycle = web_app.define_lifecycle
    context.add_lifecycle_listener(lifecycle)
  end
  context
end
ajp_enabled?() click to toggle source
# File lib/trinidad/server.rb, line 51
def ajp_enabled?
  if ! defined?(@ajp_enabled) || @ajp_enabled.nil?
    ajp = @config[:ajp]
    @ajp_enabled = ( !! ajp && ( ! ajp.respond_to?(:empty?) || ! ajp.empty? ) )
  end
  @ajp_enabled
end
app_base() click to toggle source
# File lib/trinidad/server.rb, line 24
def app_base
  @app_base ||= @config[:app_base] || @config[:apps_base]
end
configure(config = Trinidad.configuration) click to toggle source
# File lib/trinidad/server.rb, line 12
def configure(config = Trinidad.configuration)
  configure_logging config[:logging] || config[:log]
  @config = config.freeze
end
deploy_web_apps(tomcat = self.tomcat) click to toggle source
# File lib/trinidad/server.rb, line 248
def deploy_web_apps(tomcat = self.tomcat)
  web_apps = create_web_apps
  add_host_monitor web_apps
  web_apps
end
hosts() click to toggle source
# File lib/trinidad/server.rb, line 19
def hosts
  @hosts ||= @config[:hosts]
end
http_configured=(flag) click to toggle source

@deprecated

# File lib/trinidad/server.rb, line 68
def http_configured=(flag); @http_configured = flag end
http_configured?() click to toggle source
# File lib/trinidad/server.rb, line 60
def http_configured?
  if ! defined?(@http_configured) || @http_configured.nil?
    http = @config[:http]
    @http_configured = ( !! http && ( ! http.respond_to?(:empty?) || ! http.empty? ) )
  end
  @http_configured
end
https_enabled?()
Alias for: ssl_enabled?
load_config(config) click to toggle source

@deprecated replaced with {#configure}

# File lib/trinidad/server.rb, line 17
def load_config(config); configure(config); end
load_host_monitor(web_apps) click to toggle source

@deprecated replaced with {#setup_host_monitor}

# File lib/trinidad/server.rb, line 123
def load_host_monitor(web_apps); add_host_monitor(web_apps); end
load_tomcat_server() click to toggle source

deprecated renamed to {#initialize_tomcat}

# File lib/trinidad/server.rb, line 113
def load_tomcat_server; initialize_tomcat; end
ssl_enabled?() click to toggle source
# File lib/trinidad/server.rb, line 40
def ssl_enabled?
  if ! defined?(@ssl_enabled) || @ssl_enabled.nil?
    ssl = @config.key?(:https) ? @config[:https] : @config[:ssl]
    @ssl_enabled = ( !! ssl && ( ! ssl.respond_to?(:empty?) || ! ssl.empty? ) )
  end
  @ssl_enabled
end
Also aliased as: https_enabled?
start() click to toggle source
# File lib/trinidad/server.rb, line 254
def start
  deploy_web_apps(tomcat)

  trap_signals if trap?

  tomcat.start
  tomcat.server.await
end
start!() click to toggle source
# File lib/trinidad/server.rb, line 263
def start!
  if defined?(@tomcat) && @tomcat
    @tomcat.destroy; @tomcat = nil
  end
  start
end
stop() click to toggle source
# File lib/trinidad/server.rb, line 270
def stop
  if defined?(@tomcat) && @tomcat
    @tomcat.stop; true
  end
end
stop!() click to toggle source
# File lib/trinidad/server.rb, line 276
def stop!
  (@tomcat.destroy; true) if stop
end
tomcat() click to toggle source
# File lib/trinidad/server.rb, line 70
def tomcat; @tomcat ||= initialize_tomcat; end
trap?() click to toggle source
# File lib/trinidad/server.rb, line 34
def trap?
  @trap = !! @config[:trap] if ! defined?(@trap) || @trap.nil?
  @trap
end
web_apps() click to toggle source
# File lib/trinidad/server.rb, line 29
def web_apps
  @web_apps ||= @config[:web_apps] || @config[:webapps]
end

Protected Instance Methods

add_host_monitor(app_holders) click to toggle source
# File lib/trinidad/server.rb, line 115
def add_host_monitor(app_holders)
  for host in tomcat.engine.find_children
    host_apps = select_host_apps(app_holders, host, tomcat)
    host.add_lifecycle_listener(Lifecycle::Host.new(self, *host_apps))
  end
end
configure_logging(logging) click to toggle source
# File lib/trinidad/server.rb, line 435
def configure_logging(logging)
  Trinidad::Logging.configure(logging)
end
create_host(app_base, host_config, tomcat = @tomcat) click to toggle source
# File lib/trinidad/server.rb, line 392
def create_host(app_base, host_config, tomcat = @tomcat)
  host = 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
create_hosts(tomcat = @tomcat) click to toggle source
# File lib/trinidad/server.rb, line 353
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
  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
  end if web_apps
end
create_web_app(app_config) click to toggle source
# File lib/trinidad/server.rb, line 344
def create_web_app(app_config)
  host_name = app_config[:host_name] || tomcat.host.name
  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
create_web_apps() click to toggle source
# File lib/trinidad/server.rb, line 282
def create_web_apps
  # 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]

    self.web_apps = { :default => default_app }
  end

  apps = []

  # 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

  # 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 == 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
  end if app_base || hosts

  apps
end
initialize_tomcat() click to toggle source
# File lib/trinidad/server.rb, line 72
def initialize_tomcat
  set_system_properties

  tomcat = Tomcat.new # @see Trinidad::Tomcat
  tomcat.base_dir = config[:base_dir] || Dir.pwd
  address = config[:address] if config.key?(:address)
  tomcat.hostname = address || 'localhost'
  tomcat.server.address = address || nil unless address.nil?
  tomcat.port = config[:port].to_i if config.key?(:port)
  default_host(tomcat)
  create_hosts(tomcat)
  tomcat.enable_naming

  http_connector = http_configured? || ( ! ajp_enabled? && ! ssl_enabled? )

  tomcat.connector = add_http_connector(config[:http], tomcat) if http_connector

  if ssl_enabled?
    options = config.key?(:https) ? config[:https] : config[:ssl]
    options = {} if options == true
    unless options.key?(:port)
      options[:port] = http_connector ? 3443 : config[:port] || 3443
    end
    connector = add_ssl_connector(options, tomcat)
    tomcat.connector = connector unless http_connector
    http_connector = true # tomcat.connector http: or https: or ajp:
  end

  if ajp_enabled?
    options = config[:ajp]; options = {} if options == true
    unless options.key?(:port)
      options[:port] = config[:port] || 8009 unless http_connector
    end
    connector = add_ajp_connector(options, tomcat)
    tomcat.connector = connector unless http_connector
  end

  Extensions.configure_server_extensions(config[:extensions], tomcat)
end
load_default_system_properties() click to toggle source

@deprecated renamed to {#set_system_properties}

# File lib/trinidad/server.rb, line 433
def load_default_system_properties; set_system_properties; end
logger() click to toggle source
# File lib/trinidad/server.rb, line 439
def logger; @logger ||= self.class.logger; end
set_system_properties(system = Java::JavaLang::System) click to toggle source
# File lib/trinidad/server.rb, line 429
def set_system_properties(system = Java::JavaLang::System)
  system.set_property("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE", 'true')
end
setup_host(app_base, host_config, host) click to toggle source
# File lib/trinidad/server.rb, line 401
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 |aliaz|
        next if (aliaz = aliaz.to_s) == host.name
        host.add_alias(aliaz) unless aliases.include?(aliaz)
      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

Private Instance Methods

add_service_connector(options, protocol = nil, tomcat = @tomcat) click to toggle source

NOTE: make sure to pass an options Hash that might be changed !

# File lib/trinidad/server.rb, line 203
def add_service_connector(options, protocol = nil, tomcat = @tomcat)
  connector = Tomcat::Connector.new(options.delete(:protocol) || protocol)
  connector.scheme = options.delete(:scheme) if options.key?(:scheme)
  connector.secure = options.key?(:secure) ? options.delete(:secure) : false
  connector.port = options.delete(:port).to_i if options[:port]

  if handler = options.delete(:protocol_handler) || options.delete(:protocol_handler_class_name)
    connector.protocol_handler_class_name = handler
  end

  options.each { |key, value| connector.setProperty(key.to_s, value.to_s) }

  tomcat.service.add_connector(connector)
  connector
end
default_host(tomcat = @tomcat) click to toggle source
# File lib/trinidad/server.rb, line 447
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] )
  if host_config.is_a?(String)
    host.name = host_config
  elsif host_config
    host_config.each { |name, value| host.send("#{name}=", value) }
  end
  host
end
default_host_base?(host) click to toggle source
# File lib/trinidad/server.rb, line 462
def default_host_base?(host)
  host.app_base.nil? || ( host.app_base == DEFAULT_HOST_APP_BASE && host.name == 'localhost' )
end
find_host(name, host_config, tomcat = nil) click to toggle source
# File lib/trinidad/server.rb, line 513
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
generate_default_keystore(file, pass = nil) click to toggle source
# File lib/trinidad/server.rb, line 560
def generate_default_keystore(file, pass = nil) # or (config)
  file, pass = file[:keystoreFile], file[:keystorePass] if pass.nil?
  file = Java::JavaIo::File.new(file)
  keystore_dir = file.parent_file
  if ! keystore_dir.exists && ! keystore_dir.mkdir
    raise "Unable to create keystore folder: #{keystore_dir.canonical_path}"
  end

  key_tool_args = [ "-genkey",
    "-alias", "localhost",
    "-dname", dname = "CN=localhost, OU=Trinidad, O=Trinidad, C=ES",
    "-keyalg", "RSA",
    "-validity", "365",
    "-storepass", "key",
    "-keystore", file.absolute_path,
    "-storepass", pass,
    "-keypass", pass ]

  logger.info "Generating a (default) keystore for localhost #{dname.inspect} at " <<
              "#{file.canonical_path} (password: '#{pass}')"

  Java::SunSecurityTools::KeyTool.main key_tool_args.to_java(:string)
end
select_host_apps(app_holders, host, tomcat = self.tomcat) click to toggle source
# File lib/trinidad/server.rb, line 506
def select_host_apps(app_holders, host, tomcat = self.tomcat)
  app_holders.select do |app_holder|
    host_name = app_holder.web_app.host_name
    host_name ? host_name == host.name : host == tomcat.host # default host
  end
end
set_host_app_base(app_root, host, default_host, web_app_hosts) click to toggle source
# File lib/trinidad/server.rb, line 466
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
        if app_real_path.index(base_path.realpath.to_s) == 0
          base_parent = true; break
        end
      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
trap_signals() click to toggle source
# File lib/trinidad/server.rb, line 584
def trap_signals
  trap('INT') { stop! }
  trap('TERM') { stop! }
end
web_app_root_dir(config, host = nil) click to toggle source
# File lib/trinidad/server.rb, line 543
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