Class: Jettywrapper

Inherits:
Object
  • Object
show all
Includes:
Loggable, Singleton
Defined in:
lib/jettywrapper.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(params = {}) ⇒ Jettywrapper

configure the singleton with some defaults



27
28
29
30
31
32
33
34
35
36
# File 'lib/jettywrapper.rb', line 27

def initialize(params = {})
  # @pid = nil
  if defined?(Rails.root)
    @base_path = Rails.root
  else
    @base_path = "."
  end
  @logger = Logger.new(STDERR)
  @logger.debug 'Initializing jettywrapper'
end

Instance Attribute Details

#base_pathObject

The root of the application. Used for determining where log files and PID files should go.



24
25
26
# File 'lib/jettywrapper.rb', line 24

def base_path
  @base_path
end

#fedora_homeObject

Where is fedora located? Default is jetty_home/fedora



22
23
24
# File 'lib/jettywrapper.rb', line 22

def fedora_home
  @fedora_home
end

#jetty_homeObject

Where is jetty located?



18
19
20
# File 'lib/jettywrapper.rb', line 18

def jetty_home
  @jetty_home
end

#loggerObject

Where should logs be written?



23
24
25
# File 'lib/jettywrapper.rb', line 23

def logger
  @logger
end

#pidObject

the process id of the currently running jetty instance



16
17
18
# File 'lib/jettywrapper.rb', line 16

def pid
  @pid
end

#portObject

What port should jetty start on? Default is 8888



17
18
19
# File 'lib/jettywrapper.rb', line 17

def port
  @port
end

#quietObject

Keep quiet about jetty output?



20
21
22
# File 'lib/jettywrapper.rb', line 20

def quiet
  @quiet
end

#solr_homeObject

Where is solr located? Default is jetty_home/solr



21
22
23
# File 'lib/jettywrapper.rb', line 21

def solr_home
  @solr_home
end

#startup_waitObject

After jetty starts, how long to wait until starting the tests?



19
20
21
# File 'lib/jettywrapper.rb', line 19

def startup_wait
  @startup_wait
end

Class Method Details

.configure(params = {}) ⇒ Object

Set the jetty parameters. It accepts a Hash of symbols.

Parameters:

  • params (Hash<Symbol>) (defaults to: {})
  • :jetty_home (Symbol)

    Required. Where is jetty located?

  • :jetty_port (Symbol)

    What port should jetty start on? Default is 8888

  • :startup_wait (Symbol)

    After jetty starts, how long to wait before running tests? If you don’t let jetty start all the way before running the tests, they’ll fail because they can’t reach jetty.

  • :solr_home (Symbol)

    Where is solr? Default is jetty_home/solr

  • :fedora_home (Symbol)

    Where is fedora? Default is jetty_home/fedora/default

  • :quiet (Symbol)

    Keep quiet about jetty output? Default is true.



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/jettywrapper.rb', line 50

def configure(params = {})
  hydra_server = self.instance
  hydra_server.quiet = params[:quiet].nil? ? true : params[:quiet]
  if defined?(Rails.root)
   base_path = Rails.root
  else
   raise "You must set either RAILS_ROOT or :jetty_home so I know where jetty is" unless params[:jetty_home]
  end
  hydra_server.jetty_home = params[:jetty_home] || File.expand_path(File.join(base_path, 'jetty'))
  hydra_server.solr_home = params[:solr_home]  || File.join( hydra_server.jetty_home, "solr")
  hydra_server.fedora_home = params[:fedora_home] || File.join( hydra_server.jetty_home, "fedora","default")
  hydra_server.port = params[:jetty_port] || 8888
  hydra_server.startup_wait = params[:startup_wait] || 5
  return hydra_server
end

.is_jetty_running?(params) ⇒ Boolean

Determine whether the jetty at the given jetty_home is running

Examples:

Jettywrapper.is_jetty_running?(:jetty_home => '/path/to/jetty')

Parameters:

  • params: (Hash)

    :jetty_home is required. Which jetty do you want to check the status of?

Returns:

  • (Boolean)


138
139
140
141
142
143
# File 'lib/jettywrapper.rb', line 138

def is_jetty_running?(params)      
  Jettywrapper.configure(params)
  pid = Jettywrapper.instance.pid
  return false unless pid
  true
end

.is_pid_running?(pid) ⇒ Boolean

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

Returns:

  • (Boolean)


182
183
184
185
186
187
188
# File 'lib/jettywrapper.rb', line 182

def is_pid_running?(pid)
  begin
    return Process.getpgid(pid) != -1
  rescue Errno::ESRCH
    return false
  end
end

.is_port_in_use?(port) ⇒ Boolean

Check to see if the port is open so we can raise an error if we have a conflict

Examples:

Jettywrapper.is_port_open?(8983)

Parameters:

  • port (Fixnum)

    the port to check

Returns:

  • (Boolean)


162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/jettywrapper.rb', line 162

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

.pid(params) ⇒ Fixnum

Return the pid of the specified jetty, or return nil if it isn’t running

Examples:

Jettywrapper.pid(:jetty_home => '/path/to/jetty')

Parameters:

  • params: (Hash)

    :jetty_home is required.

Returns:

  • (Fixnum)

    or [nil]



150
151
152
153
154
155
# File 'lib/jettywrapper.rb', line 150

def pid(params)
  Jettywrapper.configure(params)
  pid = Jettywrapper.instance.pid
  return nil unless pid
  pid
end

.start(params) ⇒ Object

Convenience method for configuring and starting jetty with one command

Examples:

Jettywrapper.start_with_params(:jetty_home => '/path/to/jetty', :jetty_port => '8983')

Parameters:

  • params: (Hash)

    The configuration to use for starting jetty



114
115
116
117
118
# File 'lib/jettywrapper.rb', line 114

def start(params)
   Jettywrapper.configure(params)
   Jettywrapper.instance.start
   return Jettywrapper.instance
end

.stop(params) ⇒ Jettywrapper.instance

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).

Examples:

Jettywrapper.stop_with_params(:jetty_home => '/path/to/jetty')

Parameters:

  • params: (Hash)

    The jetty_home to use for stopping jetty

Returns:



127
128
129
130
131
# File 'lib/jettywrapper.rb', line 127

def stop(params)
   Jettywrapper.configure(params)
   Jettywrapper.instance.stop
   return Jettywrapper.instance
end

.wrap(params) ⇒ Object

Wrap the tests. Startup jetty, yield to the test task, capture any errors, shutdown jetty, and return the error.

Examples:

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
  }
  error = Jettywrapper.wrap(jetty_params) do   
    Rake::Task["rake:spec"].invoke 
    Rake::Task["rake:cucumber"].invoke 
  end 
  raise "test failures: #{error}" if error
end


84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/jettywrapper.rb', line 84

def wrap(params)
  error = false
  jetty_server = self.instance
  jetty_server.quiet = params[:quiet] || true
  jetty_server.jetty_home = params[:jetty_home]
  jetty_server.solr_home = params[:solr_home]
  jetty_server.port = params[:jetty_port] || 8888
  jetty_server.startup_wait = params[:startup_wait] || 5
  jetty_server.fedora_home = params[:fedora_home] || File.join( jetty_server.jetty_home, "fedora","default")

  begin
    # puts "starting jetty on #{RUBY_PLATFORM}"
    jetty_server.start
    sleep jetty_server.startup_wait
    yield
  rescue
    error = $!
    puts "*** Error starting hydra-jetty: #{error}"
  ensure
    # puts "stopping jetty server"
    jetty_server.stop
  end

  return error
end

Instance Method Details

#jetty_commandObject

What command is being run to invoke jetty?



194
195
196
# File 'lib/jettywrapper.rb', line 194

def jetty_command
  "java -Djetty.port=#{@port} -Dsolr.solr.home=#{@solr_home} -Dfedora.home=#{@fedora_home} -jar start.jar"
end

#jetty_home_to_pid_file(jetty_home) ⇒ String

Take the @jetty_home value and transform it into a legal filename

Examples:

/usr/local/jetty1 => _usr_local_jetty1.pid

Returns:

  • (String)

    the name of the pid_file



329
330
331
332
333
334
335
336
# File 'lib/jettywrapper.rb', line 329

def jetty_home_to_pid_file(jetty_home)
  begin
    jetty_home.gsub(/\//,'_') << ".pid"
  rescue
    raise "Couldn't make a pid file for jetty_home value #{jetty_home}"
    raise $!
  end
end

#nix_processObject



284
285
286
287
288
289
# File 'lib/jettywrapper.rb', line 284

def nix_process
  @pid = fork do
    # STDERR.close if @quiet
    exec jetty_command
  end
end

#nix_stopObject

stop jetty the *nix way



297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
# File 'lib/jettywrapper.rb', line 297

def nix_stop
  @logger.debug "Attempting to kill process id #{pid}."
  return nil if pid == nil
  begin
    pid_keeper = pid
    # Try to kill the process a few times to make sure it dies 
    3.times do
       Process.kill(9,pid)
       break if Jettywrapper.is_pid_running?(pid_keeper)==false
       sleep 2
    end
    FileUtils.rm(pid_path)
  rescue Errno::ESRCH
    @logger.debug "I tried to kill #{pid_keeper} but it appears it wasn't running."
    FileUtils.rm(pid_path)
  end
end

#pid_dirObject

The directory where the pid_file will be written



339
340
341
# File 'lib/jettywrapper.rb', line 339

def pid_dir
  File.expand_path(File.join(@base_path,'tmp','pids'))
end

#pid_fileObject

The file where the process ID will be written



321
322
323
# File 'lib/jettywrapper.rb', line 321

def pid_file
  jetty_home_to_pid_file(@jetty_home)
end

#pid_file?Boolean

Check to see if there is a pid file already

Returns:

  • (Boolean)

    true if the file exists, otherwise false



345
346
347
348
# File 'lib/jettywrapper.rb', line 345

def pid_file?
   return true if File.exist?(pid_path)
   false
end

#pid_pathObject

The fully qualified path to the pid_file



316
317
318
# File 'lib/jettywrapper.rb', line 316

def pid_path
  File.join(pid_dir, pid_file)
end

#platformObject

Determine whether we’re running on windows or unix. We need to know this so we know how to start and stop processes.



275
276
277
278
279
280
281
282
# File 'lib/jettywrapper.rb', line 275

def platform
  case RUBY_PLATFORM
    when /mswin32/
       return 'win'
    else
       return 'nix'
  end
end

#startObject

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”)

Examples:

Jettywrapper.configure(params)
Jettywrapper.instance.start
return Jettywrapper.instance


206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
# File 'lib/jettywrapper.rb', line 206

def start
  @logger.debug "Starting jetty with these values: "
  @logger.debug "jetty_home: #{@jetty_home}"
  @logger.debug "solr_home: #{@solr_home}"
  @logger.debug "fedora_home: #{@fedora_home}"
  @logger.debug "jetty_command: #{jetty_command}"
  
  # 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
    if Jettywrapper.is_port_in_use?(@jetty_port)
      raise("Port #{self.jetty_port} is already in use.")
    end
  end
  Dir.chdir(@jetty_home) do
    self.send "#{platform}_process".to_sym
  end
  File.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 "#{@pid}"
  f.close
  @logger.debug "Wrote pid file to #{pid_path} with value #{@pid}"
end

#stopObject

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

Examples:

Jettywrapper.configure(params)
Jettywrapper.instance.stop
return Jettywrapper.instance


247
248
249
250
251
252
253
254
255
256
257
258
259
260
# File 'lib/jettywrapper.rb', line 247

def stop    
  @logger.debug "Instance stop method called for pid #{pid}"
  if pid
    begin
      self.send "#{platform}_stop".to_sym
    rescue Errno::ESRCH
      @logger.error "I tried to kill the process #{pid} but it seems it wasn't running."
    end
    begin
      File.delete(pid_path)
    rescue
    end
  end
end

#win_processObject

Spawn a process on windows



263
264
265
266
267
268
269
270
271
# File 'lib/jettywrapper.rb', line 263

def win_process
  @pid = Process.create(
     :app_name         => jetty_command,
     :creation_flags   => Process::DETACHED_PROCESS,
     :process_inherit  => false,
     :thread_inherit   => true,
     :cwd              => "#{@jetty_home}"
  ).process_id
end

#win_stopObject

stop jetty the windows way



292
293
294
# File 'lib/jettywrapper.rb', line 292

def win_stop
  Process.kill(1, pid)
end