stomp 1.2.4 → 1.2.5

Sign up to get free protection for your applications and to get access to all the features.
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