a13g 0.1.0.beta3 → 0.1.0.beta4
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 +21 -0
- data/Rakefile +53 -0
- data/a13g-0.1.0.beta3.gem +0 -0
- data/a13g.gemspec +100 -0
- data/examples/consumer.rb +16 -0
- data/examples/multiple_connections.rb +26 -0
- data/examples/producer.rb +11 -0
- data/examples/simple_project/README +3 -0
- data/examples/simple_project/Rakefile +6 -0
- data/examples/simple_project/config/broker.yml +10 -0
- data/examples/simple_project/lib/consumers/first_consumer.rb +7 -0
- data/examples/simple_project/lib/consumers/second_consumer.rb +9 -0
- data/examples/simple_project/lib/simple_project.rb +20 -0
- data/lib/a13g.rb +68 -0
- data/lib/a13g/adapters.rb +45 -0
- data/lib/a13g/adapters/abstract_adapter.rb +330 -0
- data/lib/a13g/adapters/stomp_adapter.rb +163 -0
- data/lib/a13g/adapters/test_adapter.rb +102 -0
- data/lib/a13g/base.rb +448 -0
- data/lib/a13g/command.rb +69 -0
- data/lib/a13g/consumer.rb +129 -0
- data/lib/a13g/destination.rb +22 -0
- data/lib/a13g/errors.rb +60 -0
- data/lib/a13g/listener.rb +190 -0
- data/lib/a13g/message.rb +68 -0
- data/lib/a13g/producer.rb +107 -0
- data/lib/a13g/railtie.rb +4 -0
- data/lib/a13g/recipes.rb +31 -0
- data/lib/a13g/subscription.rb +123 -0
- data/lib/a13g/support/logger.rb +194 -0
- data/lib/a13g/support/utils.rb +25 -0
- data/lib/a13g/utils.rb +25 -0
- data/lib/a13g/version.rb +10 -0
- data/spec/a13g_spec.rb +74 -0
- data/spec/config/broker.yml +4 -0
- data/spec/dconfig/broker.yml +4 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +14 -0
- metadata +50 -4
@@ -0,0 +1,163 @@
|
|
1
|
+
module A13g
|
2
|
+
module Adapters
|
3
|
+
class StompAdapter < AbstractAdapter
|
4
|
+
def initialize(config, logger)
|
5
|
+
unless defined? Stomp
|
6
|
+
begin
|
7
|
+
require_library_or_gem('stomp')
|
8
|
+
rescue LoadError
|
9
|
+
$stderr.puts '!!! Please install the stomp gem and try again: gem install stomp.'
|
10
|
+
raise
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
config.symbolize_keys
|
15
|
+
|
16
|
+
config = {
|
17
|
+
:login => '',
|
18
|
+
:passcode => '',
|
19
|
+
:host => 'localhost',
|
20
|
+
:port => config[:ssl] ? 61612 : 61613,
|
21
|
+
:reliable => true,
|
22
|
+
:dead_letter_queue => '/queue/DLQ',
|
23
|
+
:client_id => nil,
|
24
|
+
:max_retry => 0,
|
25
|
+
:max_reconnect_delay => 30.0,
|
26
|
+
:timeout => -1,
|
27
|
+
:ssl => false
|
28
|
+
}.merge(config)
|
29
|
+
|
30
|
+
super(config, logger)
|
31
|
+
|
32
|
+
@connection_options = {
|
33
|
+
:hosts => [
|
34
|
+
{
|
35
|
+
:login => @config[:login],
|
36
|
+
:passcode => @config[:passcode],
|
37
|
+
:host => @config[:host],
|
38
|
+
:port => @config[:port],
|
39
|
+
:ssl => @config[:ssl],
|
40
|
+
:reliable => @config[:reliable],
|
41
|
+
},],
|
42
|
+
:initial_reconnect_delay => 0.01,
|
43
|
+
:max_reconnect_delay => @config[:max_reconnect_delay],
|
44
|
+
:use_exponential_back_off => true,
|
45
|
+
:back_off_multiplier => 2,
|
46
|
+
:max_reconnect_attempts => @config[:max_retry],
|
47
|
+
:randomize => false,
|
48
|
+
:backup => false,
|
49
|
+
:timeout => @config[:timeout]
|
50
|
+
}
|
51
|
+
|
52
|
+
connect
|
53
|
+
end
|
54
|
+
|
55
|
+
def adapter_name
|
56
|
+
'Stomp'.freeze
|
57
|
+
end
|
58
|
+
|
59
|
+
def url
|
60
|
+
"stomp://#{@config[:host]}:#{@config[:port]}" if @config
|
61
|
+
end
|
62
|
+
|
63
|
+
def active?
|
64
|
+
if @connection.respond_to?(:open?)
|
65
|
+
@connection.open?
|
66
|
+
else
|
67
|
+
false
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def reconnect!
|
72
|
+
disconnect!
|
73
|
+
connect
|
74
|
+
end
|
75
|
+
|
76
|
+
def disconnect!(headers={})
|
77
|
+
if active? && @connection.respond_to?(:disconnect)
|
78
|
+
@connection.disconnect(headers)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def ack(message, headers={})
|
83
|
+
if message
|
84
|
+
ack_headers = message.headers.has_key?(:transaction) ? message.headers[:transaction] : {}
|
85
|
+
headers = ack_headers.merge(headers)
|
86
|
+
result = raw_connection.ack(message.headers['message-id'], headers)
|
87
|
+
run_callbacks(:after_ack, [message, headers])
|
88
|
+
result
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def begin(name, headers={})
|
93
|
+
result = raw_connection.begin(name, headers)
|
94
|
+
run_callbacks(:after_begin_transaction, [name, headers])
|
95
|
+
result
|
96
|
+
end
|
97
|
+
|
98
|
+
def commit(name, headers={})
|
99
|
+
result = raw_connection.commit(name, headers)
|
100
|
+
run_callbacks(:after_commit_transaction, [name, headers])
|
101
|
+
result
|
102
|
+
end
|
103
|
+
|
104
|
+
def abort(name, headers={})
|
105
|
+
result = raw_connection.abort(name, headers)
|
106
|
+
run_callbacks(:after_abort_transaction, [name, headers])
|
107
|
+
result
|
108
|
+
end
|
109
|
+
|
110
|
+
def subscribe(destination, headers={}, sub_id=nil)
|
111
|
+
result = raw_connection.subscribe(destination, headers, sub_id)
|
112
|
+
run_callbacks(:after_subscribe, [destination, headers, sub_id])
|
113
|
+
result
|
114
|
+
end
|
115
|
+
|
116
|
+
def unsubscribe(destination, headers={}, sub_id=nil)
|
117
|
+
result = raw_connection.unsubscribe(destination, headers, sub_id=nil)
|
118
|
+
run_callbacks(:after_unsubscribe, [destination, headers, sub_id])
|
119
|
+
result
|
120
|
+
end
|
121
|
+
|
122
|
+
def publish(destination, message, headers={})
|
123
|
+
headers = { :persistent => true }.merge(headers)
|
124
|
+
result = raw_connection.publish(destination, message, headers)
|
125
|
+
run_callbacks(:after_publish, [destination, message, headers])
|
126
|
+
result
|
127
|
+
end
|
128
|
+
|
129
|
+
def receive
|
130
|
+
raw_message = raw_connection.receive
|
131
|
+
message = Message.new(raw_message, raw_message.headers['message-id'],
|
132
|
+
raw_message.headers, raw_message.body, raw_message.command, self)
|
133
|
+
run_callbacks(:after_receive, [message])
|
134
|
+
message
|
135
|
+
end
|
136
|
+
|
137
|
+
def unreceive(message, headers={})
|
138
|
+
defaults = { :dead_letter_queue => @config[:dead_letter_queue] }
|
139
|
+
headers = headers.merge(defaults)
|
140
|
+
result = raw_connection.unreceive(message, headers)
|
141
|
+
run_callbacks(:after_receive, [message, headers])
|
142
|
+
result
|
143
|
+
end
|
144
|
+
|
145
|
+
def client_ack?(message)
|
146
|
+
raw_connection.client_ack?(message)
|
147
|
+
end
|
148
|
+
|
149
|
+
protected
|
150
|
+
|
151
|
+
def connect
|
152
|
+
if @connection = Stomp::Connection.new(@connection_options)
|
153
|
+
logger.debug "Stomp connection with broker at #{url} has been established"
|
154
|
+
else
|
155
|
+
verify!
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
register(:stomp, StompAdapter)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
@@ -0,0 +1,102 @@
|
|
1
|
+
module A13g
|
2
|
+
module Adapters
|
3
|
+
class TestAdapter < AbstractAdapter
|
4
|
+
|
5
|
+
def initialize(config, logger)
|
6
|
+
super(config, logger)
|
7
|
+
@receiving_queue = []
|
8
|
+
connect
|
9
|
+
end
|
10
|
+
|
11
|
+
def adapter_name
|
12
|
+
'Test'.freeze
|
13
|
+
end
|
14
|
+
|
15
|
+
def url
|
16
|
+
''
|
17
|
+
end
|
18
|
+
|
19
|
+
def active?
|
20
|
+
@active ||= false
|
21
|
+
end
|
22
|
+
|
23
|
+
def reconnect!
|
24
|
+
disconnect!
|
25
|
+
connect
|
26
|
+
end
|
27
|
+
|
28
|
+
def disconnect!(headers={})
|
29
|
+
@active = false if active?
|
30
|
+
end
|
31
|
+
|
32
|
+
def ack(message, headers={})
|
33
|
+
if message
|
34
|
+
run_callbacks(:after_ack, [message, headers])
|
35
|
+
true
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def begin(name, headers={})
|
40
|
+
run_callbacks(:after_begin_transaction, [name, headers])
|
41
|
+
true
|
42
|
+
end
|
43
|
+
|
44
|
+
def commit(name, headers={})
|
45
|
+
run_callbacks(:after_commit_transaction, [name, headers])
|
46
|
+
true
|
47
|
+
end
|
48
|
+
|
49
|
+
def abort(name, headers={})
|
50
|
+
run_callbacks(:after_abort_transaction, [name, headers])
|
51
|
+
true
|
52
|
+
end
|
53
|
+
|
54
|
+
def subscribe(destination, headers={}, sub_id=nil)
|
55
|
+
run_callbacks(:after_subscribe, [destination, headers, sub_id])
|
56
|
+
true
|
57
|
+
end
|
58
|
+
|
59
|
+
def unsubscribe(destination, headers={}, sub_id=nil)
|
60
|
+
run_callbacks(:after_unsubscribe, [destination, headers, sub_id])
|
61
|
+
true
|
62
|
+
end
|
63
|
+
|
64
|
+
def publish(destination, message, headers={})
|
65
|
+
headers = {
|
66
|
+
'message-id' => 'TEST',
|
67
|
+
'destination' => destination.to_s
|
68
|
+
}.merge(headers)
|
69
|
+
msg = OpenStruct.new(
|
70
|
+
:body => message,
|
71
|
+
:headers => headers,
|
72
|
+
:command => 'MESSAGE'
|
73
|
+
)
|
74
|
+
@receiving_queue << Message.new(msg, msg.headers['message-id'],
|
75
|
+
msg.headers, message, msg.command, self)
|
76
|
+
run_callbacks(:after_publish, [destination, message, headers])
|
77
|
+
true
|
78
|
+
end
|
79
|
+
|
80
|
+
def receive
|
81
|
+
if message = @receiving_queue.shift
|
82
|
+
run_callbacks(:after_receive, [message])
|
83
|
+
message
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def unreceive(message, headers={})
|
88
|
+
run_callbacks(:after_receive, [message, headers])
|
89
|
+
end
|
90
|
+
|
91
|
+
protected
|
92
|
+
|
93
|
+
def connect
|
94
|
+
@active = true
|
95
|
+
logger.debug "Test connection has been established"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
register(:test, TestAdapter)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
data/lib/a13g/base.rb
ADDED
@@ -0,0 +1,448 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
3
|
+
module A13g
|
4
|
+
# It describes connection during setup.
|
5
|
+
class ConnectionSpecification
|
6
|
+
attr_reader :config, :adapter
|
7
|
+
def initialize(config, adapter)
|
8
|
+
@config, @adapter = config, adapter
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# It keeps context informations about connection and related consumers.
|
13
|
+
class ConnectionContext
|
14
|
+
attr_reader :name, :related_classes, :connection
|
15
|
+
|
16
|
+
# Constructor.
|
17
|
+
#
|
18
|
+
# @param [Symbol] name
|
19
|
+
# context name
|
20
|
+
# @param [A13g::Adapters::AbstractAdapter] connection
|
21
|
+
# related connection
|
22
|
+
# @param [Array] related classess
|
23
|
+
# list of consumers woring in this context
|
24
|
+
#
|
25
|
+
# @api public
|
26
|
+
def initialize(name, connection, related_classes=[])
|
27
|
+
@name, @connection, @related_classes = name, connection, related_classes
|
28
|
+
@related_classes << Base if name == :default
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_s # :nodoc:
|
32
|
+
name
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class Base
|
37
|
+
# Returns broker configuration for current connection and environment.
|
38
|
+
#
|
39
|
+
# For example, the following broker.yml...
|
40
|
+
#
|
41
|
+
# development:
|
42
|
+
# adapter: stomp
|
43
|
+
# host: localhost
|
44
|
+
# port: 61613
|
45
|
+
#
|
46
|
+
# ...would result in A13g::Base#config on development environment
|
47
|
+
# to look like this:
|
48
|
+
#
|
49
|
+
# {
|
50
|
+
# 'development' => {
|
51
|
+
# 'adapter' => 'stomp'
|
52
|
+
# 'host' => 'localhost'
|
53
|
+
# 'port' => 61613
|
54
|
+
# }
|
55
|
+
# }
|
56
|
+
#
|
57
|
+
# @api public
|
58
|
+
cattr_reader :configurations
|
59
|
+
@@configurations = HashWithIndifferentAccess.new
|
60
|
+
|
61
|
+
# @api public
|
62
|
+
cattr_accessor :logger, :instance_writer => false
|
63
|
+
@@logger = nil
|
64
|
+
|
65
|
+
# @api public
|
66
|
+
cattr_accessor :environment, :instance_writer => false
|
67
|
+
@@environment = nil
|
68
|
+
|
69
|
+
# @api public
|
70
|
+
cattr_reader :ready
|
71
|
+
@@ready = false
|
72
|
+
|
73
|
+
# Keeps list of connection contexts.
|
74
|
+
#
|
75
|
+
# @api public
|
76
|
+
cattr_reader :contexts
|
77
|
+
@@contexts = HashWithIndifferentAccess.new
|
78
|
+
|
79
|
+
# List of contexts related with consumers.
|
80
|
+
#
|
81
|
+
# @api public
|
82
|
+
cattr_reader :contextuals
|
83
|
+
@@contextuals = {}
|
84
|
+
|
85
|
+
# @api public
|
86
|
+
cattr_reader :path
|
87
|
+
@@path = nil
|
88
|
+
|
89
|
+
# Returns the connection currently associated with the class.
|
90
|
+
#
|
91
|
+
# @return [A13g::Adapters::AbstractAdapter]
|
92
|
+
# currenct connection
|
93
|
+
#
|
94
|
+
# @api public
|
95
|
+
def connection
|
96
|
+
self.class.connection
|
97
|
+
end
|
98
|
+
|
99
|
+
class << self
|
100
|
+
# Returns all pathes to important directories and files.
|
101
|
+
#
|
102
|
+
# You can define following pathes when your project structure is different
|
103
|
+
# than standard Ruby on Rails / Merb / Padrino application.
|
104
|
+
#
|
105
|
+
# A13g::Base.path.app # => path to application
|
106
|
+
# A13g::Base.path.config # => path to broker configuration file
|
107
|
+
# A13g::Base.path.consumers # => path to consumers directory
|
108
|
+
#
|
109
|
+
# There is also shortcut: A13g#path.
|
110
|
+
#
|
111
|
+
# @see A13g#path
|
112
|
+
#
|
113
|
+
# @return [Struct(:root, :log, :config, :consumers)]
|
114
|
+
# important directories pathes
|
115
|
+
#
|
116
|
+
# @api public
|
117
|
+
def path
|
118
|
+
unless @@path
|
119
|
+
@@path = OpenStruct.new
|
120
|
+
@@path.root ||= APP_ROOT if defined?(APP_ROOT)
|
121
|
+
@@path.root ||= RACK_ROOT if defined?(RACK_ROOT)
|
122
|
+
@@path.root ||= RAILS_ROOT if defined?(RAILS_ROOT)
|
123
|
+
@@path.root ||= Rails.root if defined?(Rails)
|
124
|
+
@@path.root ||= "./"
|
125
|
+
@@path.config ||= File.join(@@path.root.to_s, 'config')
|
126
|
+
@@path.consumers ||= File.join(@@path.root.to_s, 'app', 'consumers')
|
127
|
+
end
|
128
|
+
@@path
|
129
|
+
end
|
130
|
+
|
131
|
+
# Current environment.
|
132
|
+
#
|
133
|
+
# @return [String]
|
134
|
+
# env name
|
135
|
+
#
|
136
|
+
# @api public
|
137
|
+
def environment
|
138
|
+
unless @environment
|
139
|
+
@@environment ||= APP_ENV.to_s if defined?(APP_ENV)
|
140
|
+
@@environment ||= RACK_ENV.to_s if defined?(RACK_ENV)
|
141
|
+
@@environment ||= Rails.env.to_s if defined?(Rails)
|
142
|
+
@@environment ||= 'development'
|
143
|
+
end
|
144
|
+
@@environment
|
145
|
+
end
|
146
|
+
|
147
|
+
# Output logger for processor instance. Actually it's global logger for
|
148
|
+
# whole A13g.
|
149
|
+
#
|
150
|
+
# @return [Logger]
|
151
|
+
#
|
152
|
+
# @api public
|
153
|
+
def logger
|
154
|
+
unless @@logger
|
155
|
+
@@logger ||= APP_LOGGER if defined?(APP_LOGGER)
|
156
|
+
@@logger ||= Merb::Logger if defined?(Merb::Logger)
|
157
|
+
@@logger ||= RAILS_DEFAULT_LOGGER if defined?(RAILS_DEFAULT_LOGGER)
|
158
|
+
@@logger ||= Rails.logger if defined?(Rails) && !defined?(RAILS_DEFAULT_LOGGER)
|
159
|
+
@@logger ||= Logger.new(STDOUT)
|
160
|
+
end
|
161
|
+
@@logger
|
162
|
+
end
|
163
|
+
|
164
|
+
# Returns `true` if was successfully prepared to work.
|
165
|
+
#
|
166
|
+
# @return [Boolean]
|
167
|
+
# is A13g ready to work
|
168
|
+
#
|
169
|
+
# @api public
|
170
|
+
def ready?
|
171
|
+
@@ready
|
172
|
+
end
|
173
|
+
|
174
|
+
# Prepares configuration if not ready and creates connection in specified
|
175
|
+
# context.
|
176
|
+
#
|
177
|
+
# Here you have few examples how to setup A13g...
|
178
|
+
#
|
179
|
+
# # ...using configuration hash
|
180
|
+
# A13g::Base.setup(:default, :adapter => 'stomp', :host => 'localhost')
|
181
|
+
#
|
182
|
+
# # ...using configuration for specified environment
|
183
|
+
# A13g::Base.setup(:default, :development)
|
184
|
+
#
|
185
|
+
# # ...using default context and current environment configuration
|
186
|
+
# A13g::Base.setup() # or A13g::Base.setup(:default)
|
187
|
+
#
|
188
|
+
# # ...using shortcut
|
189
|
+
# A13g.setup(:default)
|
190
|
+
#
|
191
|
+
# @param [Context] context
|
192
|
+
# context name
|
193
|
+
# @param [Hash, Symbol, ConnectionSpecification] spec
|
194
|
+
# connection configuration
|
195
|
+
#
|
196
|
+
# @return [A13g::Adapters::AbstractAdapter]
|
197
|
+
# established connection
|
198
|
+
#
|
199
|
+
# @api public
|
200
|
+
def setup(context=:default, spec=nil)
|
201
|
+
unless ready?
|
202
|
+
path.freeze
|
203
|
+
environment.freeze
|
204
|
+
logger
|
205
|
+
if !spec.is_a?(Hash) && !spec.is_a?(ConnectionSpecification)
|
206
|
+
load_config_from_file
|
207
|
+
else
|
208
|
+
@@configurations[context] = HashWithIndifferentAccess.new
|
209
|
+
@@configurations[context][environment] = spec if spec.is_a?(Hash)
|
210
|
+
@@configurations[context][environment] = spec.config if spec.is_a?(ConnectionSpecification)
|
211
|
+
end
|
212
|
+
@@ready = true
|
213
|
+
end
|
214
|
+
establish_connection(context, spec)
|
215
|
+
end
|
216
|
+
|
217
|
+
# Clears all destinations and closes active connections.
|
218
|
+
#
|
219
|
+
# @api public
|
220
|
+
def teardown
|
221
|
+
destroy_subscriptions
|
222
|
+
clear_all_connections!
|
223
|
+
@@logger = nil
|
224
|
+
@@path = nil
|
225
|
+
@@environment = nil
|
226
|
+
@@contextuals = {}
|
227
|
+
@@configurations = HashWithIndifferentAccess.new
|
228
|
+
@@contexts = HashWithIndifferentAccess.new
|
229
|
+
@@ready = false
|
230
|
+
end
|
231
|
+
|
232
|
+
# Connection currently associated with the class or connection from
|
233
|
+
# specified context.
|
234
|
+
#
|
235
|
+
# @param [Symbol] name
|
236
|
+
# context name
|
237
|
+
#
|
238
|
+
# @return [A13g::Adapters::AbstractAdapter]
|
239
|
+
# found connection
|
240
|
+
#
|
241
|
+
# @api public
|
242
|
+
def connection(name=nil)
|
243
|
+
unless name.nil?
|
244
|
+
context = @@contexts[name]
|
245
|
+
if context
|
246
|
+
raise_connection_error(name) unless context.connection
|
247
|
+
return context.connection
|
248
|
+
end
|
249
|
+
else
|
250
|
+
if context
|
251
|
+
raise_connection_error(name) unless context.connection
|
252
|
+
return context.connection
|
253
|
+
else
|
254
|
+
return connection(:default)
|
255
|
+
end
|
256
|
+
end
|
257
|
+
raise_connection_error(:default)
|
258
|
+
end
|
259
|
+
|
260
|
+
# Defines connection context. For consumers can be called only once per class.
|
261
|
+
#
|
262
|
+
# @param [Symbol] name
|
263
|
+
# connection name
|
264
|
+
#
|
265
|
+
# @return [A13g::ConnectionContext]
|
266
|
+
# related context
|
267
|
+
#
|
268
|
+
# @api public
|
269
|
+
def context(name=nil)
|
270
|
+
if name.nil?
|
271
|
+
if @@contextuals[self]
|
272
|
+
return @@contextuals[self]
|
273
|
+
else
|
274
|
+
return @@contexts[:default]
|
275
|
+
end
|
276
|
+
end
|
277
|
+
unless @@contextuals[self]
|
278
|
+
if connection(name)
|
279
|
+
@@contexts[name].related_classes << self
|
280
|
+
@@contextuals[self] = @@contexts[name]
|
281
|
+
end
|
282
|
+
else
|
283
|
+
raise ContextAlreadyDefinedError
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
# Returns true if connected with broker is established and valid.
|
288
|
+
#
|
289
|
+
# @return [Boolean]
|
290
|
+
# connection state
|
291
|
+
#
|
292
|
+
# @api public
|
293
|
+
def connected?
|
294
|
+
connection && connection.active?
|
295
|
+
end
|
296
|
+
|
297
|
+
# Creates all defined subscriptions.
|
298
|
+
#
|
299
|
+
# @api public
|
300
|
+
def create_subscriptions
|
301
|
+
load_consumers
|
302
|
+
Subscription.all.each {|name, subscription| subscription.subscribe }
|
303
|
+
end
|
304
|
+
|
305
|
+
# Destroys all active subscriptions.
|
306
|
+
#
|
307
|
+
# @api public
|
308
|
+
def destroy_subscriptions
|
309
|
+
Subscription.all.each {|name, subscription| subscription.unsubscribe }
|
310
|
+
end
|
311
|
+
|
312
|
+
private
|
313
|
+
|
314
|
+
# Connects to broker using authorization specified in <tt>spec</tt> param.
|
315
|
+
#
|
316
|
+
# === Connection specification options
|
317
|
+
#
|
318
|
+
# * <tt>:adapter</tt> - You can use one of following: stomp, jms, wmq, test,
|
319
|
+
# beanstalk, asqs, realiable_msg
|
320
|
+
# * <tt>:username</tt> - User name for authentication
|
321
|
+
# * <tt>:password</tt> - Password for authentication
|
322
|
+
# * <tt>:host</tt> - Where broker is served
|
323
|
+
# * <tt>:port</tt> - Which port you want to connect
|
324
|
+
#
|
325
|
+
# There are also adapter specific options, like eg. <tt>:max_retry</tt>,
|
326
|
+
# or # <tt>:dead_letter_queue</tt> for stomp adapter.
|
327
|
+
#
|
328
|
+
# @see A13g#setup
|
329
|
+
#
|
330
|
+
# @api private
|
331
|
+
def establish_connection(context, spec=nil)
|
332
|
+
case spec
|
333
|
+
when nil
|
334
|
+
establish_connection(context, environment)
|
335
|
+
when ConnectionSpecification
|
336
|
+
remove_connection(name)
|
337
|
+
adapter = Adapters.load(spec.adapter)
|
338
|
+
conn = adapter.new(spec.config, logger)
|
339
|
+
@@contexts[context] = ConnectionContext.new(context, conn)
|
340
|
+
conn
|
341
|
+
when Symbol, String
|
342
|
+
if configurations[context] && configuration = configurations[context][spec.to_s]
|
343
|
+
establish_connection(context, configuration)
|
344
|
+
else
|
345
|
+
raise AdapterNotSpecified, "Broker in `#{spec}` environment is not configured"
|
346
|
+
end
|
347
|
+
when Hash
|
348
|
+
spec = spec.symbolize_keys
|
349
|
+
establish_connection unless spec.key?(:adapter)
|
350
|
+
establish_connection(context, ConnectionSpecification.new(spec, spec[:adapter]))
|
351
|
+
else
|
352
|
+
raise ArgumentError, "Unknown connection specification"
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
# @param [Symbol] name
|
357
|
+
# context name
|
358
|
+
#
|
359
|
+
# @api private
|
360
|
+
def raise_connection_error(name)
|
361
|
+
if name != :default
|
362
|
+
raise ConnectionNotEstablished, "Connection marked as `#{name}` is not established"
|
363
|
+
else
|
364
|
+
raise MissingDefaultContext, "There is not defined default connection context. Did you forgot about `:default`?"
|
365
|
+
end
|
366
|
+
nil
|
367
|
+
end
|
368
|
+
|
369
|
+
# Removes specified connection.
|
370
|
+
#
|
371
|
+
# @param [Symbol] name
|
372
|
+
# context name
|
373
|
+
#
|
374
|
+
# @api private
|
375
|
+
def remove_connection(context)
|
376
|
+
context = @@contexts.delete(context)
|
377
|
+
context.connection.disconnect! if context && context.connection
|
378
|
+
end
|
379
|
+
|
380
|
+
# Close all active connections.
|
381
|
+
#
|
382
|
+
# @api private
|
383
|
+
def clear_active_connections!
|
384
|
+
@@contexts.values.each do |context|
|
385
|
+
if c = context.connection
|
386
|
+
c.disconnect! if c.active?
|
387
|
+
end
|
388
|
+
end
|
389
|
+
end
|
390
|
+
|
391
|
+
# Close all connections.
|
392
|
+
#
|
393
|
+
# @api private
|
394
|
+
def clear_all_connections!
|
395
|
+
@@contexts.values.each do |context|
|
396
|
+
if c = context.connection
|
397
|
+
c.disconnect!
|
398
|
+
end
|
399
|
+
end
|
400
|
+
end
|
401
|
+
|
402
|
+
# Verify all connections.
|
403
|
+
#
|
404
|
+
# @api private
|
405
|
+
def verify_active_connections!
|
406
|
+
@@contexts.values.each do |context|
|
407
|
+
if c = context.connection
|
408
|
+
c.verify!
|
409
|
+
end
|
410
|
+
end
|
411
|
+
end
|
412
|
+
|
413
|
+
# Load configurations from file.
|
414
|
+
#
|
415
|
+
# @param [Symbol] context
|
416
|
+
# context name
|
417
|
+
#
|
418
|
+
# @return [HashWithIndifferentAccess]
|
419
|
+
# configuration hash
|
420
|
+
#
|
421
|
+
# @api private
|
422
|
+
def load_config_from_file(context=:default)
|
423
|
+
fname = context == :default ? "broker.yml" : "broker-#{context.to_s}.yml"
|
424
|
+
cpath = File.join(@@path.config, fname)
|
425
|
+
if File.exists?(cpath)
|
426
|
+
conf = YAML.load_file(cpath)
|
427
|
+
@@configurations[context] = HashWithIndifferentAccess.new(conf)
|
428
|
+
end
|
429
|
+
end
|
430
|
+
|
431
|
+
# Loads all available consumers.
|
432
|
+
#
|
433
|
+
# @api private
|
434
|
+
def load_consumers
|
435
|
+
if File.exists?(path.consumers)
|
436
|
+
begin
|
437
|
+
load File.join(path.consumers, 'application_consumer.rb')
|
438
|
+
rescue LoadError
|
439
|
+
# Do nothing... It is allowed to skip ApplicationConsumer.
|
440
|
+
end
|
441
|
+
Dir[File.join(path.consumers, '*_consumer.rb')].each do |f|
|
442
|
+
load f unless f =~ /\/application_consumer.rb\Z/
|
443
|
+
end
|
444
|
+
end
|
445
|
+
end
|
446
|
+
end
|
447
|
+
end
|
448
|
+
end
|