explainer-rmb-rails 0.0.0
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/.document +5 -0
- data/.gitignore +5 -0
- data/LICENSE +20 -0
- data/README.rdoc +7 -0
- data/Rakefile +58 -0
- data/VERSION.yml +1 -0
- data/lib/listener_client.rb +58 -0
- data/lib/listener_daemon.rb +19 -0
- data/lib/listener_daemon_control.rb +70 -0
- data/lib/listener_main.rb +83 -0
- data/lib/mechanize_submitter.rb +83 -0
- data/lib/rmb-rails.rb +51 -0
- data/lib/rmb2.rb +69 -0
- data/lib/stomp_subscriber.rb +51 -0
- data/lib/submitter.rb +22 -0
- data/lib/subscriber.rb +22 -0
- data/rmb-rails.gemspec +57 -0
- data/test/rmb-rails_test.rb +7 -0
- data/test/test_helper.rb +9 -0
- metadata +73 -0
data/.document
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Ken Burgett
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "rmb-rails"
|
8
|
+
gem.summary = %Q{RESTful Message Beans for Rails}
|
9
|
+
gem.email = "keburgett@gmail.com"
|
10
|
+
gem.homepage = "http://github.com/explainer/rmb-rails"
|
11
|
+
gem.authors = ["Ken Burgett"]
|
12
|
+
gem.rubyforge_project = "rmb-rails"
|
13
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
14
|
+
end
|
15
|
+
|
16
|
+
Jeweler::RubyforgeTasks.new
|
17
|
+
rescue LoadError
|
18
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
19
|
+
end
|
20
|
+
|
21
|
+
require 'rake/testtask'
|
22
|
+
Rake::TestTask.new(:test) do |test|
|
23
|
+
test.libs << 'lib' << 'test'
|
24
|
+
test.pattern = 'test/**/*_test.rb'
|
25
|
+
test.verbose = true
|
26
|
+
end
|
27
|
+
|
28
|
+
begin
|
29
|
+
require 'rcov/rcovtask'
|
30
|
+
Rcov::RcovTask.new do |test|
|
31
|
+
test.libs << 'test'
|
32
|
+
test.pattern = 'test/**/*_test.rb'
|
33
|
+
test.verbose = true
|
34
|
+
end
|
35
|
+
rescue LoadError
|
36
|
+
task :rcov do
|
37
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
task :default => :test
|
43
|
+
|
44
|
+
require 'rake/rdoctask'
|
45
|
+
Rake::RDocTask.new do |rdoc|
|
46
|
+
if File.exist?('VERSION.yml')
|
47
|
+
config = YAML.load(File.read('VERSION.yml'))
|
48
|
+
version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
|
49
|
+
else
|
50
|
+
version = ""
|
51
|
+
end
|
52
|
+
|
53
|
+
rdoc.rdoc_dir = 'rdoc'
|
54
|
+
rdoc.title = "rmb-rails #{version}"
|
55
|
+
rdoc.rdoc_files.include('README*')
|
56
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
57
|
+
end
|
58
|
+
|
data/VERSION.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.4
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module RMB
|
2
|
+
|
3
|
+
#
|
4
|
+
# This code is called from the client application. It starts/stops the daemon controller script
|
5
|
+
#
|
6
|
+
class ListenerClient
|
7
|
+
|
8
|
+
def initialize(hash)
|
9
|
+
@hash = hash
|
10
|
+
end
|
11
|
+
|
12
|
+
def start
|
13
|
+
control('start')
|
14
|
+
end
|
15
|
+
|
16
|
+
def stop
|
17
|
+
control('stop')
|
18
|
+
end
|
19
|
+
|
20
|
+
def control(action)
|
21
|
+
setup
|
22
|
+
control_script = "ruby #{File.dirname(__FILE__)}/#{LD}control.rb #{action}"
|
23
|
+
control_params = "#{@hash[:working_dir]} #{@hash[:key]}"
|
24
|
+
system("#{control_script} #{control_params} -- #{control_params}")
|
25
|
+
end
|
26
|
+
|
27
|
+
def app_name
|
28
|
+
@hash[:daemon_options][:app_name]
|
29
|
+
end
|
30
|
+
|
31
|
+
def properties=(hash)
|
32
|
+
@hash=hash
|
33
|
+
end
|
34
|
+
|
35
|
+
def properties
|
36
|
+
@hash
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def setup
|
42
|
+
# add derived values to the daemon_options hash
|
43
|
+
@hash[:daemon_options][:app_name] = "#{LD}#{@hash[:key]}"
|
44
|
+
@hash[:daemon_options][:dir] = File.join("#{@hash[:working_dir]}", "tmp", "pids")
|
45
|
+
# Ensure the properties folder is present
|
46
|
+
properties_dir = File.join("#{@hash[:working_dir]}", "tmp", "properties")
|
47
|
+
if !File.directory?(properties_dir)
|
48
|
+
Dir.mkdir(properties_dir)
|
49
|
+
end
|
50
|
+
# dump the properties to a tmp file
|
51
|
+
File.open(File.join("#{properties_dir}", "#{app_name}.properties"), "w+") do |f|
|
52
|
+
Marshal.dump(@hash, f)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
#
|
2
|
+
# Listener Daemon main program
|
3
|
+
#
|
4
|
+
|
5
|
+
# Value of ARGV[0] => RAILS_ROOT
|
6
|
+
# Value of ARGV[1] => key
|
7
|
+
|
8
|
+
require 'rubygems'
|
9
|
+
require 'logger'
|
10
|
+
require 'rmb-rails'
|
11
|
+
|
12
|
+
#
|
13
|
+
# start the daemon worker code...
|
14
|
+
#
|
15
|
+
listener = RMB::ListenerMain.new(ARGV[0], ARGV[1])
|
16
|
+
# ...and listen forever
|
17
|
+
listener.run
|
18
|
+
|
19
|
+
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
#
|
3
|
+
# Listener Daemon Control Program
|
4
|
+
#
|
5
|
+
require 'logger'
|
6
|
+
require 'daemons'
|
7
|
+
require 'rmb-rails'
|
8
|
+
#
|
9
|
+
# This ruby script is invoked by the ListenerClient.control method to start and stop the daemon
|
10
|
+
#
|
11
|
+
=begin rdoc
|
12
|
+
+app_name+ The name of the application. This will be used to contruct the name of the pid files and log files.
|
13
|
+
Defaults to the basename of the script.
|
14
|
+
+ARGV+ An array of strings containing parameters and switches for Daemons. This includes both parameters for Daemons
|
15
|
+
itself and the controlling script. These are assumed to be separated by an array element ’—’,
|
16
|
+
e.g. [‘start’, ‘f’, ’—’, ‘param1_for_script’, ‘param2_for_script’].
|
17
|
+
If not given, ARGV (the parameters given to the Ruby process) will be used.
|
18
|
+
+dir_mode+ Either
|
19
|
+
+script (the directory for writing the pid files to given by +dir is interpreted relative to the script location given by script)
|
20
|
+
+normal (the directory given by +dir is interpreted as a (absolute or relative) path)
|
21
|
+
+system (/var/run is used as the pid file directory)
|
22
|
+
+dir+ Used in combination with +dir_mode (description above)
|
23
|
+
+multiple+ Specifies whether multiple instances of the same script are allowed to run at the same time
|
24
|
+
+ontop+ When given (i.e. set to true), stay on top, i.e. do not daemonize the application
|
25
|
+
(but the pid-file and other things are written as usual)
|
26
|
+
+mode+
|
27
|
+
+load Load the script with Kernel.load;
|
28
|
+
+exec Execute the script file with Kernel.exec
|
29
|
+
+backtrace+ Write a backtrace of the last exceptions to the file ’[app_name].log’ in the pid-file
|
30
|
+
directory if the application exits due to an uncaught exception
|
31
|
+
+monitor+ Monitor the programs and restart crashed instances
|
32
|
+
+log_output+ When given (i.e. set to true), redirect both STDOUT and STDERR to a logfile named ’[app_name].output’ in the pid-file directory
|
33
|
+
+keep_pid_files+ When given do not delete lingering pid-files (files for which the process is no longer running).
|
34
|
+
+hard_exit+ When given use exit! to end a daemons instead of exit (this will for example not call at_exit handlers).
|
35
|
+
=end
|
36
|
+
# Value of ARGV[0] => action (start|stop)
|
37
|
+
# Value of ARGV[1] => RAILS_ROOT
|
38
|
+
|
39
|
+
# Value of ARGV[2] => listener key
|
40
|
+
key = ARGV[2]
|
41
|
+
daemon_name = "listener_daemon_#{key}"
|
42
|
+
# Value of ARGV[2] => --
|
43
|
+
# Value of ARGV[3] => listener key
|
44
|
+
|
45
|
+
messages_dir = File.join("#{ARGV[1]}", "tmp", "messages")
|
46
|
+
if !File.directory?(messages_dir)
|
47
|
+
Dir.mkdir(messages_dir)
|
48
|
+
end
|
49
|
+
logger = Logger.new("#{ARGV[1]}/log/listener_daemon_control.log")
|
50
|
+
logger.info "Starting the #{File.basename(__FILE__)}..."
|
51
|
+
0.upto ARGV.length-1 do |i|
|
52
|
+
logger.info "Value of ARGV[#{i}] => #{ARGV[i]}"
|
53
|
+
end
|
54
|
+
|
55
|
+
# load an instance of the ListenerMain in order to get the options hash
|
56
|
+
l = RMB::ListenerMain.new(ARGV[1], ARGV[2])
|
57
|
+
options = l.hash[:daemon_options]
|
58
|
+
options.each do |key, value|
|
59
|
+
logger.info "options[#{key}] => #{value}"
|
60
|
+
end
|
61
|
+
|
62
|
+
# launch the daemon file from the same directory as this program file.
|
63
|
+
target = File.join(File.dirname(__FILE__), "listener_daemon.rb")
|
64
|
+
logger.info "Launching #{target}...\n"
|
65
|
+
begin
|
66
|
+
Daemons.run(target, options)
|
67
|
+
rescue Exception
|
68
|
+
logger.fatal "#{__FILE__}:#{__LINE__} Exception #{$!}"
|
69
|
+
raise
|
70
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module RMB
|
2
|
+
#
|
3
|
+
# This is the class that gets instantiated from the listener daemon
|
4
|
+
# It contains the worker code of the daemon
|
5
|
+
#
|
6
|
+
class ListenerMain
|
7
|
+
attr_accessor :submitter, :subscriber, :logger, :hash
|
8
|
+
=begin rdoc
|
9
|
+
+initialize+ Given root (the working directory or RAILS_ROOT) and key (the unique identifier that denotes a
|
10
|
+
particular Listener instance), the initialize method sets up the entire daemon.
|
11
|
+
* The daemon name is created from the key
|
12
|
+
* A logger object is instantiated for the use of the daemon components
|
13
|
+
* A hash of properties is read from a properties file, whose name is also derived from the root and key.
|
14
|
+
* An instance of a subclass of Subscriber is created to act as the front end of the daemon, listening on a topic or queue for the arrival of a message
|
15
|
+
* An instance of a subclass of Submitter is created to send messages on to a parent rails app, using RESTful techniques to send the message to a rails controller.
|
16
|
+
=end
|
17
|
+
def initialize(root, key)
|
18
|
+
@key = key
|
19
|
+
@logger = Logger.new("#{root}/log/#{app_name}.log")
|
20
|
+
@logger.info "\nStarting #{File.basename(__FILE__)} --> #{app_name}..."
|
21
|
+
@hash = nil
|
22
|
+
# load the marshalled hash of properties
|
23
|
+
f = File.join("#{root}", "tmp", "properties", "#{app_name}.properties")
|
24
|
+
File.open(f) do |props|
|
25
|
+
@hash = Marshal.load(props)
|
26
|
+
end
|
27
|
+
@hash[:logger] = @logger
|
28
|
+
# instantiate the two objects that comprise the front-end and the back-end of
|
29
|
+
# this listener daemon
|
30
|
+
front = @hash[:subscriber]
|
31
|
+
@subscriber = Kernel.eval "#{front[:class_name]}.new"
|
32
|
+
@subscriber.properties=@hash
|
33
|
+
back = @hash[:submitter]
|
34
|
+
@submitter = Kernel.eval "#{back[:class_name]}.new"
|
35
|
+
@submitter.properties=@hash
|
36
|
+
end
|
37
|
+
=begin rdoc
|
38
|
+
+run+
|
39
|
+
* The subscriber is connected to a message broker,
|
40
|
+
* the submitter is connected to the rails controller,
|
41
|
+
* then an infinite loop is entered
|
42
|
+
* subscriber waits to receive a message
|
43
|
+
* when a message arrives, it is sent to the rails controller via the submitter
|
44
|
+
* ...and loop forever
|
45
|
+
=end
|
46
|
+
def run
|
47
|
+
begin
|
48
|
+
subscriber.connect
|
49
|
+
logger.info "subscriber connected."
|
50
|
+
rescue Exception
|
51
|
+
logger.fatal "#{__FILE__}:#{__LINE__} Exception #{$!}"
|
52
|
+
raise
|
53
|
+
end
|
54
|
+
begin
|
55
|
+
submitter.connect
|
56
|
+
logger.info "submitter logged in."
|
57
|
+
rescue Exception
|
58
|
+
logger.fatal "#{__FILE__}:#{__LINE__} Exception #{$!}"
|
59
|
+
raise
|
60
|
+
end
|
61
|
+
logger.info "Waiting for messages in #{subscriber.url}."
|
62
|
+
loop do
|
63
|
+
begin
|
64
|
+
message = subscriber.receive
|
65
|
+
rescue
|
66
|
+
logger.fatal "#{__FILE__}:#{__LINE__} Exception #{$!}"
|
67
|
+
raise
|
68
|
+
end
|
69
|
+
begin
|
70
|
+
submitter.send(message)
|
71
|
+
rescue Exception
|
72
|
+
logger.fatal "#{__FILE__}:#{__LINE__} Exception #{$!}"
|
73
|
+
raise
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def app_name
|
79
|
+
"#{LD}#{@key}"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'mechanize'
|
2
|
+
require 'submitter'
|
3
|
+
|
4
|
+
module RMB
|
5
|
+
|
6
|
+
class MechanizeSubmitter < Submitter
|
7
|
+
attr_accessor :user, :password, :login_url, :delivery_url, :agent, :logger, :agent, :daemon_name
|
8
|
+
=begin rdoc
|
9
|
+
+properties=(hash)+ Accepts a hash object containing all of the configuration properties required. These properties are copied into instance variables.
|
10
|
+
=end
|
11
|
+
def properties=(hash)
|
12
|
+
super
|
13
|
+
@hash = hash
|
14
|
+
@daemon_name = "#{LD}#{hash[:key]}"
|
15
|
+
submitter = hash[:submitter]
|
16
|
+
@user = submitter[:user] || ""
|
17
|
+
@password = submitter[:password] || ""
|
18
|
+
@login_url = submitter[:login_url] || ""
|
19
|
+
@delivery_url = submitter[:delivery_url] || ""
|
20
|
+
begin
|
21
|
+
@agent = WWW::Mechanize.new
|
22
|
+
@agent.user_agent_alias = 'Linux Mozilla'
|
23
|
+
rescue Exception
|
24
|
+
logger.fatal "#{__FILE__}:#{__LINE__} Exception #{$!}"
|
25
|
+
raise
|
26
|
+
end
|
27
|
+
end
|
28
|
+
=begin rdoc
|
29
|
+
+connect+ Uses the login_url property, along with the user and password properties, to log in to the rails app.
|
30
|
+
=end
|
31
|
+
def connect
|
32
|
+
super
|
33
|
+
#this code requires completion of the User controller in the main app
|
34
|
+
end
|
35
|
+
=begin rdoc
|
36
|
+
+marshal_message_body+ Extracts the message body from the rest of the message, and marshals it into a file. The name of this file will be submitted to the rails app, along with other message attributes.
|
37
|
+
=end
|
38
|
+
def marshal_message_body(message)
|
39
|
+
file = File.join("#{@hash[:working_dir]}", "tmp", "messages", "#{daemon_name}_#{message.headers["timestamp"]}.message")
|
40
|
+
File.open(file, "w+") do |f|
|
41
|
+
Marshal.dump(message.body, f)
|
42
|
+
end
|
43
|
+
file
|
44
|
+
end
|
45
|
+
=begin rdoc
|
46
|
+
+send+ This method uses the +delivery_url+ property to issue a get request to retrieve the <tt>new document</tt> form from the rails app. The form is filled in with message attributes and submitted to the rails app for processing.
|
47
|
+
=end
|
48
|
+
def send(message)
|
49
|
+
super
|
50
|
+
file = marshal_message_body(message)
|
51
|
+
begin
|
52
|
+
page = agent.get(delivery_url)
|
53
|
+
rescue Exception
|
54
|
+
logger.fatal "#{__FILE__}:#{__LINE__} Exception #{$!}"
|
55
|
+
raise
|
56
|
+
end
|
57
|
+
form = page.forms.first
|
58
|
+
|
59
|
+
# I can't seem to make the Mechanize code recognize fields as attributes, so
|
60
|
+
# I am forced to treat them as an array
|
61
|
+
form.fields[1].value = @hash[:key]
|
62
|
+
form.fields[2].value = message.headers["destination"]
|
63
|
+
form.fields[3].value = message.headers["message-id"]
|
64
|
+
form.fields[4].value = message.headers["content-type"]
|
65
|
+
form.fields[5].value = message.headers["priority"]
|
66
|
+
form.fields[6].value = message.headers["content-length"]
|
67
|
+
form.fields[7].value = message.headers["timestamp"]
|
68
|
+
form.fields[8].value = message.headers["expires"]
|
69
|
+
form.fields[9].value = file
|
70
|
+
|
71
|
+
#logger.info "final form: #{form.inspect}"
|
72
|
+
|
73
|
+
#submit the form
|
74
|
+
begin
|
75
|
+
page = agent.submit(form)
|
76
|
+
rescue Exception
|
77
|
+
logger.fatal "#{__FILE__}:#{__LINE__} Exception #{$!}"
|
78
|
+
raise
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
data/lib/rmb-rails.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'stomp'
|
2
|
+
require 'subscriber'
|
3
|
+
|
4
|
+
module RMB
|
5
|
+
|
6
|
+
class StompSubscriber < Subscriber
|
7
|
+
attr_accessor :url, :host, :port, :user, :password, :connection, :logger
|
8
|
+
=begin rdoc
|
9
|
+
+connect+ Opens a connection with the message broker, and then subscribes on the url
|
10
|
+
=end
|
11
|
+
def connect
|
12
|
+
super
|
13
|
+
begin
|
14
|
+
@connection = Stomp::Connection.open(user, password, host, port)
|
15
|
+
@connection.subscribe url, { :ack => 'auto' }
|
16
|
+
rescue Exception
|
17
|
+
logger.fatal "#{__FILE__}:#{__LINE__} Exception #{$!}"
|
18
|
+
raise
|
19
|
+
end
|
20
|
+
logger.info "Waiting for messages in #{url}."
|
21
|
+
end
|
22
|
+
=begin rdoc
|
23
|
+
+properties=(hash)+ Accepts a hash object containing all of the configuration properties required. These properties are copied into instance variables.
|
24
|
+
=end
|
25
|
+
def properties=(hash)
|
26
|
+
subscriber = hash[:subscriber]
|
27
|
+
@url = subscriber[:url] || "/queue/something"
|
28
|
+
@host = subscriber[:host] || ""
|
29
|
+
@port = subscriber[:port] || 61613
|
30
|
+
@user = subscriber[:user] || ""
|
31
|
+
@password = subscriber[:password] || ""
|
32
|
+
@connection = nil
|
33
|
+
super
|
34
|
+
end
|
35
|
+
=begin rdoc
|
36
|
+
+receive+ Executes a receive on the connection, thus blocking the daemon until a message arrives. Then answers the message.
|
37
|
+
=end
|
38
|
+
def receive
|
39
|
+
super
|
40
|
+
begin
|
41
|
+
message = @connection.receive
|
42
|
+
rescue Exception
|
43
|
+
logger.fatal "#{__FILE__}:#{__LINE__} Exception #{$!}"
|
44
|
+
raise
|
45
|
+
end
|
46
|
+
logger.info "Received message: #{message.inspect}"
|
47
|
+
message
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
data/lib/rmb2.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
#
|
2
|
+
# = RESTful-Message-Beans module
|
3
|
+
#
|
4
|
+
# Abstraction which wraps the daemon scripts and
|
5
|
+
# handles the setup.
|
6
|
+
#
|
7
|
+
require 'listener_client'
|
8
|
+
require 'listener_main'
|
9
|
+
require 'mechanize_submitter'
|
10
|
+
require 'stomp_subscriber'
|
11
|
+
require 'submitter'
|
12
|
+
require 'subscriber'
|
13
|
+
|
14
|
+
module RMB
|
15
|
+
# This multi-level hash contains the initial set of properties needed to launch a Listener daemon.
|
16
|
+
#* Make a writable copy of this hash
|
17
|
+
#* Fill in the areas denoted by <<fill>> with your values
|
18
|
+
#* Add additional properties required by the Subscriber and Submitter classes used
|
19
|
+
#* Pass this has as the sole parameter in listener_client = ListenerClient.new(hash) to set up the daemon
|
20
|
+
#* Call listener_client.start to start the daemon.
|
21
|
+
RMB_Properties = {
|
22
|
+
:key => "<<fill>>",
|
23
|
+
:subscriber => {
|
24
|
+
:class_name => "<<fill>>" #set this to selected subclass of Subscriber
|
25
|
+
# <== add more properties for your Subscriber here
|
26
|
+
},
|
27
|
+
:submitter => {
|
28
|
+
:class_name => "<<fill>>" #set this to selected subclass of Submitter
|
29
|
+
# <== add more properties for your Submitter here
|
30
|
+
},
|
31
|
+
:working_dir => "<<fill>>", #set this to the RAILS_ROOT directory
|
32
|
+
|
33
|
+
:daemon_options => { #these options are passed directly to the class method Daemons.run(target, options)
|
34
|
+
:app_name => "", #custom name for this daemon, set by ListenerClient#initialize
|
35
|
+
:ARGV => nil, #use the program defaults
|
36
|
+
:dir_mode => :normal, #requires absolute path
|
37
|
+
:dir => "<<fill>>", #this is set to "#{working_dir}/tmp/pids" by ListenerClient#setup
|
38
|
+
:multiple => false, #this will allow multiple daemons to run
|
39
|
+
:ontop => false, #
|
40
|
+
:mode => :load,
|
41
|
+
:backtrace => false,
|
42
|
+
:monitor => false,
|
43
|
+
:log_output => true,
|
44
|
+
:keep_pid_files => true,
|
45
|
+
:hard_exit => true
|
46
|
+
}
|
47
|
+
}
|
48
|
+
|
49
|
+
LD = "listener_daemon_" #prefix for all listener_daemon artifacts produced: pids, log files, property files, and message files
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
if __FILE__ == $0
|
54
|
+
hash = RMB::ListenerClient.properties('inventory', RAILS_ROOT, 'StompSubscriber', 'MechanizeSubmitter')
|
55
|
+
hash[:daemon_options][:dir] = File.join("#{hash[:working_dir]}", "tmp", "pids")
|
56
|
+
front = hash[:subscriber]
|
57
|
+
front[:url] = '/topic/inventory'
|
58
|
+
front[:host] = 'localhost'
|
59
|
+
front[:port] = 61613
|
60
|
+
front[:user] = nil
|
61
|
+
front[:password] = nil
|
62
|
+
|
63
|
+
back = hash[:submitter]
|
64
|
+
back[:login_url] = 'http://localhost:3000/login'
|
65
|
+
back[:delivery_url] = 'http://localhost:3000/documents/new'
|
66
|
+
lc = RMB::ListenerClient.new(hash)
|
67
|
+
puts lc.inspect
|
68
|
+
lc.start
|
69
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'stomp'
|
2
|
+
require 'subscriber'
|
3
|
+
|
4
|
+
module RMB
|
5
|
+
|
6
|
+
class StompSubscriber < Subscriber
|
7
|
+
attr_accessor :url, :host, :port, :user, :password, :connection, :logger
|
8
|
+
=begin rdoc
|
9
|
+
+connect+ Opens a connection with the message broker, and then subscribes on the url
|
10
|
+
=end
|
11
|
+
def connect
|
12
|
+
super
|
13
|
+
begin
|
14
|
+
@connection = Stomp::Connection.open(user, password, host, port)
|
15
|
+
@connection.subscribe url, { :ack => 'auto' }
|
16
|
+
rescue Exception
|
17
|
+
logger.fatal "#{__FILE__}:#{__LINE__} Exception #{$!}"
|
18
|
+
raise
|
19
|
+
end
|
20
|
+
logger.info "Waiting for messages in #{url}."
|
21
|
+
end
|
22
|
+
=begin rdoc
|
23
|
+
+properties=(hash)+ Accepts a hash object containing all of the configuration properties required. These properties are copied into instance variables.
|
24
|
+
=end
|
25
|
+
def properties=(hash)
|
26
|
+
subscriber = hash[:subscriber]
|
27
|
+
@url = subscriber[:url] || "/queue/something"
|
28
|
+
@host = subscriber[:host] || ""
|
29
|
+
@port = subscriber[:port] || 61613
|
30
|
+
@user = subscriber[:user] || ""
|
31
|
+
@password = subscriber[:password] || ""
|
32
|
+
@connection = nil
|
33
|
+
super
|
34
|
+
end
|
35
|
+
=begin rdoc
|
36
|
+
+receive+ Executes a receive on the connection, thus blocking the daemon until a message arrives. Then answers the message.
|
37
|
+
=end
|
38
|
+
def receive
|
39
|
+
super
|
40
|
+
begin
|
41
|
+
message = @connection.receive
|
42
|
+
rescue Exception
|
43
|
+
logger.fatal "#{__FILE__}:#{__LINE__} Exception #{$!}"
|
44
|
+
raise
|
45
|
+
end
|
46
|
+
logger.info "Received message: #{message.inspect}"
|
47
|
+
message
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
data/lib/submitter.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
module RMB
|
2
|
+
|
3
|
+
class Submitter
|
4
|
+
=begin rdoc
|
5
|
+
+properties=(hash)+ This method establishes the logger for the subclass.
|
6
|
+
=end
|
7
|
+
def properties=(hash)
|
8
|
+
@logger = hash[:logger]
|
9
|
+
end
|
10
|
+
=begin rdoc
|
11
|
+
+connect+ This is an abstract method, intended to be implemented by a subclass.
|
12
|
+
=end
|
13
|
+
def connect
|
14
|
+
end
|
15
|
+
=begin rdoc
|
16
|
+
+connect+ This is an abstract method, intended to be implemented by a subclass.
|
17
|
+
=end
|
18
|
+
def send(message)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
data/lib/subscriber.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
module RMB
|
2
|
+
|
3
|
+
class Subscriber
|
4
|
+
=begin rdoc
|
5
|
+
+connect+ This is an abstract method, intended to be implemented by a subclass.
|
6
|
+
=end
|
7
|
+
def connect
|
8
|
+
end
|
9
|
+
=begin rdoc
|
10
|
+
+receive+ This is an abstract method, intended to be implemented by a subclass.
|
11
|
+
=end
|
12
|
+
def receive
|
13
|
+
end
|
14
|
+
=begin rdoc
|
15
|
+
+properties=(hash)+ This method establishes the logger for the subclass.
|
16
|
+
=end
|
17
|
+
def properties=(hash)
|
18
|
+
@logger = hash[:logger]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
data/rmb-rails.gemspec
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{rmb-rails}
|
5
|
+
s.version = "0.0.0"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Ken Burgett"]
|
9
|
+
s.date = %q{2009-07-21}
|
10
|
+
s.email = %q{keburgett@gmail.com}
|
11
|
+
s.extra_rdoc_files = [
|
12
|
+
"LICENSE",
|
13
|
+
"README.rdoc"
|
14
|
+
]
|
15
|
+
s.files = [
|
16
|
+
".document",
|
17
|
+
".gitignore",
|
18
|
+
"LICENSE",
|
19
|
+
"README.rdoc",
|
20
|
+
"Rakefile",
|
21
|
+
"VERSION.yml",
|
22
|
+
"lib/listener_client.rb",
|
23
|
+
"lib/listener_daemon.rb",
|
24
|
+
"lib/listener_daemon_control.rb",
|
25
|
+
"lib/listener_main.rb",
|
26
|
+
"lib/mechanize_submitter.rb",
|
27
|
+
"lib/rmb-rails.rb",
|
28
|
+
"lib/rmb2.rb",
|
29
|
+
"lib/stomp_subscriber.rb",
|
30
|
+
"lib/submitter.rb",
|
31
|
+
"lib/subscriber.rb",
|
32
|
+
"rmb-rails.gemspec",
|
33
|
+
"test/rmb-rails_test.rb",
|
34
|
+
"test/test_helper.rb"
|
35
|
+
]
|
36
|
+
s.has_rdoc = true
|
37
|
+
s.homepage = %q{http://github.com/explainer/rmb-rails}
|
38
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
39
|
+
s.require_paths = ["lib"]
|
40
|
+
s.rubyforge_project = %q{rmb-rails}
|
41
|
+
s.rubygems_version = %q{1.3.1}
|
42
|
+
s.summary = %q{RESTful Message Beans for Rails}
|
43
|
+
s.test_files = [
|
44
|
+
"test/test_helper.rb",
|
45
|
+
"test/rmb-rails_test.rb"
|
46
|
+
]
|
47
|
+
|
48
|
+
if s.respond_to? :specification_version then
|
49
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
50
|
+
s.specification_version = 2
|
51
|
+
|
52
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
53
|
+
else
|
54
|
+
end
|
55
|
+
else
|
56
|
+
end
|
57
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: explainer-rmb-rails
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ken Burgett
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-07-21 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description:
|
17
|
+
email: keburgett@gmail.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- LICENSE
|
24
|
+
- README.rdoc
|
25
|
+
files:
|
26
|
+
- .document
|
27
|
+
- .gitignore
|
28
|
+
- LICENSE
|
29
|
+
- README.rdoc
|
30
|
+
- Rakefile
|
31
|
+
- VERSION.yml
|
32
|
+
- lib/listener_client.rb
|
33
|
+
- lib/listener_daemon.rb
|
34
|
+
- lib/listener_daemon_control.rb
|
35
|
+
- lib/listener_main.rb
|
36
|
+
- lib/mechanize_submitter.rb
|
37
|
+
- lib/rmb-rails.rb
|
38
|
+
- lib/rmb2.rb
|
39
|
+
- lib/stomp_subscriber.rb
|
40
|
+
- lib/submitter.rb
|
41
|
+
- lib/subscriber.rb
|
42
|
+
- rmb-rails.gemspec
|
43
|
+
- test/rmb-rails_test.rb
|
44
|
+
- test/test_helper.rb
|
45
|
+
has_rdoc: true
|
46
|
+
homepage: http://github.com/explainer/rmb-rails
|
47
|
+
post_install_message:
|
48
|
+
rdoc_options:
|
49
|
+
- --charset=UTF-8
|
50
|
+
require_paths:
|
51
|
+
- lib
|
52
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: "0"
|
57
|
+
version:
|
58
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: "0"
|
63
|
+
version:
|
64
|
+
requirements: []
|
65
|
+
|
66
|
+
rubyforge_project: rmb-rails
|
67
|
+
rubygems_version: 1.2.0
|
68
|
+
signing_key:
|
69
|
+
specification_version: 2
|
70
|
+
summary: RESTful Message Beans for Rails
|
71
|
+
test_files:
|
72
|
+
- test/test_helper.rb
|
73
|
+
- test/rmb-rails_test.rb
|