hot_bunnies 1.5.0-java → 2.0.0.pre1-java
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/lib/ext/rabbitmq-client.jar +0 -0
- data/lib/hot_bunnies/channel.rb +287 -9
- data/lib/hot_bunnies/consumers.rb +152 -0
- data/lib/hot_bunnies/exceptions.rb +151 -0
- data/lib/hot_bunnies/exchange.rb +22 -30
- data/lib/hot_bunnies/juc.rb +9 -0
- data/lib/hot_bunnies/metadata.rb +90 -0
- data/lib/hot_bunnies/queue.rb +52 -265
- data/lib/hot_bunnies/session.rb +170 -0
- data/lib/hot_bunnies/version.rb +1 -1
- data/lib/hot_bunnies.rb +5 -91
- metadata +15 -39
- data/.gitignore +0 -7
- data/.rvmrc +0 -1
- data/.travis.yml +0 -12
- data/ChangeLog.md +0 -46
- data/Gemfile +0 -10
- data/LICENSE +0 -20
- data/README.md +0 -58
- data/Rakefile +0 -6
- data/examples/blocking_subscription.rb +0 -36
- data/examples/non_blocking_subscription.rb +0 -32
- data/examples/non_blocking_subscription_with_executor.rb +0 -38
- data/hot_bunnies.gemspec +0 -24
- data/spec/integration/alternate_exchanges_spec.rb +0 -36
- data/spec/integration/basic_consume_spec.rb +0 -128
- data/spec/integration/connection_spec.rb +0 -26
- data/spec/integration/error_handling_by_consumers_spec.rb +0 -97
- data/spec/integration/exchange_bind_spec.rb +0 -35
- data/spec/integration/exchange_declare_spec.rb +0 -113
- data/spec/integration/message_metadata_access_spec.rb +0 -94
- data/spec/integration/publisher_confirmations_spec.rb +0 -51
- data/spec/integration/queue_bind_spec.rb +0 -56
- data/spec/integration/queue_declare_spec.rb +0 -44
- data/spec/integration/queue_delete_spec.rb +0 -23
- data/spec/integration/queue_purge_spec.rb +0 -38
- data/spec/integration/queue_unbind_spec.rb +0 -53
- data/spec/integration/sender_selected_distribution_spec.rb +0 -47
- data/spec/spec_helper.rb +0 -18
data/lib/ext/rabbitmq-client.jar
CHANGED
Binary file
|
data/lib/hot_bunnies/channel.rb
CHANGED
@@ -1,19 +1,162 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
module HotBunnies
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
class Channel
|
5
|
+
attr_reader :session
|
6
|
+
|
7
|
+
def initialize(session, delegate)
|
8
|
+
@connection = session
|
9
|
+
@delegate = delegate
|
10
|
+
|
11
|
+
# we keep track of consumers to gracefully shut down their
|
12
|
+
# executors when the channel is closed. This frees library users
|
13
|
+
# from having to worry about this. MK.
|
14
|
+
@consumers = ConcurrentHashMap.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def client
|
18
|
+
@connection
|
19
|
+
end
|
20
|
+
|
21
|
+
def id
|
22
|
+
@delegate.channel_number
|
23
|
+
end
|
24
|
+
|
25
|
+
def number
|
26
|
+
@delegate.channel_number
|
27
|
+
end
|
28
|
+
|
29
|
+
def channel_number
|
30
|
+
@delegate.channel_number
|
31
|
+
end
|
32
|
+
|
33
|
+
def close(code = 200, reason = "Goodbye")
|
34
|
+
v = @delegate.close(code, reason)
|
35
|
+
|
36
|
+
@consumers.each do |tag, consumer|
|
37
|
+
consumer.gracefully_shut_down
|
38
|
+
end
|
39
|
+
|
40
|
+
@connection.unregister_channel(self)
|
41
|
+
|
42
|
+
v
|
7
43
|
end
|
8
44
|
|
45
|
+
|
46
|
+
# @group Exchanges
|
47
|
+
|
9
48
|
def exchange(name, options={})
|
10
|
-
|
11
|
-
|
12
|
-
|
49
|
+
Exchange.new(self, name, options).tap do |x|
|
50
|
+
x.declare!
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def fanout(name, opts = {})
|
55
|
+
Exchange.new(self, name, opts.merge(:type => "fanout")).tap do |x|
|
56
|
+
x.declare!
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def direct(name, opts = {})
|
61
|
+
Exchange.new(self, name, opts.merge(:type => "direct")).tap do |x|
|
62
|
+
x.declare!
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def topic(name, opts = {})
|
67
|
+
Exchange.new(self, name, opts.merge(:type => "topic")).tap do |x|
|
68
|
+
x.declare!
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def headers(name, opts = {})
|
73
|
+
Exchange.new(self, name, opts.merge(:type => "headers")).tap do |x|
|
74
|
+
x.declare!
|
75
|
+
end
|
13
76
|
end
|
14
77
|
|
15
78
|
def default_exchange
|
16
|
-
self.exchange("", :durable => true, :auto_delete => false, :type => "direct")
|
79
|
+
@default_exchange ||= self.exchange("", :durable => true, :auto_delete => false, :type => "direct")
|
80
|
+
end
|
81
|
+
|
82
|
+
def exchange_declare(name, type, durable = false, auto_delete = false, arguments = nil)
|
83
|
+
@delegate.exchange_declare(name, type, durable, auto_delete, arguments)
|
84
|
+
end
|
85
|
+
|
86
|
+
# @endgroup
|
87
|
+
|
88
|
+
|
89
|
+
# @group Queues
|
90
|
+
|
91
|
+
def queue(name, options={})
|
92
|
+
Queue.new(self, name, options).tap do |q|
|
93
|
+
q.declare!
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def queue_declare(name, durable, exclusive, auto_delete, arguments = {})
|
98
|
+
converting_rjc_exceptions_to_ruby do
|
99
|
+
@delegate.queue_declare(name, durable, exclusive, auto_delete, arguments)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def queue_declare_passive(name)
|
104
|
+
converting_rjc_exceptions_to_ruby do
|
105
|
+
@delegate.queue_declare_passive(name)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def queue_delete(name, if_empty = false, if_unused = false)
|
110
|
+
converting_rjc_exceptions_to_ruby do
|
111
|
+
@delegate.queue_delete(name, if_empty, if_unused)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def queue_bind(queue, exchange, routing_key, arguments = nil)
|
116
|
+
converting_rjc_exceptions_to_ruby do
|
117
|
+
@delegate.queue_bind(queue, exchange, routing_key, arguments)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def queue_unbind(queue, exchange, routing_key, arguments = nil)
|
122
|
+
converting_rjc_exceptions_to_ruby do
|
123
|
+
@delegate.queue_unbind(queue, exchange, routing_key, arguments)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def queue_purge(name)
|
128
|
+
converting_rjc_exceptions_to_ruby do
|
129
|
+
@delegate.queue_purge(name)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
# @endgroup
|
134
|
+
|
135
|
+
|
136
|
+
# @group basic.*
|
137
|
+
|
138
|
+
def basic_publish(exchange, routing_key, mandatory, properties, body)
|
139
|
+
converting_rjc_exceptions_to_ruby do
|
140
|
+
@delegate.basic_publish(exchange, routing_key, mandatory, false, BasicPropertiesBuilder.build_properties_from(properties || Hash.new), body)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def basic_get(queue, auto_ack)
|
145
|
+
converting_rjc_exceptions_to_ruby do
|
146
|
+
@delegate.basic_get(queue, auto_ack)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def basic_consume(queue, auto_ack, consumer)
|
151
|
+
converting_rjc_exceptions_to_ruby do
|
152
|
+
@delegate.basic_consume(queue, auto_ack, consumer)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def basic_qos(prefetch_count)
|
157
|
+
converting_rjc_exceptions_to_ruby do
|
158
|
+
@delegate.basic_qos(prefetch_count)
|
159
|
+
end
|
17
160
|
end
|
18
161
|
|
19
162
|
def qos(options={})
|
@@ -24,11 +167,146 @@ module HotBunnies
|
|
24
167
|
end
|
25
168
|
|
26
169
|
def prefetch=(n)
|
27
|
-
|
170
|
+
basic_qos(n)
|
171
|
+
end
|
172
|
+
|
173
|
+
def ack(delivery_tag, multiple = false)
|
174
|
+
converting_rjc_exceptions_to_ruby do
|
175
|
+
basic_ack(delivery_tag, multiple)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
alias acknowledge ack
|
179
|
+
|
180
|
+
def reject(delivery_tag, requeue = false)
|
181
|
+
converting_rjc_exceptions_to_ruby do
|
182
|
+
basic_reject(delivery_tag, requeue)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def nack(delivery_tag, multiple = false, requeue = false)
|
187
|
+
converting_rjc_exceptions_to_ruby do
|
188
|
+
basic_nack(delivery_tag, multiple, requeue)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def basic_recover(requeue = true)
|
193
|
+
converting_rjc_exceptions_to_ruby do
|
194
|
+
@delegate.basic_recover(requeue)
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
def basic_recover_async(requeue = true)
|
199
|
+
converting_rjc_exceptions_to_ruby do
|
200
|
+
@delegate.basic_recover_async(requeue)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
# @endgroup
|
205
|
+
|
206
|
+
|
207
|
+
def confirm_select
|
208
|
+
converting_rjc_exceptions_to_ruby do
|
209
|
+
@delegate.confirm_select
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
# Waits until all outstanding publisher confirms arrive.
|
214
|
+
#
|
215
|
+
# Takes an optional timeout in milliseconds. Will raise
|
216
|
+
# an exception in timeout has occured.
|
217
|
+
#
|
218
|
+
# @param [Integer] timeout Timeout in milliseconds
|
219
|
+
# @return [Boolean] true if all confirms were positive,
|
220
|
+
# false if some were negative
|
221
|
+
def wait_for_confirms(timeout = nil)
|
222
|
+
if timeout
|
223
|
+
converting_rjc_exceptions_to_ruby do
|
224
|
+
@delegate.wait_for_confirms(timeout)
|
225
|
+
end
|
226
|
+
else
|
227
|
+
@delegate.wait_for_confirms
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
def next_publisher_seq_no
|
232
|
+
@delegate.next_publisher_seq_no
|
28
233
|
end
|
29
234
|
|
235
|
+
def tx_select
|
236
|
+
converting_rjc_exceptions_to_ruby do
|
237
|
+
@delegate.tx_select
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
def tx_commit
|
242
|
+
converting_rjc_exceptions_to_ruby do
|
243
|
+
@delegate.tx_commit
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
def tx_rollback
|
248
|
+
converting_rjc_exceptions_to_ruby do
|
249
|
+
@delegate.tx_rollback
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
def channel_flow(active)
|
254
|
+
converting_rjc_exceptions_to_ruby do
|
255
|
+
@delegate.channel_flow(active)
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
|
30
260
|
def on_return(&block)
|
31
|
-
self.
|
261
|
+
self.add_return_listener(BlockReturnListener.from(block))
|
262
|
+
end
|
263
|
+
|
264
|
+
def method_missing(selector, *args)
|
265
|
+
@delegate.__send__(selector, *args)
|
266
|
+
end
|
267
|
+
|
268
|
+
|
269
|
+
#
|
270
|
+
# Implementation
|
271
|
+
#
|
272
|
+
|
273
|
+
class BlockReturnListener
|
274
|
+
include com.rabbitmq.client.ReturnListener
|
275
|
+
|
276
|
+
def self.from(block)
|
277
|
+
new(block)
|
278
|
+
end
|
279
|
+
|
280
|
+
def initialize(block)
|
281
|
+
@block = block
|
282
|
+
end
|
283
|
+
|
284
|
+
def handleReturn(reply_code, reply_text, exchange, routing_key, basic_properties, payload)
|
285
|
+
# TODO: convert properties to a Ruby hash
|
286
|
+
@block.call(reply_code, reply_text, exchange, routing_key, basic_properties, String.from_java_bytes(payload))
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
# @private
|
291
|
+
def register_consumer(consumer_tag, consumer)
|
292
|
+
@consumers[consumer_tag] = consumer
|
293
|
+
end
|
294
|
+
|
295
|
+
# @private
|
296
|
+
def unregister_consumer(consumer_tag)
|
297
|
+
@consumers.delete(consumer_tag)
|
298
|
+
end
|
299
|
+
|
300
|
+
# Executes a block, catching Java exceptions RabbitMQ Java client throws and
|
301
|
+
# transforms them to Ruby exceptions that are then re-raised.
|
302
|
+
#
|
303
|
+
# @private
|
304
|
+
def converting_rjc_exceptions_to_ruby(&block)
|
305
|
+
begin
|
306
|
+
block.call
|
307
|
+
rescue Exception, java.lang.Throwable => e
|
308
|
+
Exceptions.convert_and_reraise(e)
|
309
|
+
end
|
32
310
|
end
|
33
311
|
end
|
34
312
|
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
module HotBunnies
|
2
|
+
import com.rabbitmq.client.DefaultConsumer
|
3
|
+
|
4
|
+
class BaseConsumer < DefaultConsumer
|
5
|
+
attr_accessor :consumer_tag
|
6
|
+
|
7
|
+
def initialize(channel)
|
8
|
+
super(channel)
|
9
|
+
@channel = channel
|
10
|
+
|
11
|
+
@cancelling = JavaConcurrent::AtomicBoolean.new
|
12
|
+
@cancelled = JavaConcurrent::AtomicBoolean.new
|
13
|
+
end
|
14
|
+
|
15
|
+
def handleDelivery(consumer_tag, envelope, properties, body)
|
16
|
+
body = String.from_java_bytes(body)
|
17
|
+
headers = Headers.new(channel, consumer_tag, envelope, properties)
|
18
|
+
|
19
|
+
deliver(headers, body)
|
20
|
+
end
|
21
|
+
|
22
|
+
def handleCancel(consumer_tag)
|
23
|
+
@cancelled.set(true)
|
24
|
+
end
|
25
|
+
|
26
|
+
def handleCancelOk(consumer_tag)
|
27
|
+
@cancelled.set(true)
|
28
|
+
@channel.unregister_consumer(consumer_tag)
|
29
|
+
end
|
30
|
+
|
31
|
+
def start
|
32
|
+
end
|
33
|
+
|
34
|
+
def deliver(headers, message)
|
35
|
+
raise NotImplementedError, 'To be implemented by a subclass'
|
36
|
+
end
|
37
|
+
|
38
|
+
def cancel
|
39
|
+
@cancelling.set(true)
|
40
|
+
response = channel.basic_cancel(consumer_tag)
|
41
|
+
@cancelled.set(true)
|
42
|
+
|
43
|
+
response
|
44
|
+
end
|
45
|
+
|
46
|
+
def cancelled?
|
47
|
+
@cancelling.get || @cancelled.get
|
48
|
+
end
|
49
|
+
|
50
|
+
def active?
|
51
|
+
!cancelled?
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
class CallbackConsumer < BaseConsumer
|
57
|
+
def initialize(channel, callback)
|
58
|
+
super(channel)
|
59
|
+
@callback = callback
|
60
|
+
@callback_arity = @callback.arity
|
61
|
+
end
|
62
|
+
|
63
|
+
def callback(headers, message)
|
64
|
+
if @callback_arity == 2
|
65
|
+
@callback.call(headers, message)
|
66
|
+
else
|
67
|
+
@callback.call(message)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
class AsyncCallbackConsumer < CallbackConsumer
|
73
|
+
def initialize(channel, callback, executor)
|
74
|
+
super(channel, callback)
|
75
|
+
@executor = executor
|
76
|
+
end
|
77
|
+
|
78
|
+
def deliver(headers, message)
|
79
|
+
unless @executor.shutdown?
|
80
|
+
@executor.submit do
|
81
|
+
begin
|
82
|
+
callback(headers, message)
|
83
|
+
rescue Exception => e
|
84
|
+
$stderr.puts "Unhandled exception in consumer #{@consumer_tag}: #{e.message}"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def cancel
|
91
|
+
super
|
92
|
+
|
93
|
+
maybe_shut_down_executor
|
94
|
+
end
|
95
|
+
|
96
|
+
def shutdown!
|
97
|
+
@executor.shutdown_now if @executor
|
98
|
+
end
|
99
|
+
alias shut_down! shutdown!
|
100
|
+
|
101
|
+
def gracefully_shut_down
|
102
|
+
unless @executor.await_termination(1, JavaConcurrent::TimeUnit::SECONDS)
|
103
|
+
@executor.shutdown_now
|
104
|
+
end
|
105
|
+
end
|
106
|
+
alias maybe_shut_down_executor gracefully_shut_down
|
107
|
+
alias gracefully_shutdown gracefully_shut_down
|
108
|
+
end
|
109
|
+
|
110
|
+
class BlockingCallbackConsumer < CallbackConsumer
|
111
|
+
include JavaConcurrent
|
112
|
+
|
113
|
+
def initialize(channel, buffer_size, callback)
|
114
|
+
super(channel, callback)
|
115
|
+
if buffer_size
|
116
|
+
@internal_queue = ArrayBlockingQueue.new(buffer_size)
|
117
|
+
else
|
118
|
+
@internal_queue = LinkedBlockingQueue.new
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def start
|
123
|
+
interrupted = false
|
124
|
+
until (@cancelling.get || @cancelled.get) || JavaConcurrent::Thread.current_thread.interrupted?
|
125
|
+
begin
|
126
|
+
pair = @internal_queue.take
|
127
|
+
callback(*pair) if pair
|
128
|
+
rescue InterruptedException => e
|
129
|
+
interrupted = true
|
130
|
+
end
|
131
|
+
end
|
132
|
+
while (pair = @internal_queue.poll)
|
133
|
+
callback(*pair)
|
134
|
+
end
|
135
|
+
if interrupted
|
136
|
+
JavaConcurrent::Thread.current_thread.interrupt
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def deliver(*pair)
|
141
|
+
if (@cancelling.get || @cancelled.get) || JavaConcurrent::Thread.current_thread.interrupted?
|
142
|
+
@internal_queue.offer(pair)
|
143
|
+
else
|
144
|
+
begin
|
145
|
+
@internal_queue.put(pair)
|
146
|
+
rescue InterruptedException => e
|
147
|
+
JavaConcurrent::Thread.current_thread.interrupt
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
@@ -0,0 +1,151 @@
|
|
1
|
+
module HotBunnies
|
2
|
+
class Exception < ::StandardError
|
3
|
+
end
|
4
|
+
|
5
|
+
|
6
|
+
class ChannelLevelException < Exception
|
7
|
+
attr_reader :channel_close
|
8
|
+
|
9
|
+
def initialize(message, channel_close)
|
10
|
+
super(message)
|
11
|
+
|
12
|
+
@channel_close = channel_close
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class ConnectionLevelException < Exception
|
17
|
+
attr_reader :connection_close
|
18
|
+
|
19
|
+
def initialize(message, connection_close)
|
20
|
+
super(message)
|
21
|
+
|
22
|
+
@connection_close = connection_close
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
class PossibleAuthenticationFailureError < Exception
|
28
|
+
|
29
|
+
#
|
30
|
+
# API
|
31
|
+
#
|
32
|
+
|
33
|
+
attr_reader :username, :vhost
|
34
|
+
|
35
|
+
def initialize(username, vhost, password_length)
|
36
|
+
@username = username
|
37
|
+
@vhost = vhost
|
38
|
+
|
39
|
+
super("RabbitMQ closed TCP connection before authentication succeeded: this usually means authentication failure due to misconfiguration or that RabbitMQ version does not support AMQP 0.9.1. Please check your configuration. Username: #{username}, vhost: #{vhost}, password length: #{password_length}")
|
40
|
+
end # initialize(settings)
|
41
|
+
end # PossibleAuthenticationFailureError
|
42
|
+
|
43
|
+
|
44
|
+
class PreconditionFailed < ChannelLevelException
|
45
|
+
end
|
46
|
+
|
47
|
+
class NotFound < ChannelLevelException
|
48
|
+
end
|
49
|
+
|
50
|
+
class ResourceLocked < ChannelLevelException
|
51
|
+
end
|
52
|
+
|
53
|
+
class AccessRefused < ChannelLevelException
|
54
|
+
end
|
55
|
+
|
56
|
+
class ChannelError < ConnectionLevelException
|
57
|
+
end
|
58
|
+
|
59
|
+
class InvalidCommand < ConnectionLevelException
|
60
|
+
end
|
61
|
+
|
62
|
+
class FrameError < ConnectionLevelException
|
63
|
+
end
|
64
|
+
|
65
|
+
class UnexpectedFrame < ConnectionLevelException
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
|
70
|
+
# Converts RabbitMQ Java client exceptions
|
71
|
+
# @private
|
72
|
+
class Exceptions
|
73
|
+
def self.convert(e, unwrap_io_exception = true)
|
74
|
+
case e
|
75
|
+
when java.io.IOException then
|
76
|
+
c = e.cause
|
77
|
+
|
78
|
+
if unwrap_io_exception
|
79
|
+
convert(c, false)
|
80
|
+
else
|
81
|
+
c
|
82
|
+
end
|
83
|
+
when com.rabbitmq.client.AlreadyClosedException then
|
84
|
+
cmd = e.reason
|
85
|
+
|
86
|
+
puts cmd.method.class.inspect
|
87
|
+
when com.rabbitmq.client.ShutdownSignalException then
|
88
|
+
cmd = e.reason
|
89
|
+
|
90
|
+
exception_for_protocol_method(cmd.method)
|
91
|
+
else
|
92
|
+
e
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def self.convert_and_reraise(e)
|
97
|
+
raise convert(e)
|
98
|
+
end
|
99
|
+
|
100
|
+
def self.exception_for_protocol_method(m)
|
101
|
+
case m
|
102
|
+
# com.rabbitmq.client.AMQP.Connection.Close does not resolve the inner
|
103
|
+
# class correctly. Looks like a JRuby bug we work around by using Rubyesque
|
104
|
+
# class name. MK.
|
105
|
+
when Java::ComRabbitmqClient::AMQP::Connection::Close then
|
106
|
+
exception_for_connection_close(m)
|
107
|
+
when Java::ComRabbitmqClient::AMQP::Channel::Close then
|
108
|
+
exception_for_channel_close(m)
|
109
|
+
else
|
110
|
+
NotImplementedError.new("Exception convertion for protocol method #{m.inspect} is not implemented!")
|
111
|
+
end
|
112
|
+
end # def self
|
113
|
+
|
114
|
+
|
115
|
+
def self.exception_for_connection_close(m)
|
116
|
+
klass = case m.reply_code
|
117
|
+
when 320 then
|
118
|
+
ConnectionForced
|
119
|
+
when 501 then
|
120
|
+
FrameError
|
121
|
+
when 503 then
|
122
|
+
InvalidCommand
|
123
|
+
when 504 then
|
124
|
+
ChannelError
|
125
|
+
when 505 then
|
126
|
+
UnexpectedFrame
|
127
|
+
else
|
128
|
+
raise "Unknown reply code: #{m.reply_code}, text: #{m.reply_text}"
|
129
|
+
end
|
130
|
+
|
131
|
+
klass.new("Connection-level error: #{m.reply_text}", m)
|
132
|
+
end
|
133
|
+
|
134
|
+
def self.exception_for_channel_close(m)
|
135
|
+
klass = case m.reply_code
|
136
|
+
when 403 then
|
137
|
+
AccessRefused
|
138
|
+
when 404 then
|
139
|
+
NotFound
|
140
|
+
when 405 then
|
141
|
+
ResourceLocked
|
142
|
+
when 406 then
|
143
|
+
PreconditionFailed
|
144
|
+
else
|
145
|
+
ChannelLevelException
|
146
|
+
end
|
147
|
+
|
148
|
+
klass.new(m.reply_text, m)
|
149
|
+
end
|
150
|
+
end # Exceptions
|
151
|
+
end # HotBunnies
|
data/lib/hot_bunnies/exchange.rb
CHANGED
@@ -1,18 +1,29 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
module HotBunnies
|
4
|
+
import com.rabbitmq.client.AMQP
|
5
|
+
|
4
6
|
class Exchange
|
5
7
|
attr_reader :name, :channel
|
6
8
|
|
7
|
-
def initialize(channel, name, options={})
|
9
|
+
def initialize(channel, name, options = {})
|
10
|
+
raise ArgumentError, "exchange channel cannot be nil" if channel.nil?
|
11
|
+
raise ArgumentError, "exchange name cannot be nil" if name.nil?
|
12
|
+
raise ArgumentError, "exchange :type must be specified as an option" if options[:type].nil?
|
13
|
+
|
8
14
|
@channel = channel
|
9
|
-
@name
|
15
|
+
@name = name
|
16
|
+
@type = options[:type]
|
10
17
|
@options = {:type => :fanout, :durable => false, :auto_delete => false, :internal => false, :passive => false}.merge(options)
|
11
18
|
end
|
12
19
|
|
13
|
-
def publish(body,
|
14
|
-
options = {:routing_key => '', :mandatory => false
|
15
|
-
@channel.basic_publish(@name,
|
20
|
+
def publish(body, opts = {})
|
21
|
+
options = {:routing_key => '', :mandatory => false}.merge(opts)
|
22
|
+
@channel.basic_publish(@name,
|
23
|
+
options[:routing_key],
|
24
|
+
options[:mandatory],
|
25
|
+
options.fetch(:properties, Hash.new),
|
26
|
+
body.to_java_bytes)
|
16
27
|
end
|
17
28
|
|
18
29
|
def delete(options={})
|
@@ -28,37 +39,18 @@ module HotBunnies
|
|
28
39
|
@name.empty? || @name.start_with?("amq.")
|
29
40
|
end
|
30
41
|
|
42
|
+
#
|
43
|
+
# Implementation
|
44
|
+
#
|
45
|
+
|
46
|
+
# @api private
|
31
47
|
def declare!
|
32
48
|
unless predefined?
|
33
49
|
if @options[:passive]
|
34
50
|
then @channel.exchange_declare_passive(@name)
|
35
|
-
else @channel.exchange_declare(@name, @options[:type].to_s, @options[:durable], @options[:auto_delete], @options[:
|
51
|
+
else @channel.exchange_declare(@name, @options[:type].to_s, @options[:durable], @options[:auto_delete], @options[:arguments])
|
36
52
|
end
|
37
53
|
end
|
38
54
|
end
|
39
|
-
|
40
|
-
|
41
|
-
protected
|
42
|
-
|
43
|
-
def build_properties_from(props = {})
|
44
|
-
builder = AMQP::BasicProperties::Builder.new
|
45
|
-
|
46
|
-
builder.content_type(props[:content_type]).
|
47
|
-
content_encoding(props[:content_encoding]).
|
48
|
-
headers(props[:headers]).
|
49
|
-
delivery_mode(props[:persistent] ? 2 : 1).
|
50
|
-
priority(props[:priority]).
|
51
|
-
correlation_id(props[:correlation_id]).
|
52
|
-
reply_to(props[:reply_to]).
|
53
|
-
expiration(props[:expiration]).
|
54
|
-
message_id(props[:message_id]).
|
55
|
-
timestamp(props[:timestamp]).
|
56
|
-
type(props[:type]).
|
57
|
-
user_id(props[:user_id]).
|
58
|
-
app_id(props[:app_id]).
|
59
|
-
cluster_id(props[:cluster_id]).
|
60
|
-
build
|
61
|
-
end
|
62
|
-
|
63
55
|
end
|
64
56
|
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module JavaConcurrent
|
2
|
+
java_import 'java.lang.Thread'
|
3
|
+
java_import 'java.lang.InterruptedException'
|
4
|
+
java_import 'java.util.concurrent.Executors'
|
5
|
+
java_import 'java.util.concurrent.LinkedBlockingQueue'
|
6
|
+
java_import 'java.util.concurrent.ArrayBlockingQueue'
|
7
|
+
java_import 'java.util.concurrent.TimeUnit'
|
8
|
+
java_import 'java.util.concurrent.atomic.AtomicBoolean'
|
9
|
+
end
|