stomp 1.2.10 → 1.2.11

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/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