stomp 1.2.10 → 1.2.11

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.rdoc CHANGED
@@ -1,3 +1,10 @@
1
+ == 1.2.11 20130728
2
+
3
+ * Issue #60, timeout/hang under JRuby
4
+ * More generally support JRuby use and testing
5
+ * Issue #58, nil message in Client on AMQ shutdown
6
+ * More robust RabbitMQ tests
7
+
1
8
  == 1.2.10 20130708
2
9
 
3
10
  * Issue #57, reconnect delays not honored if erroneous headers
data/README.rdoc CHANGED
@@ -12,6 +12,7 @@ An implementation of the Stomp protocol for Ruby. See:
12
12
 
13
13
  See _CHANGELOG.rdoc_ for details.
14
14
 
15
+ * Gem version 1.2.11. JRuby and AMQ support fixes.
15
16
  * Gem version 1.2.10. Support failover from heartbeat threads.
16
17
  * Gem version 1.2.9. Miscellaneous fixes and changes.
17
18
  * Gem version 1.2.8. Stomp 1.1+ header codec inversion fix, test refactoring.
data/lib/client/utils.rb CHANGED
@@ -157,15 +157,18 @@ module Stomp
157
157
  @listener_thread = Thread.start do
158
158
  while true
159
159
  message = @connection.receive
160
- if message # AMQ specific?, nil message on multiple reconnects
161
- if message.command == Stomp::CMD_MESSAGE
162
- if listener = find_listener(message)
163
- listener.call(message)
164
- end
165
- elsif message.command == Stomp::CMD_RECEIPT
166
- if listener = @receipt_listeners[message.headers['receipt-id']]
167
- listener.call(message)
168
- end
160
+ # AMQ specific behavior
161
+ if message.nil? && (!@reliable)
162
+ raise Stomp::Error::NilMessageError
163
+ end
164
+ # OK, we have some real data
165
+ if message.command == Stomp::CMD_MESSAGE
166
+ if listener = find_listener(message)
167
+ listener.call(message)
168
+ end
169
+ elsif message.command == Stomp::CMD_RECEIPT
170
+ if listener = @receipt_listeners[message.headers['receipt-id']]
171
+ listener.call(message)
169
172
  end
170
173
  end
171
174
  end # while true
@@ -152,7 +152,7 @@ module Stomp
152
152
  while true do
153
153
  sleep sleeptime
154
154
  next unless @socket # nil under some circumstances ??
155
- rdrdy = @socket.ready? ? true : false
155
+ rdrdy = _is_ready?(@socket)
156
156
  curt = Time.now.to_f
157
157
  if @logger && @logger.respond_to?(:on_hbfire)
158
158
  @logger.on_hbfire(log_params, "receive_fire", curt)
@@ -171,7 +171,7 @@ module Stomp
171
171
  lock = @read_semaphore.try_lock
172
172
  if lock
173
173
  lock_fail_count = 0 # clear
174
- rdrdy = @socket.ready? ? true : false # This logic will be bad for JRuby I think
174
+ rdrdy = _is_ready?(@socket)
175
175
  if rdrdy
176
176
  read_fail_count = 0 # clear
177
177
  last_char = @socket.getc
@@ -16,7 +16,16 @@ module Stomp
16
16
  @read_semaphore.synchronize do
17
17
  line = ''
18
18
  if @protocol == Stomp::SPL_10 || (@protocol >= Stomp::SPL_11 && !@hbr)
19
- line = read_socket.gets # The old way
19
+ if @jruby
20
+ # Handle JRuby specific behavior.
21
+ while true
22
+ line = read_socket.gets # Data from wire
23
+ break unless line == "\n"
24
+ line = ''
25
+ end
26
+ else
27
+ line = read_socket.gets # The old way
28
+ end
20
29
  else # We are >= 1.1 *AND* receiving heartbeats.
21
30
  while true
22
31
  line = read_socket.gets # Data from wire
@@ -28,7 +37,6 @@ module Stomp
28
37
  return nil if line.nil?
29
38
  # p [ "wiredatain_01", line ]
30
39
  line = _normalize_line_end(line) if @protocol >= Stomp::SPL_12
31
-
32
40
  # If the reading hangs for more than X seconds, abort the parsing process.
33
41
  # X defaults to 5. Override allowed in connection hash parameters.
34
42
  Timeout::timeout(@parse_timeout, Stomp::Error::PacketParsingTimeout) do
@@ -58,15 +66,16 @@ module Stomp
58
66
 
59
67
  # If the buffer isn't empty, reads trailing new lines.
60
68
  #
61
- # Note: experiments with JRuby seem to show that .ready? never
62
- # returns true. This means that this code to drain trailing new
63
- # lines never runs using JRuby.
69
+ # Note: experiments with JRuby seem to show that socket.ready? never
70
+ # returns true. It appears that in cases where Ruby returns true
71
+ # that JRuby returns a Fixnum. We attempt to adjust for this
72
+ # in the _is_ready? method.
64
73
  #
65
74
  # Note 2: the draining of new lines must be done _after_ a message
66
75
  # is read. Do _not_ leave them on the wire and attempt to drain them
67
76
  # at the start of the next read. Attempting to do that breaks the
68
77
  # asynchronous nature of the 'poll' method.
69
- while read_socket.ready?
78
+ while _is_ready?(read_socket)
70
79
  last_char = read_socket.getc
71
80
  break unless last_char
72
81
  if parse_char(last_char) != "\n"
@@ -74,9 +83,6 @@ module Stomp
74
83
  break
75
84
  end
76
85
  end
77
- # And so, a JRuby hack. Remove any new lines at the start of the
78
- # next buffer.
79
- message_header.gsub!(/^\n?/, "")
80
86
 
81
87
  if @protocol >= Stomp::SPL_11
82
88
  @lr = Time.now.to_f if @hbr
@@ -92,6 +98,15 @@ module Stomp
92
98
  end
93
99
  end
94
100
 
101
+ # Check if the socket is ready, i.e. there is data to read.
102
+ def _is_ready?(s)
103
+ rdy = s.ready?
104
+ if @jruby
105
+ rdy = rdy.class == Fixnum ? true : false
106
+ end
107
+ rdy
108
+ end
109
+
95
110
  # Normalize line ends because 1.2+ brokers can send 'mixed mode' headers, i.e.:
96
111
  # - Some headers end with '\n'
97
112
  # - Other headers end with '\r\n'
data/lib/stomp/client.rb CHANGED
@@ -233,6 +233,11 @@ module Stomp
233
233
  @connection.closed?()
234
234
  end
235
235
 
236
+ # jruby? tests if the connection has detcted a JRuby environment
237
+ def jruby?()
238
+ @connection.jruby
239
+ end
240
+
236
241
  # close frees resources in use by this client. The listener thread is
237
242
  # terminated, and disconnect on the connection is called.
238
243
  def close(headers={})
@@ -31,6 +31,9 @@ module Stomp
31
31
  # Heartbeat send has been successful.
32
32
  attr_reader :hb_sent # Heartbeat sent successfully
33
33
 
34
+ # JRuby detected
35
+ attr_reader :jruby
36
+
34
37
  # Autoflush forces a flush on each transmit. This may be changed
35
38
  # dynamically by calling code.
36
39
  attr_accessor :autoflush
@@ -87,7 +90,10 @@ module Stomp
87
90
  @hb_received = true # Assumed at first
88
91
  @hb_sent = true # Assumed at first
89
92
  @hbs = @hbr = false # Sending/Receiving heartbeats. Assume no for now.
90
-
93
+ @jruby = false # Assumed at first
94
+ if defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /jruby/
95
+ @jruby = true
96
+ end
91
97
  if login.is_a?(Hash)
92
98
  hashed_initialize(login)
93
99
  else
data/lib/stomp/errors.rb CHANGED
@@ -196,6 +196,15 @@ module Stomp
196
196
  class LoggerConnectionError < RuntimeError
197
197
  end
198
198
 
199
+ # NilMessageError is raised if:
200
+ # * Invalid (nil) data is received from the Stomp server in a client's
201
+ # listener thread, and the connection is not reliable.
202
+ class NilMessageError < RuntimeError
203
+ def message
204
+ "Received message is nil, and connection not reliable"
205
+ end
206
+ end
207
+
199
208
  end # module Error
200
209
 
201
210
  end # module Stomp
data/lib/stomp/version.rb CHANGED
@@ -6,7 +6,7 @@ module Stomp
6
6
  module Version #:nodoc: all
7
7
  MAJOR = 1
8
8
  MINOR = 2
9
- PATCH = 10
9
+ PATCH = 11
10
10
  STRING = "#{MAJOR}.#{MINOR}.#{PATCH}"
11
11
  end
12
12
  end
data/stomp.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{stomp}
8
- s.version = "1.2.10"
8
+ s.version = "1.2.11"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Brian McCallister", "Marius Mathiesen", "Thiago Morello", "Guy M. Allard"]
12
- s.date = %q{2013-07-08}
12
+ s.date = %q{2013-07-28}
13
13
  s.description = %q{Ruby client for the Stomp messaging protocol. Note that this gem is no longer supported on rubyforge.}
14
14
  s.email = ["brianm@apache.org", "marius@stones.com", "morellon@gmail.com", "allard.guy.m@gmail.com"]
15
15
  s.executables = ["catstomp", "stompcat"]
data/test/test_client.rb CHANGED
@@ -23,7 +23,7 @@ class TestClient < Test::Unit::TestCase
23
23
  end
24
24
 
25
25
  def teardown
26
- @client.close if @client.open? # allow tests to close
26
+ @client.close if @client && @client.open? # allow tests to close
27
27
  end
28
28
 
29
29
  # Test poll works.
@@ -50,7 +50,7 @@ class TestClient < Test::Unit::TestCase
50
50
  sleep 0.01 until receipt
51
51
  assert_not_nil receipt.headers['receipt-id']
52
52
  checkEmsg(@client)
53
- end unless ENV['STOMP_RABBIT'] # TODO: why does Rabbit 1.1 fail ?
53
+ end
54
54
 
55
55
  # Test Client subscribe
56
56
  def test_asynch_subscribe
@@ -160,61 +160,133 @@ class TestClient < Test::Unit::TestCase
160
160
  end unless RUBY_ENGINE =~ /jruby/
161
161
 
162
162
  # Test transaction publish and abort, receive with new client.
163
- def test_transaction_ack_rollback_with_new_client
164
- @client.publish make_destination, message_text
163
+ # New client uses ack => client.
164
+ def test_tran_ack_abrt_newcli_cli
165
+ @client.close if @client && @client.open? # allow tests to close
166
+ @client = get_client()
167
+ q = make_destination
168
+ data = message_text
169
+ @client.publish q, data
165
170
 
166
171
  @client.begin 'tx1'
167
172
  message = nil
168
173
  sid = nil
169
174
  if @client.protocol() == Stomp::SPL_10
170
- @client.subscribe(make_destination, :ack => 'client') {|m| message = m}
171
- else
175
+ @client.subscribe(q, :ack => 'client') {|m| message = m}
176
+ else # 1.1 and 1.2 are the same for this
172
177
  sid = @client.uuid()
173
- @client.subscribe(make_destination, :ack => 'client', :id => sid) {|m| message = m}
178
+ @client.subscribe(q, :ack => 'client', :id => sid) {|m| message = m}
174
179
  end
175
180
  sleep 0.01 until message
176
- assert_equal message_text, message.body
181
+ assert_equal data, message.body
177
182
  assert_nothing_raised {
178
- if @client.protocol() == Stomp::SPL_10
179
- @client.acknowledge message, :transaction => 'tx1'
180
- else
181
- @client.acknowledge message, :transaction => 'tx1', :subscription => sid
183
+ case @client.protocol()
184
+ when Stomp::SPL_10
185
+ @client.acknowledge message, :transaction => 'tx1'
186
+ checkEmsg(@client)
187
+ when Stomp::SPL_11
188
+ @client.acknowledge message, :transaction => 'tx1', :subscription => message.headers['subscription']
189
+ checkEmsg(@client)
190
+ else # 1.2+
191
+ @client.acknowledge message, :transaction => 'tx1', :id => message.headers['ack']
192
+ checkEmsg(@client)
182
193
  end
183
- message = nil
184
- @client.abort 'tx1'
194
+ message = nil # reset
195
+ @client.abort 'tx1' # now abort
185
196
  }
186
197
  checkEmsg(@client)
187
198
  # lets recreate the connection
188
- teardown
189
- setup
199
+ @client.close
200
+ @client = get_client()
190
201
  sid = nil
202
+ message2 = nil
203
+ @client.begin 'tx2'
191
204
  assert_nothing_raised {
192
205
  if @client.protocol() == Stomp::SPL_10
193
- @client.subscribe(make_destination, :ack => 'client') {|m| message = m}
194
- else
206
+ @client.subscribe(q, :ack => 'client') {|m| message2 = m}
207
+ else # 1.1 and 1.2 are the same for this
195
208
  sid = @client.uuid()
196
- @client.subscribe(make_destination, :ack => 'client', :id => sid) {|m| message = m}
209
+ @client.subscribe(q, :ack => 'client', :id => sid) {|m| message2 = m}
197
210
  end
198
211
  }
199
- Timeout::timeout(4) do
200
- sleep 0.01 until message
201
- end
212
+ sleep 0.01 until message2
202
213
  assert_not_nil message
203
- assert_equal message_text, message.body
214
+ assert_equal data, message2.body
204
215
  assert_nothing_raised {
205
- @client.begin 'tx2'
206
216
  case @client.protocol()
207
217
  when Stomp::SPL_10
208
- @client.acknowledge message, :transaction => 'tx2'
218
+ @client.acknowledge message2, :transaction => 'tx2'
219
+ checkEmsg(@client)
209
220
  when Stomp::SPL_11
210
- @client.acknowledge message, :transaction => 'tx2', :subscription => sid
211
- else
212
- # Skip 1.2+ for now. Current 1.2 broker appears to think this is
213
- # already ACK'd.
221
+ @client.acknowledge message2, :transaction => 'tx2', :subscription => message2.headers['subscription']
222
+ checkEmsg(@client)
223
+ else # 1.2+
224
+ @client.acknowledge message2, :transaction => 'tx2', :id => message2.headers['ack']
225
+ checkEmsg(@client)
214
226
  end
215
227
  @client.commit 'tx2'
216
228
  }
217
229
  checkEmsg(@client)
230
+ @client.close
231
+ end
232
+
233
+ # Test transaction publish and abort, receive with new client.
234
+ # New client uses ack => auto.
235
+ def test_tran_ack_abrt_newcli_auto
236
+ @client.close if @client && @client.open? # allow tests to close
237
+ @client = get_client()
238
+ q = make_destination
239
+ data = message_text
240
+ @client.publish q, data
241
+
242
+ @client.begin 'tx1'
243
+ message = nil
244
+ sid = nil
245
+ if @client.protocol() == Stomp::SPL_10
246
+ @client.subscribe(q, :ack => 'client') {|m| message = m}
247
+ else # 1.1 and 1.2 are the same for this
248
+ sid = @client.uuid()
249
+ @client.subscribe(q, :ack => 'client', :id => sid) {|m| message = m}
250
+ end
251
+ sleep 0.01 until message
252
+ assert_equal data, message.body
253
+ assert_nothing_raised {
254
+ case @client.protocol()
255
+ when Stomp::SPL_10
256
+ @client.acknowledge message, :transaction => 'tx1'
257
+ checkEmsg(@client)
258
+ when Stomp::SPL_11
259
+ @client.acknowledge message, :transaction => 'tx1', :subscription => message.headers['subscription']
260
+ checkEmsg(@client)
261
+ else # 1.2+
262
+ @client.acknowledge message, :transaction => 'tx1', :id => message.headers['ack']
263
+ checkEmsg(@client)
264
+ end
265
+ message = nil # reset
266
+ @client.abort 'tx1' # now abort
267
+ }
268
+ checkEmsg(@client)
269
+ # lets recreate the connection
270
+ @client.close
271
+
272
+ @client = get_client()
273
+ sid = nil
274
+ message2 = nil
275
+ @client.begin 'tx2'
276
+ assert_nothing_raised {
277
+ if @client.protocol() == Stomp::SPL_10
278
+ @client.subscribe(q, :ack => 'auto') {|m| message2 = m}
279
+ else # 1.1 and 1.2 are the same for this
280
+ sid = @client.uuid()
281
+ @client.subscribe(q, :ack => 'auto', :id => sid) {|m| message2 = m}
282
+ end
283
+ }
284
+ sleep 0.01 until message2
285
+ assert_not_nil message2
286
+ assert_equal data, message2.body
287
+ @client.commit 'tx2'
288
+ checkEmsg(@client)
289
+ @client.close
218
290
  end
219
291
 
220
292
  # Test that subscription destinations must be unique for a Client.
@@ -313,50 +385,60 @@ class TestClient < Test::Unit::TestCase
313
385
  checkEmsg(@client)
314
386
  end unless ENV['STOMP_NOWILD'] || ENV['STOMP_DOTQUEUE']
315
387
 
316
- # Test transaction with client side redilivery.
317
- def test_transaction_with_client_side_redelivery
318
- @client.publish make_destination, message_text
388
+ # Test transaction with client side reacknowledge.
389
+ def test_transaction_with_client_side_reack
390
+ @client.close if @client && @client.open? # allow tests to close
391
+ @client = get_client()
392
+ q = make_destination
393
+ data = message_text
394
+ @client.publish q, data
319
395
 
320
396
  @client.begin 'tx1'
321
397
  message = nil
322
398
  sid = nil
323
399
  if @client.protocol() == Stomp::SPL_10
324
- @client.subscribe(make_destination, :ack => 'client') { |m| message = m }
400
+ @client.subscribe(q, :ack => 'client') { |m| message = m }
325
401
  else
326
402
  sid = @client.uuid()
327
- @client.subscribe(make_destination, :ack => 'client', :id => sid) { |m| message = m }
403
+ @client.subscribe(q, :ack => 'client', :id => sid) { |m| message = m }
328
404
  end
329
-
330
405
  sleep 0.1 while message.nil?
331
-
332
- assert_equal message_text, message.body
333
- if @client.protocol() == Stomp::SPL_10
334
- @client.acknowledge message, :transaction => 'tx1'
335
- else
336
- @client.acknowledge message, :transaction => 'tx1', :subscription => sid
406
+ assert_equal data, message.body
407
+ case @client.protocol()
408
+ when Stomp::SPL_10
409
+ @client.acknowledge message, :transaction => 'tx1'
410
+ checkEmsg(@client)
411
+ when Stomp::SPL_11
412
+ @client.acknowledge message, :transaction => 'tx1', :subscription => message.headers['subscription']
413
+ checkEmsg(@client)
414
+ else # 1.2+
415
+ @client.acknowledge message, :transaction => 'tx1', :id => message.headers['ack']
416
+ checkEmsg(@client)
337
417
  end
338
418
  message = nil
339
419
  @client.abort 'tx1'
340
-
420
+ # Wait for redlivery (Client logic)
341
421
  sleep 0.1 while message.nil?
342
-
343
422
  assert_not_nil message
344
- assert_equal message_text, message.body
345
-
423
+ assert_equal data, message.body
346
424
  assert_nothing_raised {
347
425
  @client.begin 'tx2'
348
426
  case @client.protocol()
349
427
  when Stomp::SPL_10
350
428
  @client.acknowledge message, :transaction => 'tx2'
429
+ checkEmsg(@client)
351
430
  when Stomp::SPL_11
352
- @client.acknowledge message, :transaction => 'tx2', :subscription => sid
353
- else
354
- # Skip 1.2+ for now. Current 1.2 broker appears to think this is
355
- # already ACK'd.
431
+ @client.acknowledge message, :transaction => 'tx2', :subscription => message.headers['subscription']
432
+ checkEmsg(@client)
433
+ else # 1.2+
434
+ @client.acknowledge message, :transaction => 'tx2', :id => message.headers['ack']
435
+ checkEmsg(@client)
356
436
  end
357
437
  @client.commit 'tx2'
358
438
  }
359
439
  checkEmsg(@client)
440
+ @client.close
441
+ @client = nil
360
442
  end
361
443
 
362
444
  # Test that a connection frame is received.
@@ -523,6 +605,15 @@ class TestClient < Test::Unit::TestCase
523
605
  end
524
606
  end
525
607
 
608
+ # test JRuby detection
609
+ def test_jruby_presence
610
+ if defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /jruby/
611
+ assert @client.jruby?
612
+ else
613
+ assert !@client.jruby?
614
+ end
615
+ end
616
+
526
617
  private
527
618
  def message_text
528
619
  name = caller_method_name unless name
@@ -115,7 +115,7 @@ class TestConnection < Test::Unit::TestCase
115
115
  # matching the message-id for the MESSAGE being acknowledged and
116
116
  # subscription, which MUST be set to match the value of the subscription's
117
117
  # id header.
118
- @conn.ack msg.headers['message-id'], :subscription => sid
118
+ @conn.ack msg.headers['message-id'], :subscription => msg.headers['subscription']
119
119
  }
120
120
  checkEmsg(@conn)
121
121
  end
@@ -509,5 +509,14 @@ class TestConnection < Test::Unit::TestCase
509
509
  c.disconnect if c
510
510
  end
511
511
 
512
+ # test JRuby detection
513
+ def test_jruby_presence
514
+ if defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /jruby/
515
+ assert @conn.jruby
516
+ else
517
+ assert !@conn.jruby
518
+ end
519
+ end
520
+
512
521
  end
513
522
 
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stomp
3
3
  version: !ruby/object:Gem::Version
4
- hash: 11
4
+ hash: 9
5
5
  prerelease: false
6
6
  segments:
7
7
  - 1
8
8
  - 2
9
- - 10
10
- version: 1.2.10
9
+ - 11
10
+ version: 1.2.11
11
11
  platform: ruby
12
12
  authors:
13
13
  - Brian McCallister
@@ -18,7 +18,7 @@ autorequire:
18
18
  bindir: bin
19
19
  cert_chain: []
20
20
 
21
- date: 2013-07-08 00:00:00 -04:00
21
+ date: 2013-07-28 00:00:00 -04:00
22
22
  default_executable:
23
23
  dependencies:
24
24
  - !ruby/object:Gem::Dependency