stomp 1.2.4 → 1.2.5

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.
Files changed (56) hide show
  1. data/CHANGELOG.rdoc +11 -0
  2. data/README.rdoc +38 -26
  3. data/Rakefile +3 -0
  4. data/bin/catstomp +34 -34
  5. data/bin/stompcat +36 -36
  6. data/examples/client11_ex1.rb +64 -55
  7. data/examples/client11_putget1.rb +47 -35
  8. data/examples/conn11_ex1.rb +59 -51
  9. data/examples/conn11_ex2.rb +59 -50
  10. data/examples/conn11_hb1.rb +35 -26
  11. data/examples/consumer.rb +25 -12
  12. data/examples/get11conn_ex1.rb +97 -89
  13. data/examples/get11conn_ex2.rb +55 -47
  14. data/examples/logexamp.rb +66 -52
  15. data/examples/logexamp_ssl.rb +66 -52
  16. data/examples/publisher.rb +21 -10
  17. data/examples/put11conn_ex1.rb +35 -24
  18. data/examples/putget11_rh1.rb +66 -56
  19. data/examples/slogger.rb +65 -52
  20. data/examples/ssl_uc1.rb +24 -13
  21. data/examples/ssl_uc1_ciphers.rb +28 -15
  22. data/examples/ssl_uc2.rb +26 -16
  23. data/examples/ssl_uc2_ciphers.rb +31 -18
  24. data/examples/ssl_uc3.rb +25 -14
  25. data/examples/ssl_uc3_ciphers.rb +31 -18
  26. data/examples/ssl_uc4.rb +26 -15
  27. data/examples/ssl_uc4_ciphers.rb +32 -19
  28. data/examples/ssl_ucx_default_ciphers.rb +25 -12
  29. data/examples/stomp11_common.rb +16 -15
  30. data/examples/topic_consumer.rb +23 -10
  31. data/examples/topic_publisher.rb +22 -8
  32. data/lib/client/utils.rb +116 -0
  33. data/lib/connection/heartbeats.rb +173 -0
  34. data/lib/connection/netio.rb +322 -0
  35. data/lib/connection/utf8.rb +294 -0
  36. data/lib/connection/utils.rb +104 -0
  37. data/lib/stomp/client.rb +127 -179
  38. data/lib/stomp/codec.rb +5 -2
  39. data/lib/stomp/connection.rb +109 -865
  40. data/lib/stomp/constants.rb +52 -33
  41. data/lib/stomp/errors.rb +56 -5
  42. data/lib/stomp/ext/hash.rb +4 -0
  43. data/lib/stomp/message.rb +49 -29
  44. data/lib/stomp/sslparams.rb +83 -71
  45. data/lib/stomp/version.rb +3 -1
  46. data/lib/stomp.rb +18 -9
  47. data/stomp.gemspec +58 -3
  48. data/test/test_client.rb +28 -1
  49. data/test/test_codec.rb +8 -2
  50. data/test/test_connection.rb +29 -0
  51. data/test/test_connection1p.rb +31 -16
  52. data/test/test_helper.rb +20 -3
  53. data/test/test_message.rb +8 -3
  54. data/test/test_ssl.rb +10 -4
  55. data/test/tlogger.rb +16 -15
  56. metadata +59 -4
@@ -11,68 +11,77 @@ else
11
11
  require "stomp11_common"
12
12
  end
13
13
  include Stomp11Common
14
+
14
15
  #
15
- # Stomp 1.1 Connection Example 1
16
- # ==============================
16
+ # == Stomp 1.1 Connection Example 2
17
17
  #
18
18
  # Purpose: to demonstrate a connect and disconnect sequence using Stomp 1.1.
19
19
  #
20
20
  # This example is like the 'conn11_ex1.rb' example except that a 'hashed'
21
21
  # connect request is made.
22
22
  #
23
- # Create connection headers
24
- # =========================
25
- #
26
- # The two headers used here are _required_ by the specification.
27
- #
28
- conn_hdrs = {"accept-version" => "1.1", # Demand a 1.1 connection (use a CSV list if you will consider multiple versions)
23
+ class Connection11Example2
24
+ # Initialize.
25
+ def initialize
26
+ end
27
+ # Run example.
28
+ def run
29
+ # Create connection headers
30
+ # =========================
31
+ #
32
+ # The two headers used here are _required_ by the specification.
33
+ #
34
+ conn_hdrs = {"accept-version" => "1.1", # Demand a 1.1 connection (use a CSV list if you will consider multiple versions)
29
35
  "host" => virt_host, # The 1.1 vhost (could be different than connection host)
30
36
  } # No heartbeats here: there will be none for this connection
31
- #
32
- # Create the connect hash.
33
- # ========================
34
- #
35
- conn_hash = { :hosts => [
36
- {:login => login, :passcode => passcode, :host => host, :port => port},
37
+ #
38
+ # Create the connect hash.
39
+ # ========================
40
+ #
41
+ conn_hash = { :hosts => [
42
+ {:login => login, :passcode => passcode, :host => host, :port => port},
37
43
  ],
38
44
  :reliable => false, # Override default
39
45
  :connect_headers => conn_hdrs,
40
46
  }
47
+ #
48
+ # Get a connection
49
+ # ================
50
+ #
51
+ conn = Stomp::Connection.new(conn_hash)
52
+ puts "Connection complete"
53
+ #
54
+ # Let's just do some sanity checks, and look around.
55
+ #
56
+ raise "Connection failed!!" unless conn.open?
57
+ #
58
+ # Is this really a 1.1 conection? ('protocol' is a read only connection
59
+ # instance variable. The value will be '1.0' for those types of connections.)
60
+ #
61
+ raise "Unexpected protocol level" if conn.protocol != Stomp::SPL_11
62
+ #
63
+ # The broker _could_ have returned an ERROR frame (unlikely).
64
+ #
65
+ raise "Connect error: #{conn.connection_frame.body}" if conn.connection_frame.command == Stomp::CMD_ERROR
66
+ #
67
+ # Examine the CONNECT response (the connection_frame).
68
+ #
69
+ puts "Connected Headers required to be present:"
70
+ puts "Connect version - \t#{conn.connection_frame.headers['version']}"
71
+ puts
72
+ puts "Connected Headers that are optional:"
73
+ puts "Connect server - \t\t#{conn.connection_frame.headers['server']}"
74
+ puts "Session ID - \t\t\t#{conn.connection_frame.headers['session']}"
75
+ puts "Server requested heartbeats - \t#{conn.connection_frame.headers['heart-beat']}"
76
+ #
77
+ # Finally disconnect
78
+ # ==================
79
+ #
80
+ conn.disconnect # Business as usual, just like 1.0
81
+ puts "Disconnect complete"
82
+ end
83
+ end
41
84
  #
42
- # Get a connection
43
- # ================
44
- #
45
- conn = Stomp::Connection.new(conn_hash)
46
- puts "Connection complete"
47
- #
48
- # Let's just do some sanity checks, and look around.
49
- #
50
- raise "Connection failed!!" unless conn.open?
51
- #
52
- # Is this really a 1.1 conection? ('protocol' is a read only connection
53
- # instance variable. The value will be '1.0' for those types of connections.)
54
- #
55
- raise "Unexpected protocol level" if conn.protocol != Stomp::SPL_11
56
- #
57
- # The broker _could_ have returned an ERROR frame (unlikely).
58
- #
59
- raise "Connect error: #{conn.connection_frame.body}" if conn.connection_frame.command == Stomp::CMD_ERROR
60
- #
61
- # Examine the CONNECT response (the connection_frame).
62
- #
63
- puts "Connected Headers required to be present:"
64
- puts "Connect version - \t#{conn.connection_frame.headers['version']}"
65
- puts
66
- puts "Connected Headers that are optional:"
67
- puts "Connect broker - \t\t#{conn.connection_frame.headers['broker']}"
68
- puts "Session ID - \t\t\t#{conn.connection_frame.headers['session']}"
69
- puts "Server requested heartbeats - \t#{conn.connection_frame.headers['heart-beat']}"
70
- #
71
- # Finally disconnect
72
- # ==================
73
- #
74
- conn.disconnect # Business as usual, just like 1.0
75
- puts "Disconnect complete"
76
-
77
-
85
+ e = Connection11Example2.new
86
+ e.run
78
87
 
@@ -13,36 +13,45 @@ else
13
13
  require "slogger"
14
14
  end
15
15
  include Stomp11Common
16
+
16
17
  #
17
- # Stomp 1.1 Heartbeat Example 1
18
- # =============================
18
+ # == Stomp 1.1 Heartbeat Example 1
19
19
  #
20
20
  # Purpose: to demonstrate that heart beats can work.
21
21
  #
22
- # Create connection headers
23
- # =========================
24
- #
25
- conn_hdrs = {"accept-version" => "1.1", # 1.1
26
- "host" => virt_host, # vhost
27
- "heart-beat" => "5000,10000", # heartbeats
22
+ class HeartBeatExample1
23
+ # Initialize.
24
+ def initialize
25
+ end
26
+ # Run example.
27
+ def run
28
+ # Create connection headers
29
+ # =========================
30
+ #
31
+ conn_hdrs = {"accept-version" => "1.1", # 1.1
32
+ "host" => virt_host, # vhost
33
+ "heart-beat" => "5000,10000", # heartbeats
28
34
  }
29
- # Create a logger for demonstration purposes
30
- logger = Slogger.new
31
- # Connect - a paramaterized request.
32
- conn = Stomp::Connection.new(login, passcode, host, port, # Normal connect parms
33
- false, # Not reliable, the default for a paramaterized connection
34
- 5, # Connect redelay, the default for a paramaterized connection
35
- conn_hdrs) # The 1.1 connection parameters / headers
36
- puts "Connection connect complete"
37
- #
38
- raise "Unexpected protocol level" if conn.protocol != Stomp::SPL_11
39
- #
40
- conn.set_logger(logger) # Connection uses a logger
41
- sleep 65
42
- conn.set_logger(nil) # No logging
35
+ # Create a logger for demonstration purposes
36
+ logger = Slogger.new
37
+ # Connect - a paramaterized request.
38
+ conn = Stomp::Connection.new(login, passcode, host, port, # Normal connect parms
39
+ false, # Not reliable, the default for a paramaterized connection
40
+ 5, # Connect redelay, the default for a paramaterized connection
41
+ conn_hdrs) # The 1.1 connection parameters / headers
42
+ puts "Connection connect complete"
43
+ #
44
+ raise "Unexpected protocol level" if conn.protocol != Stomp::SPL_11
45
+ #
46
+ conn.set_logger(logger) # Connection uses a logger
47
+ sleep 65
48
+ conn.set_logger(nil) # No logging
49
+ #
50
+ conn.disconnect # Get out
51
+ puts "Connection disconnect complete"
52
+ end
53
+ end
43
54
  #
44
- conn.disconnect # Get out
45
- puts "Connection disconnect complete"
46
-
47
-
55
+ e = HeartBeatExample1.new
56
+ e.run
48
57
 
data/examples/consumer.rb CHANGED
@@ -2,20 +2,33 @@
2
2
 
3
3
  require 'rubygems'
4
4
  require 'stomp'
5
+ #
6
+ # == Example message consumer.
7
+ #
8
+ class ExampleConsumer
9
+ # Initialize.
10
+ def initialize
11
+ end
12
+ # Run example.
13
+ def run
14
+ client = Stomp::Client.new("failover://(stomp://:@localhost:61613,stomp://:@remotehost:61613)?initialReconnectDelay=5000&randomize=false&useExponentialBackOff=false")
15
+ puts "Subscribing ronaldo"
16
+ client.subscribe("/queue/ronaldo", {:ack => "client", "activemq.prefetchSize" => 1, "activemq.exclusive" => true }) do |msg|
17
+ File.open("file", "a") do |f|
18
+ f.write(msg.body)
19
+ f.write("\n----------------\n")
20
+ end
5
21
 
22
+ client.acknowledge(msg)
23
+ end
6
24
 
7
- client = Stomp::Client.new("failover://(stomp://:@localhost:61613,stomp://:@remotehost:61613)?initialReconnectDelay=5000&randomize=false&useExponentialBackOff=false")
8
- puts "Subscribing ronaldo"
9
- client.subscribe("/queue/ronaldo", {:ack => "client", "activemq.prefetchSize" => 1, "activemq.exclusive" => true }) do |msg|
10
- File.open("file", "a") do |f|
11
- f.write(msg.body)
12
- f.write("\n----------------\n")
25
+ loop do
26
+ sleep(1)
27
+ puts "."
28
+ end
13
29
  end
14
-
15
- client.acknowledge(msg)
16
30
  end
31
+ #
32
+ e = ExampleConsumer.new
33
+ e.run
17
34
 
18
- loop do
19
- sleep(1)
20
- puts "."
21
- end
@@ -12,98 +12,106 @@ else
12
12
  end
13
13
  include Stomp11Common
14
14
  #
15
- # Stomp 1.1 Receive Example 1
16
- # ===========================
15
+ # == Stomp 1.1 Receive Example 1
17
16
  #
18
17
  # Purpose: to demonstrate receiving messages using Stomp 1.1.
19
18
  #
20
- conn = get_connection() # Use helper method to obtain a Stomp#connection
21
- raise "Unexpected protocol level" if conn.protocol != Stomp::SPL_11
22
- #
23
- # To start receiving messages, you must first subscribe. This is similar
24
- # to using Stomp 1.0.
25
- #
26
- # However, with Stomp 1.1:
27
- #
28
- # * for subscribe, the 'id' header is now _required_
29
- # * for unsubscribe, the 'id' header is now _required_
30
- #
31
- # The 'id' header specifies a 'subscription id' that _must_ be unique for
32
- # the current session.
33
- #
34
- qname = "/queue/nodea.nodeb.nodec"
35
- #
36
- # Here is an example of allowed functionality in 1.0 that is not allowed in 1.1:
37
- #
38
- begin
39
- conn.subscribe qname
40
- rescue RuntimeError => sre
41
- puts "Rescue: #{sre}, #{sre.message}"
19
+ class Receive11Example1
20
+ # Initialize.
21
+ def initialize
22
+ end
23
+ # Run example.
24
+ def run
25
+ conn = get_connection() # Use helper method to obtain a Stomp#connection
26
+ raise "Unexpected protocol level" if conn.protocol != Stomp::SPL_11
27
+ #
28
+ # To start receiving messages, you must first subscribe. This is similar
29
+ # to using Stomp 1.0.
30
+ #
31
+ # However, with Stomp 1.1:
32
+ #
33
+ # * for subscribe, the 'id' header is now _required_
34
+ # * for unsubscribe, the 'id' header is now _required_
35
+ #
36
+ # The 'id' header specifies a 'subscription id' that _must_ be unique for
37
+ # the current session.
38
+ #
39
+ qname = "/queue/nodea.nodeb.nodec"
40
+ #
41
+ # Here is an example of allowed functionality in 1.0 that is not allowed in 1.1:
42
+ #
43
+ begin
44
+ conn.subscribe qname
45
+ rescue RuntimeError => sre
46
+ puts "Rescue: #{sre}, #{sre.message}"
47
+ end
48
+ #
49
+ # So, you must specify an 'id' header. And it must be unique within the
50
+ # current session.
51
+ #
52
+ # You can build your own unique ids of course. That is a valid option.
53
+ # In order to provide you with some assistance in generating unique ids,
54
+ # two convenience methods are provided with the connection:
55
+ #
56
+ # * sha1 - generate a sha1 hash of some data you supply. This may be sufficient for many purposes.
57
+ # * uuid - generate a type 4 UUID. This would be sufficient in all cases.
58
+ #
59
+ # Get a sha1:
60
+ #
61
+ sha1 = conn.sha1(qname) # sha1 of the queue name perhaps
62
+ puts "Queue name: #{qname}, sha1: #{sha1}"
63
+ #
64
+ # Or perhaps a different sha1:
65
+ #
66
+ tn = Time.now.to_f.to_s # Maybe unique itself.
67
+ sha1 = conn.sha1(tn)
68
+ puts "Time now: #{tn}, sha1: #{sha1}"
69
+ #
70
+ # Or a Type 4 UUID:
71
+ #
72
+ uuid = conn.uuid()
73
+ puts "Type 4 UUID: #{uuid}"
74
+ #
75
+ # You can specify the 'id' in the subscribe call in one of two ways:
76
+ #
77
+ # a) In the headers parameter
78
+ # b) In the third positional parameter, the subId
79
+ #
80
+ # So, using the 'uuid', either:
81
+ #
82
+ # a) conn.subscribe qname, {'id' => uuid}
83
+ # b) conn.subscribe qname, {}, uuid
84
+ #
85
+ conn.subscribe qname, {'id' => uuid} # First style
86
+ #
87
+ # Within a session, you may not subscribe to the same subscription id.
88
+ #
89
+ begin
90
+ conn.subscribe qname, {'id' => uuid} # Second time
91
+ rescue RuntimeError => sre
92
+ puts "Rescue: #{sre}, #{sre.message}"
93
+ end
94
+ #
95
+ # Once you have subscribed, you may receive as usual
96
+ #
97
+ 1.upto(nmsgs()) do
98
+ received = conn.receive
99
+ puts "Received data: #{received.body}"
100
+ end
101
+ #
102
+ # For unsubscribe, you must use the 'id' you used on subscribe.
103
+ #
104
+ # You have the same options for placing this id in the headers or in the 3rd
105
+ # positional parameter.
106
+ #
107
+ conn.unsubscribe qname, {}, uuid # Second style
108
+ #
109
+ # And finally, disconnect.
110
+ #
111
+ conn.disconnect
112
+ end
42
113
  end
43
114
  #
44
- # So, you must specify an 'id' header. And it must be unique within the
45
- # current session.
46
- #
47
- # You can build your own unique ids of course. That is a valid option.
48
- # In order to provide you with some assistance in generating unique ids,
49
- # two convenience methods are provided with the connection:
50
- #
51
- # * sha1 - generate a sha1 hash of some data you supply. This may be sufficient for many purposes.
52
- # * uuid - generate a type 4 UUID. This would be sufficient in all cases.
53
- #
54
- # Get a sha1:
55
- #
56
- sha1 = conn.sha1(qname) # sha1 of the queue name perhaps
57
- puts "Queue name: #{qname}, sha1: #{sha1}"
58
- #
59
- # Or perhaps a different sha1:
60
- #
61
- tn = Time.now.to_f.to_s # Maybe unique itself.
62
- sha1 = conn.sha1(tn)
63
- puts "Time now: #{tn}, sha1: #{sha1}"
64
- #
65
- # Or a Type 4 UUID:
66
- #
67
- uuid = conn.uuid()
68
- puts "Type 4 UUID: #{uuid}"
69
- #
70
- # You can specify the 'id' in the subscribe call in one of two ways:
71
- #
72
- # a) In the headers parameter
73
- # b) In the third positional parameter, the subId
74
- #
75
- # So, using the 'uuid', either:
76
- #
77
- # a) conn.subscribe qname, {'id' => uuid}
78
- # b) conn.subscribe qname, {}, uuid
79
- #
80
- conn.subscribe qname, {'id' => uuid} # First style
81
- #
82
- # Within a session, you may not subscribe to the same subscription id.
83
- #
84
- begin
85
- conn.subscribe qname, {'id' => uuid} # Second time
86
- rescue RuntimeError => sre
87
- puts "Rescue: #{sre}, #{sre.message}"
88
- end
89
- #
90
- # Once you have subscribed, you may receive as usual
91
- #
92
- 1.upto(nmsgs()) do
93
- received = conn.receive
94
- puts "Received data: #{received.body}"
95
- end
96
- #
97
- # For unsubscribe, you must use the 'id' you used on subscribe.
98
- #
99
- # You have the same options for placing this id in the headers or in the 3rd
100
- # positional parameter.
101
- #
102
- conn.unsubscribe qname, {}, uuid # Second style
103
- #
104
- # And finally, disconnect.
105
- #
106
- conn.disconnect
107
-
108
-
115
+ e = Receive11Example1.new
116
+ e.run
109
117
 
@@ -12,58 +12,66 @@ else
12
12
  end
13
13
  include Stomp11Common
14
14
  #
15
- # Stomp 1.1 Receive Example 2
16
- # ===========================
15
+ # == Stomp 1.1 Receive Example 2
17
16
  #
18
17
  # Purpose: to demonstrate receiving messages using Stomp 1.1, and using
19
18
  # 'ack => client'.
20
19
  #
21
- conn = get_connection() # Use helper method to obtain a Stomp#connection
22
- raise "Unexpected protocol level" if conn.protocol != Stomp::SPL_11
23
- #
24
- qname = "/queue/nodea.nodeb.nodec"
25
- #
26
- uuid = conn.uuid()
27
- puts "Subscribe id: #{uuid}"
28
- #
29
- # Subscribe with client ack mode
30
- #
31
- conn.subscribe qname, {'id' => uuid, 'ack' => 'client'} #
32
- #
33
- # Once you have subscribed, you may receive as usual
34
- #
35
- 1.upto(nmsgs()) do
36
- received = conn.receive
37
- puts "Received data: #{received.body}"
38
- #
39
- # We want now to ACK this message. In Stomp 1.0, a 'message-id' header was
40
- # required for the ACK. In Stomp 1.1, and additional header is required:
41
- #
42
- # * 'subscription' => id
43
- #
44
- msgid = received.headers['message-id']
45
- #
46
- # What you cannot do:
47
- #
48
- begin
49
- conn.ack msgid
50
- rescue RuntimeError => sre
51
- puts "Rescue: #{sre}, #{sre.message}"
20
+ class Receive11Example2
21
+ # Initialize.
22
+ def initialize
23
+ end
24
+ # Run example.
25
+ def run
26
+ conn = get_connection() # Use helper method to obtain a Stomp#connection
27
+ raise "Unexpected protocol level" if conn.protocol != Stomp::SPL_11
28
+ #
29
+ qname = "/queue/nodea.nodeb.nodec"
30
+ #
31
+ uuid = conn.uuid()
32
+ puts "Subscribe id: #{uuid}"
33
+ #
34
+ # Subscribe with client ack mode
35
+ #
36
+ conn.subscribe qname, {'id' => uuid, 'ack' => 'client'} #
37
+ #
38
+ # Once you have subscribed, you may receive as usual
39
+ #
40
+ 1.upto(nmsgs()) do
41
+ received = conn.receive
42
+ puts "Received data: #{received.body}"
43
+ #
44
+ # We want now to ACK this message. In Stomp 1.0, a 'message-id' header was
45
+ # required for the ACK. In Stomp 1.1, and additional header is required:
46
+ #
47
+ # * 'subscription' => id
48
+ #
49
+ msgid = received.headers['message-id']
50
+ #
51
+ # What you cannot do:
52
+ #
53
+ begin
54
+ conn.ack msgid
55
+ rescue RuntimeError => sre
56
+ puts "Rescue: #{sre}, #{sre.message}"
57
+ end
58
+ #
59
+ # Try a valid 1.1 ACK
60
+ #
61
+ conn.ack msgid, {'subscription' => uuid}
62
+ puts "ACK - msgid: #{msgid}, subscription: #{uuid}"
63
+ end
64
+ #
65
+ # Unsubscribe
66
+ #
67
+ conn.unsubscribe qname, {}, uuid # Second style
68
+ #
69
+ # And finally, disconnect.
70
+ #
71
+ conn.disconnect
52
72
  end
53
- #
54
- # Try a valid 1.1 ACK
55
- #
56
- conn.ack msgid, {'subscription' => uuid}
57
- puts "ACK - msgid: #{msgid}, subscription: #{uuid}"
58
73
  end
59
74
  #
60
- # Unsubscribe
61
- #
62
- conn.unsubscribe qname, {}, uuid # Second style
63
- #
64
- # And finally, disconnect.
65
- #
66
- conn.disconnect
67
-
68
-
75
+ e = Receive11Example2.new
76
+ e.run
69
77