class Jettywrapper

Constants

VERSION

Attributes

env[W]
hydra_jetty_version[W]
jetty_dir[W]
tmp_dir[W]
url[W]
base_path[RW]
java_command[RW]
java_opts[RW]
java_version[RW]
jetty_home[RW]
jetty_opts[RW]
port[RW]
quiet[RW]
solr_home[RW]
startup_wait[RW]

Public Class Methods

app_root() click to toggle source
# File lib/jettywrapper.rb, line 138
def app_root
  return @app_root if @app_root
  @app_root = Rails.root if defined?(Rails) and defined?(Rails.root)
  @app_root ||= APP_ROOT if defined?(APP_ROOT)
  @app_root ||= '.'
end
check_java_version!(java_path, required_java_version) click to toggle source
# File lib/jettywrapper.rb, line 335
def check_java_version! java_path, required_java_version
  Tempfile.open("java-version-output") do |f|
    process = ChildProcess.build(java_path, "-version")
    process.io.stderr = f
    process.start

    begin
      process.poll_for_exit(10)
    rescue ChildProcess::TimeoutError
      process.stop # tries increasingly harsher methods to kill the process.
    end

    f.rewind
    err = f.read

    java_version = if version = err.match(/java version "([^"]+)"/)
      version[1]
    else
      raise "Java not found, or an error was encountered when running `#{java_path} -version`: #{err}"
    end

    unless Gem::Dependency.new('', required_java_version.gsub("_", ".")).match?('', java_version.gsub("_", "."))
      raise "Java #{required_java_version} is required to run Jetty. Found Java #{java_version} when running `#{java_path} -version`."
    end
  end

  true
end
clean() click to toggle source
# File lib/jettywrapper.rb, line 126
def clean
  FileUtils.remove_dir(jetty_dir,true)
  unzip
end
configure(params = {}) click to toggle source

Set the jetty parameters. It accepts a Hash of symbols. @param [Hash<Symbol>] params

:jetty_home Required. Jetty's home direcotry
:jetty_port  Jetty's port.  Default is 8888.   Note that attribute is named port, but params passed in expect :jetty_port
:startup_wait How many seconds to wait for jetty to spin up.  Default is 5. If jetty doesn't finish spinning up, tests can fail because they can't reach jetty.
:solr_home Solr's home directory. Default is jetty_home/solr
:quiet Keep True(default) to reduce jetty's output
:java_opts options to pass to the jvm (ex. ["-Xmx512mb", "-Xms128mb"])
:jetty_opts options to pass to jetty (ex. ["etc/my_jetty.xml", "etc/other.xml"] as in http://wiki.eclipse.org/Jetty/Reference/jetty.xml_usage
# File lib/jettywrapper.rb, line 204
def configure(params = {})
  jetty_server = self.instance
  jetty_server.reset_process!
  jetty_server.configure params
  return jetty_server
end
default_environment() click to toggle source
# File lib/jettywrapper.rb, line 162
def default_environment
  'development'
end
download(url = nil) click to toggle source
# File lib/jettywrapper.rb, line 76
def download(url = nil)
  return if File.exists? zip_file
  self.url = url if url
  logger.info "Downloading jetty at #{self.url} ..."
  FileUtils.mkdir tmp_dir unless File.exists? tmp_dir

  begin
    open(self.url) do |io|
      IO.copy_stream(io,zip_file)
    end
  rescue Exception => e
    abort "Unable to download jetty from #{self.url} #{e.message}"
  end
end
env() click to toggle source
# File lib/jettywrapper.rb, line 145
def env
  @env ||= begin
    case
    when ENV['JETTYWRAPPER_ENV']
      ENV['JETTYWRAPPER_ENV']
    when defined?(Rails) && Rails.respond_to?(:env)
      Rails.env
    when ENV['RAILS_ENV']
      ENV['RAILS_ENV']
    when ENV['environment']
      ENV['environment']
    else
      default_environment
    end
  end
end
expanded_zip_dir(tmp_save_dir) click to toggle source
# File lib/jettywrapper.rb, line 120
def expanded_zip_dir(tmp_save_dir)
  # This old way is more specific, but won't work for blacklight-jetty
  #expanded_dir = Dir[File.join(tmp_save_dir, "hydra-jetty-*")].first
  Dir[File.join(tmp_save_dir, "*")].first
end
hydra_jetty_version() click to toggle source
# File lib/jettywrapper.rb, line 55
def hydra_jetty_version
  @hydra_jetty_version ||= 'master'
end
instance() click to toggle source
# File lib/jettywrapper.rb, line 211
def instance
  @instance ||= Jettywrapper.new
end
is_jetty_running?(params) click to toggle source

Determine whether the jetty at the given jetty_home is running @param [Hash] params: :jetty_home is required. Which jetty do you want to check the status of? @return [Boolean] @example

Jettywrapper.is_jetty_running?(:jetty_home => '/path/to/jetty')
# File lib/jettywrapper.rb, line 283
def is_jetty_running?(params)
  Jettywrapper.configure(params)
  pid = Jettywrapper.instance.pid
  return false unless pid
  true
end
is_pid_running?(pid) click to toggle source

Check to see if the pid is actually running. This only works on unix.

# File lib/jettywrapper.rb, line 327
def is_pid_running?(pid)
  begin
    return Process.getpgid(pid) != -1
  rescue Errno::ESRCH
    return false
  end
end
is_port_in_use?(port) click to toggle source

Check to see if the port is open so we can raise an error if we have a conflict @param [Fixnum] port the port to check @return [Boolean] @example

Jettywrapper.is_port_open?(8983)
# File lib/jettywrapper.rb, line 307
def is_port_in_use?(port)
  begin
    Timeout::timeout(1) do
      begin
        s = TCPSocket.new('127.0.0.1', port)
        s.close
        return true
      rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
        return false
      rescue
        return false
      end
    end
  rescue Timeout::Error
  end

  return false
end
jetty_dir() click to toggle source
# File lib/jettywrapper.rb, line 72
def jetty_dir
  @jetty_dir ||= 'jetty'
end
load_config(config_name = env) click to toggle source
# File lib/jettywrapper.rb, line 166
def load_config(config_name = env)
  @env = config_name
  jetty_file = "#{app_root}/config/jetty.yml"

  unless File.exists?(jetty_file)
    logger.warn "Didn't find expected jettywrapper config file at #{jetty_file}, using default file instead."
    jetty_file = File.expand_path("../config/jetty.yml", File.dirname(__FILE__))
  end

  begin
    jetty_erb = ERB.new(IO.read(jetty_file)).result(binding)
  rescue
    raise("jetty.yml was found, but could not be parsed with ERB. \n#{$!.inspect}")
  end

  begin
    jetty_yml = YAML::load(jetty_erb)
  rescue
    raise("jetty.yml was found, but could not be parsed.\n")
  end

  if jetty_yml.nil? || !jetty_yml.is_a?(Hash)
    raise("jetty.yml was found, but was blank or malformed.\n")
  end

  config = jetty_yml.with_indifferent_access
  config[config_name] || config['default'.freeze]
end
logger() click to toggle source

If ::Rails.logger is defined and is not nil, it will be returned. If no logger has been defined, a new STDOUT Logger will be created.

# File lib/jettywrapper.rb, line 370
def logger
  @@logger ||= defined?(::Rails) && Rails.logger ? ::Rails.logger : ::Logger.new(STDOUT)
end
logger=(logger) click to toggle source
# File lib/jettywrapper.rb, line 364
def logger=(logger)
  @@logger = logger
end
new(params = {}) click to toggle source
# File lib/jettywrapper.rb, line 32
def initialize(params = {})
  self.base_path = self.class.app_root
  configure(params)
end
pid(params) click to toggle source

Return the pid of the specified jetty, or return nil if it isn't running @param [Hash] params: :jetty_home is required. @return [Fixnum] or [nil] @example

Jettywrapper.pid(:jetty_home => '/path/to/jetty')
# File lib/jettywrapper.rb, line 295
def pid(params)
  Jettywrapper.configure(params)
  pid = Jettywrapper.instance.pid
  return nil unless pid
  pid
end
reset_config() click to toggle source
# File lib/jettywrapper.rb, line 131
def reset_config
  @app_root = nil
  @env = nil
  @url = nil
  @hydra_jetty_version = nil
end
start(params) click to toggle source

Convenience method for configuring and starting jetty with one command @param [Hash] params: The configuration to use for starting jetty @example

Jettywrapper.start(:jetty_home => '/path/to/jetty', :jetty_port => '8983')
# File lib/jettywrapper.rb, line 258
def start(params)
  unzip unless File.exists? jetty_dir
  Jettywrapper.configure(params)
  Jettywrapper.instance.start
  return Jettywrapper.instance
end
stop(params) click to toggle source

Convenience method for configuring and starting jetty with one command. Note that for stopping, only the :jetty_home value is required (including other values won't hurt anything, though). @param [Hash] params: The jetty_home to use for stopping jetty @return [Jettywrapper.instance] @example

Jettywrapper.stop_with_params(:jetty_home => '/path/to/jetty')
# File lib/jettywrapper.rb, line 272
def stop(params)
   Jettywrapper.configure(params)
   Jettywrapper.instance.stop
   return Jettywrapper.instance
end
tmp_dir() click to toggle source
# File lib/jettywrapper.rb, line 64
def tmp_dir
  @tmp_dir ||= 'tmp'
end
unzip() click to toggle source
# File lib/jettywrapper.rb, line 91
def unzip
  download unless File.exists? zip_file
  logger.info "Unpacking #{zip_file}..."
  tmp_save_dir = File.join tmp_dir, 'jetty_generator'
  begin
    Zip::File.open(zip_file) do |zip_file|
      # Handle entries one by one
      zip_file.each do |entry|
        dest_file = File.join(tmp_save_dir,entry.name)
        FileUtils.remove_entry(dest_file,true)
        entry.extract(dest_file)
      end
    end
  rescue Exception => e
    abort "Unable to unzip #{zip_file} into tmp_save_dir/ #{e.message}"
  end

  # Remove the old jetty directory if it exists
  FileUtils.remove_dir(jetty_dir,true)

  # Move the expanded zip file into the final destination.
  expanded_dir = expanded_zip_dir(tmp_save_dir)
  begin
    FileUtils.mv(expanded_dir, jetty_dir)
  rescue Exception => e
    abort "Unable to move #{expanded_dir} into #{jetty_dir}/ #{e.message}"
  end
end
url() click to toggle source
# File lib/jettywrapper.rb, line 59
def url
  @url ||= defined?(ZIP_URL) ? ZIP_URL : "https://github.com/projecthydra/hydra-jetty/archive/#{hydra_jetty_version}.zip"
  @url
end
wrap(params) { || ... } click to toggle source

Wrap the tests. Startup jetty, yield to the test task, capture any errors, shutdown jetty, and return the error. @example Using this method in a rake task

require 'jettywrapper'
desc "Spin up jetty and run tests against it"
task :newtest do
  jetty_params = {
    :jetty_home => "/path/to/jetty",
    :quiet => false,
    :jetty_port => 8983,
    :startup_wait => 30,
    :jetty_opts => "/etc/jetty.xml"
  }
  error = Jettywrapper.wrap(jetty_params) do
    Rake::Task["rake:spec"].invoke
    Rake::Task["rake:cucumber"].invoke
  end
  raise "test failures: #{error}" if error
end
# File lib/jettywrapper.rb, line 234
def wrap(params)
  error = false
  jetty_server = self.configure(params)

  begin
    jetty_server.start
    yield
  rescue
    error = $!
    logger.error "*** Error starting jetty: #{error}"
  ensure
    # puts "stopping jetty server"
    jetty_server.stop
  end

  raise error if error

  return error
end
zip_file() click to toggle source
# File lib/jettywrapper.rb, line 68
def zip_file
  ENV['JETTY_ZIP'] || File.join(tmp_dir, url.split('/').last)
end

Public Instance Methods

check_java_version!() click to toggle source
# File lib/jettywrapper.rb, line 390
def check_java_version!
  if java_version
    @checked_java_version ||= Jettywrapper.check_java_version!(java_command, java_version)
  end
end
configure(params) click to toggle source
# File lib/jettywrapper.rb, line 37
def configure params
  self.quiet        = params[:quiet].nil? ? true : params[:quiet]
  self.jetty_home   = params[:jetty_home  ] || File.expand_path(File.join(self.base_path, 'jetty'))
  self.solr_home    = params[:solr_home   ] || File.join( self.jetty_home, "solr")
  self.port         = params[:jetty_port  ] || 8888
  self.startup_wait = params[:startup_wait] || 5
  self.java_opts    = params[:java_opts   ] || []
  self.java_command = params[:java_command] || default_java_command
  self.java_version = params[:java_version]
  self.jetty_opts   = params[:jetty_opts  ] || []
end
java_variables() click to toggle source
# File lib/jettywrapper.rb, line 385
def java_variables
  ["-Djetty.port=#{@port}",
   "-Dsolr.solr.home=#{Shellwords.escape(@solr_home)}"]
end
jetty_command() click to toggle source

What command is being run to invoke jetty?

# File lib/jettywrapper.rb, line 381
def jetty_command
  [java_command, java_variables, java_opts, "-jar", "start.jar", jetty_opts].flatten
end
jetty_home_to_pid_file(jetty_home) click to toggle source

Take the @jetty_home value and transform it into a legal filename @return [String] the name of the pid_file @example

/usr/local/jetty1 => _usr_local_jetty1.pid
# File lib/jettywrapper.rb, line 510
def jetty_home_to_pid_file(jetty_home)
  begin
    jetty_home.gsub(/\//,'_') << "_#{self.class.env}" << ".pid"
  rescue Exception => e
    raise "Couldn't make a pid file for jetty_home value #{jetty_home}\n  Caused by: #{e}"
  end
end
logger() click to toggle source
# File lib/jettywrapper.rb, line 376
def logger
  self.class.logger
end
pid() click to toggle source

the process id of the currently running jetty instance

# File lib/jettywrapper.rb, line 530
def pid
  File.open( pid_path ) { |f| return f.gets.to_i } if File.exist?(pid_path)
end
pid_dir() click to toggle source

The directory where the pid_file will be written

# File lib/jettywrapper.rb, line 519
def pid_dir
  File.expand_path(File.join(base_path,'tmp','pids'))
end
pid_file() click to toggle source

The file where the process ID will be written

# File lib/jettywrapper.rb, line 502
def pid_file
  jetty_home_to_pid_file(@jetty_home)
end
pid_file?() click to toggle source

Check to see if there is a pid file already @return true if the file exists, otherwise false

# File lib/jettywrapper.rb, line 525
def pid_file?
  File.exist?(pid_path)
end
pid_path() click to toggle source

The fully qualified path to the pid_file

# File lib/jettywrapper.rb, line 496
def pid_path
  #need to memoize this, becasuse the base path could be relative and the cwd can change in the yield block of wrap
  @path ||= File.join(pid_dir, pid_file)
end
process() click to toggle source
# File lib/jettywrapper.rb, line 453
def process
  @process ||= begin
     process = ChildProcess.build(*jetty_command)
     if self.quiet
       process.io.stderr = File.open(File.expand_path("jettywrapper.log"), "w+")
       process.io.stdout = process.io.stderr
       logger.warn "Logging jettywrapper stdout to #{File.expand_path(process.io.stderr.path)}"
     else
       process.io.inherit!
     end
     process.detach = true

     process
   end
end
reset_process!() click to toggle source
# File lib/jettywrapper.rb, line 469
def reset_process!
  @process = nil
end
start() click to toggle source

Start the jetty server. Check the pid file to see if it is running already, and stop it if so. After you start jetty, write the PID to a file. This is the instance start method. It must be called on Jettywrapper.instance You're probably better off using Jettywrapper.start(:jetty_home => “/path/to/jetty”) @example

Jettywrapper.configure(params)
Jettywrapper.instance.start
return Jettywrapper.instance
# File lib/jettywrapper.rb, line 404
def start
  logger.debug "Starting jetty with these values: "
  logger.debug "jetty_home: #{@jetty_home}"
  logger.debug "jetty_command: #{jetty_command.join(' ')}"

  check_java_version!

  # Check to see if we can start.
  # 1. If there is a pid, check to see if it is really running
  # 2. Check to see if anything is blocking the port we want to use
  if pid
    if Jettywrapper.is_pid_running?(pid)
      raise("Server is already running with PID #{pid}")
    else
      logger.warn "Removing stale PID file at #{pid_path}"
      File.delete(pid_path)
    end
  end
  if Jettywrapper.is_port_in_use?(self.port)
    raise("Port #{self.port} is already in use.")
  end
  benchmark "Started jetty" do
    Dir.chdir(@jetty_home) do
      process.start
    end
    FileUtils.makedirs(pid_dir) unless File.directory?(pid_dir)
    begin
      f = File.new(pid_path,  "w")
    rescue Errno::ENOENT, Errno::EACCES
      f = File.new(File.join(base_path,'tmp',pid_file),"w")
    end
    f.puts "#{process.pid}"
    f.close
    logger.debug "Wrote pid file to #{pid_path} with value #{process.pid}"
    startup_wait!
  end
end
startup_wait!() click to toggle source

Wait for the jetty server to start and begin listening for requests

# File lib/jettywrapper.rb, line 443
def startup_wait!
  begin
  Timeout::timeout(startup_wait) do
    sleep 1 until (Jettywrapper.is_port_in_use? self.port)
  end
  rescue Timeout::Error
    logger.warn "Waited #{startup_wait} seconds for jetty to start, but it is not yet listening on port #{self.port}. Continuing anyway."
  end
end
stop() click to toggle source

Instance stop method. Must be called on Jettywrapper.instance You're probably better off using Jettywrapper.stop(:jetty_home => “/path/to/jetty”) @example

Jettywrapper.configure(params)
Jettywrapper.instance.stop
return Jettywrapper.instance
# File lib/jettywrapper.rb, line 479
def stop
  logger.debug "Instance stop method called for pid '#{pid}'"
  if pid
    if @process
      @process.stop
    else
      Process.kill("KILL", pid) rescue nil
    end

    begin
      File.delete(pid_path)
    rescue
    end
  end
end

Private Instance Methods

default_java_command() click to toggle source
# File lib/jettywrapper.rb, line 536
def default_java_command
  # Use the same JAVA_HOME lookup as Solr
  @default_java_command ||= if ENV["JAVA_HOME"]
    if File.exists? File.join(ENV["JAVA_HOME"], "bin", "java")
      File.join(ENV["JAVA_HOME"], "bin", "java")
    end

    if File.exists? File.join(ENV["JAVA_HOME"], "amd64", "bin", "java")
      File.join(ENV["JAVA_HOME"], "amd64", "bin", "java")
    end
  end

  @default_java_command ||= "java"
end