qpid_proton 0.19.0 → 0.21.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/examples/README.md +76 -0
  3. data/examples/broker.rb +167 -0
  4. data/examples/client.rb +79 -0
  5. data/examples/direct_recv.rb +61 -0
  6. data/examples/direct_send.rb +67 -0
  7. data/examples/example_test.rb +109 -0
  8. data/examples/helloworld.rb +57 -0
  9. data/examples/server.rb +70 -0
  10. data/examples/simple_recv.rb +57 -0
  11. data/examples/simple_send.rb +63 -0
  12. data/examples/ssl_certs/README.txt +24 -0
  13. data/examples/ssl_certs/tclient-certificate.p12 +0 -0
  14. data/examples/ssl_certs/tclient-certificate.pem +19 -0
  15. data/examples/ssl_certs/tclient-full.p12 +0 -0
  16. data/examples/ssl_certs/tclient-private-key.pem +30 -0
  17. data/examples/ssl_certs/tserver-certificate.p12 +0 -0
  18. data/examples/ssl_certs/tserver-certificate.pem +19 -0
  19. data/examples/ssl_certs/tserver-full.p12 +0 -0
  20. data/examples/ssl_certs/tserver-private-key.pem +30 -0
  21. data/examples/ssl_send.rb +70 -0
  22. data/ext/cproton/cproton.c +105 -74
  23. data/lib/core/container.rb +2 -1
  24. data/lib/core/ssl_domain.rb +1 -1
  25. data/lib/core/uri.rb +15 -9
  26. data/lib/handler/messaging_adapter.rb +20 -5
  27. data/tests/old_examples/broker.rb +200 -0
  28. data/tests/old_examples/client.rb +81 -0
  29. data/tests/old_examples/direct_recv.rb +64 -0
  30. data/tests/old_examples/direct_send.rb +63 -0
  31. data/tests/old_examples/helloworld.rb +72 -0
  32. data/tests/old_examples/helloworld_direct.rb +73 -0
  33. data/tests/old_examples/lib/debugging.rb +25 -0
  34. data/tests/old_examples/lib/driver.rb +68 -0
  35. data/tests/old_examples/lib/qpid_examples.rb +26 -0
  36. data/tests/old_examples/lib/selectable.rb +119 -0
  37. data/tests/old_examples/lib/send_and_receive.rb +89 -0
  38. data/tests/old_examples/old_example_test.rb +107 -0
  39. data/tests/old_examples/recv.rb +23 -0
  40. data/tests/old_examples/send.rb +21 -0
  41. data/tests/old_examples/server.rb +75 -0
  42. data/tests/old_examples/simple_recv.rb +57 -0
  43. data/tests/old_examples/simple_send.rb +54 -0
  44. data/tests/test_connection_driver.rb +134 -0
  45. data/tests/test_container.rb +319 -0
  46. data/tests/test_data.rb +66 -0
  47. data/tests/test_delivery.rb +110 -0
  48. data/tests/test_interop.rb +131 -0
  49. data/tests/test_messaging_adapter.rb +223 -0
  50. data/tests/test_old_adapter.rb +228 -0
  51. data/tests/test_tools.rb +147 -0
  52. data/tests/test_uri.rb +83 -0
  53. metadata +49 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f385297be1c8a5e6052554821f2231bf09869dfd
4
- data.tar.gz: 72345155dbd507d0e2c53fe3a34f27d8f9a4e838
3
+ metadata.gz: 6495371bf4622d74d87cfd02d4e58323652572eb
4
+ data.tar.gz: 79af23eb910b3f38a1252530b318c45cafe6af54
5
5
  SHA512:
6
- metadata.gz: 19d1c1d49c74667d66474320b6f8e382fbc560131286839cba68c8f99e27a660f7627ab6075dd41ba0867a5dd1803dfa4b0ab60930c1a4023fc93c06fc9fc636
7
- data.tar.gz: 7ae4b1919814ed6b7091dc36ab758634b3bc82a1deb9b59654a05fc621a5666fe6275ad405c95f4c189d6934db3c58ec4f8dd0196209163c341b6e79c63a5732
6
+ metadata.gz: 52e822deb2d458caa735b88d0d6dc5d5e6377d16e836d744d80cdf847c1fcff89b1f22e2e178aa653411e2ffecefb7e314dfa3315f10034c77795cecf4146414
7
+ data.tar.gz: 4cea7fcfbdfadaf4c7fc1319303186c0282292134397c4d536eb46b9e8abccb719164b1b964b09a712aba95fab2193c00a502d1c39fbdace8b6ff636a594fc40
@@ -0,0 +1,76 @@
1
+ ## Simple Examples
2
+
3
+ ### The Broker
4
+
5
+ The examples come with a sample broker which can be used by other examples and which also works as an example itself. For now we'll just start up the broker example and tell it to listen on port 8888:
6
+
7
+ ````
8
+ $ ruby broker.rb amqp://:8888
9
+ Listening on amqp://:8888
10
+ ````
11
+
12
+ This example broker will receive messages, create queues as needed, and deliver messages to endpoints.
13
+
14
+ ### Hello World Using A Broker
15
+
16
+ Our first example creates an endpoint that sends messages to a queue to which it is subscribed. So it both sends and receives a message.
17
+
18
+ To start it, simply run:
19
+
20
+ ```
21
+ $ ruby helloworld.rb //:8888
22
+ Hello world!
23
+ ```
24
+
25
+ As you can see, the classic message was output by the example. Now let's take a look at what's going on under the covers.
26
+
27
+ #### Events When Talking To A Broker
28
+
29
+ The following events occur while **helloworld.rb** runs:
30
+
31
+ * **on_start** - Fired when the application is started.
32
+ * **on_sendable** - Fired when a message can be sent.
33
+ * **on_message** - Fired when a message is received.
34
+
35
+ ## More Complex Examples
36
+
37
+ Now that we've covered the basics with the archetypical hello world app, let's look at some more interesting examples.
38
+
39
+ The following two client examples send and receive messages to an external broker or server:
40
+
41
+ * **simple_send.rb** - connect to a server, send messages to an address
42
+ * **simple_recv.rb** - connect to a server, receives messages from an address
43
+
44
+ For example: start `broker.rb`; run `simple_send.rb` to send messages to a
45
+ broker queue; then `simple_recv.rb` to receive the messages from the broker.
46
+
47
+ The following two examples are *servers* that can be connected to directly, without a broker:
48
+
49
+ * **direct_send.rb** - sends messages directly to a receiver and listens for responses itself, and
50
+ * **direct_recv.rb** - receives messages directly.
51
+
52
+ For example if you start `direct_recv.rb`, you can connect to it directly with
53
+ `simple_send.rb` vice-versa with `direct_send.rb` and `simple_recv.rb`
54
+
55
+ In this set of examples we see the following event occurring, in addition to what we've seen before:
56
+
57
+ * **on_transport_close** - Fired when the network transport is closed.
58
+
59
+ ## Now About That Broker example
60
+
61
+ The **broker.rb** example application is a nice demonstration of doing something more interesting in Ruby with Proton.
62
+
63
+ The way the broker works is to listen to incoming connections, examine the components of the address for that connection, attach that connection to an exchange managing that address and then it sends any messages destined for that address to them.
64
+
65
+ The components of the broker example include:
66
+ * **Broker** - A class that extends the MessagingHandler class. It accepts incoming connections, manages subscribing them to exchanges, and transfers messages between them.
67
+ * **MessageQueue** - Distributes messages to subscriptions.
68
+
69
+ The Broker manages a map connecting a queue address to the instance of Exchange that holds references to the endpoints of interest.
70
+
71
+ The broker application demonstrates a new set of events:
72
+
73
+ * **on_link_open** - Fired when a remote link is opened. From this event the broker grabs the address and subscribes the link to an exchange for that address.
74
+ * **on_link_close** - Fired when a remote link is closed. From this event the broker grabs the address and unsubscribes the link from that exchange.
75
+ * **on_connection_close** - Fired when a remote connection is closed but the local end is still open.
76
+ * **on_transport_close** - Fired when the protocol transport has closed. The broker removes all links for the disconnected connection, avoiding workign with endpoints that are now gone.
@@ -0,0 +1,167 @@
1
+ #--
2
+ # Licensed to the Apache Software Foundation (ASF) under one
3
+ # or more contributor license agreements. See the NOTICE file
4
+ # distributed with this work for additional information
5
+ # regarding copyright ownership. The ASF licenses this file
6
+ # to you under the Apache License, Version 2.0 (the
7
+ # "License"); you may not use this file except in compliance
8
+ # with the License. You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing,
13
+ # software distributed under the License is distributed on an
14
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
+ # KIND, either express or implied. See the License for the
16
+ # specific language governing permissions and limitations
17
+ # under the License.
18
+ #++
19
+
20
+ require 'qpid_proton'
21
+ require 'optparse'
22
+ require 'pathname'
23
+
24
+ class MessageQueue
25
+
26
+ def initialize(dynamic = false)
27
+ @dynamic = dynamic
28
+ @queue = Queue.new
29
+ @consumers = []
30
+ end
31
+
32
+ def subscribe(consumer)
33
+ @consumers << (consumer)
34
+ end
35
+
36
+ def unsubscribe(consumer)
37
+ if @consumers.include?(consumer)
38
+ @consumers.delete(consumer)
39
+ end
40
+ @consumers.empty? && (@dynamic || @queue.empty?)
41
+ end
42
+
43
+ def publish(message)
44
+ @queue << message
45
+ self.dispatch
46
+ end
47
+
48
+ def dispatch(consumer = nil)
49
+ if consumer
50
+ c = [consumer]
51
+ else
52
+ c = @consumers
53
+ end
54
+
55
+ while self.deliver_to(c) do
56
+ end
57
+ end
58
+
59
+ def deliver_to(consumers)
60
+ result = false
61
+ consumers.each do |consumer|
62
+ if consumer.credit > 0 && !@queue.empty?
63
+ consumer.send(@queue.pop(true))
64
+ result = true
65
+ end
66
+ end
67
+ return result
68
+ end
69
+
70
+ end
71
+
72
+ class Broker < Qpid::Proton::MessagingHandler
73
+
74
+ def initialize(url)
75
+ super()
76
+ @url = url
77
+ @queues = {}
78
+ begin # Optional SSL setup, ignore if we don't find cert files etc.
79
+ @ssl_domain = Qpid::Proton::SSLDomain.new(Qpid::Proton::SSLDomain::MODE_SERVER)
80
+ cert_passsword = "tserverpw"
81
+ if Gem.win_platform? # Use P12 certs for windows schannel
82
+ @ssl_domain.credentials("ssl_certs/tserver-certificate.p12", "", cert_passsword)
83
+ else
84
+ @ssl_domain.credentials("ssl_certs/tserver-certificate.pem", "ssl_certs/tserver-private-key.pem", cert_passsword)
85
+ end
86
+ @ssl_domain.allow_unsecured_client # SSL is optional, this is not secure.
87
+ rescue
88
+ @ssl_domain = nil # Don't worry if we can't set up SSL.
89
+ end
90
+ end
91
+
92
+ def on_container_start(container)
93
+ # Options for incoming connections, provide SSL configuration if we have it.
94
+ opts = {:ssl_domain => @ssl_domain} if @ssl_domain
95
+ @listener = container.listen(@url, Qpid::Proton::Listener::Handler.new(opts))
96
+ STDOUT.puts "Listening on #{@url.inspect}"; STDOUT.flush
97
+ end
98
+
99
+ def queue(address)
100
+ unless @queues.has_key?(address)
101
+ @queues[address] = MessageQueue.new
102
+ end
103
+ @queues[address]
104
+ end
105
+
106
+ def on_sender_open(sender)
107
+ if sender.remote_source.dynamic?
108
+ address = SecureRandom.uuid
109
+ sender.source.address = address
110
+ q = MessageQueue.new(true)
111
+ @queues[address] = q
112
+ q.subscribe(sender)
113
+ elsif sender.remote_source.address
114
+ sender.source.address = sender.remote_source.address
115
+ self.queue(sender.source.address).subscribe(sender)
116
+ end
117
+ end
118
+
119
+ def on_receiver_open(receiver)
120
+ if receiver.remote_target.address
121
+ receiver.target.address = receiver.remote_target.address
122
+ end
123
+ end
124
+
125
+ def unsubscribe(link)
126
+ if @queues.has_key?(link.source.address)
127
+ if @queues[link.source.address].unsubscribe(link)
128
+ @queues.delete(link.source.address)
129
+ end
130
+ end
131
+ end
132
+
133
+ def on_sender_close(sender)
134
+ self.unsubscribe(sender)
135
+ end
136
+
137
+ def on_connection_close(connection)
138
+ self.remove_stale_consumers(connection)
139
+ end
140
+
141
+ def on_transport_close(transport)
142
+ self.remove_stale_consumers(transport.connection)
143
+ end
144
+
145
+ def remove_stale_consumers(connection)
146
+ connection.each_sender { |s| unsubscribe(s) }
147
+ end
148
+
149
+ def on_sendable(sender)
150
+ q = self.queue(sender.source.address)
151
+ q.dispatch(sender)
152
+ end
153
+
154
+ def on_message(delivery, message)
155
+ q = self.queue(delivery.link.target.address)
156
+ q.publish(message)
157
+ end
158
+
159
+ end
160
+
161
+ if ARGV.size != 1
162
+ STDERR.puts "Usage: #{__FILE__} URL
163
+ Start an example broker listening on URL"
164
+ return 1
165
+ end
166
+ url, = ARGV
167
+ Qpid::Proton::Container.new(Broker.new(url)).run
@@ -0,0 +1,79 @@
1
+ #--
2
+ # Licensed to the Apache Software Foundation (ASF) under one
3
+ # or more contributor license agreements. See the NOTICE file
4
+ # distributed with this work for additional information
5
+ # regarding copyright ownership. The ASF licenses this file
6
+ # to you under the Apache License, Version 2.0 (the
7
+ # "License"); you may not use this file except in compliance
8
+ # with the License. You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing,
13
+ # software distributed under the License is distributed on an
14
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
+ # KIND, either express or implied. See the License for the
16
+ # specific language governing permissions and limitations
17
+ # under the License.
18
+ #++
19
+
20
+ require 'qpid_proton'
21
+ require 'optparse'
22
+
23
+ class Client < Qpid::Proton::MessagingHandler
24
+
25
+ def initialize(url, address, requests)
26
+ super()
27
+ @url = url
28
+ @address = address
29
+ @requests = requests
30
+ end
31
+
32
+ def on_container_start(container)
33
+ c = container.connect(@url)
34
+ @sender = c.open_sender(@address)
35
+ @receiver = c.open_receiver({:dynamic => true})
36
+ end
37
+
38
+ def next_request
39
+ if @receiver.remote_source.address
40
+ req = Qpid::Proton::Message.new
41
+ req.reply_to = @receiver.remote_source.address
42
+ req.body = @requests.first
43
+ puts "-> #{req.body}"
44
+ @sender.send(req)
45
+ end
46
+ end
47
+
48
+ def on_receiver_open(receiver)
49
+ next_request
50
+ end
51
+
52
+ def on_message(delivery, message)
53
+ puts "<- #{message.body}"
54
+ @requests.delete_at(0)
55
+ if !@requests.empty?
56
+ next_request
57
+ else
58
+ delivery.connection.close
59
+ end
60
+ end
61
+
62
+ def on_transport_error(transport)
63
+ raise "Connection error: #{transport.condition}"
64
+ end
65
+
66
+ end
67
+
68
+ REQUESTS = ["Twas brillig, and the slithy toves",
69
+ "Did gire and gymble in the wabe.",
70
+ "All mimsy were the borogroves,",
71
+ "And the mome raths outgrabe."]
72
+
73
+ if ARGV.size != 2
74
+ STDERR.puts "Usage: #{__FILE__} URL ADDRESS
75
+ Connect to URL and send messages to ADDRESS"
76
+ return 1
77
+ end
78
+ url, address = ARGV
79
+ Qpid::Proton::Container.new(Client.new(url, address, REQUESTS)).run
@@ -0,0 +1,61 @@
1
+ #--
2
+ # Licensed to the Apache Software Foundation (ASF) under one
3
+ # or more contributor license agreements. See the NOTICE file
4
+ # distributed with this work for additional information
5
+ # regarding copyright ownership. The ASF licenses this file
6
+ # to you under the Apache License, Version 2.0 (the
7
+ # "License"); you may not use this file except in compliance
8
+ # with the License. You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing,
13
+ # software distributed under the License is distributed on an
14
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
+ # KIND, either express or implied. See the License for the
16
+ # specific language governing permissions and limitations
17
+ # under the License.
18
+ #++
19
+
20
+ require 'qpid_proton'
21
+ require 'optparse'
22
+
23
+ class DirectReceive < Qpid::Proton::MessagingHandler
24
+
25
+ def initialize(url, address, count)
26
+ super()
27
+ @url = url
28
+ @address = address
29
+ @expected = count
30
+ @received = 0
31
+ end
32
+
33
+ class ListenOnce < Qpid::Proton::Listener::Handler
34
+ def on_open(l) STDOUT.puts "Listening\n"; STDOUT.flush; end
35
+ def on_accept(l) l.close; end
36
+ end
37
+
38
+ def on_container_start(container)
39
+ container.listen(@url, ListenOnce.new)
40
+ end
41
+
42
+ def on_message(delivery, message)
43
+ if @expected.zero? || (@received < @expected)
44
+ puts "Received: #{message.body}"
45
+ @received = @received + 1
46
+ if @received == @expected
47
+ delivery.connection.close
48
+ end
49
+ end
50
+ end
51
+ end
52
+
53
+ unless (2..3).include? ARGV.size
54
+ STDERR.puts "Usage: #{__FILE__} URL ADDRESS [COUNT]
55
+ Listen on URL and receive COUNT messages from ADDRESS"
56
+ return 1
57
+ end
58
+ url, address, count = ARGV
59
+ count = Integer(count || 10)
60
+ Qpid::Proton::Container.new(DirectReceive.new(url, address, count)).run
61
+
@@ -0,0 +1,67 @@
1
+ #--
2
+ # Licensed to the Apache Software Foundation (ASF) under one
3
+ # or more contributor license agreements. See the NOTICE file
4
+ # distributed with this work for additional information
5
+ # regarding copyright ownership. The ASF licenses this file
6
+ # to you under the Apache License, Version 2.0 (the
7
+ # "License"); you may not use this file except in compliance
8
+ # with the License. You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing,
13
+ # software distributed under the License is distributed on an
14
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
+ # KIND, either express or implied. See the License for the
16
+ # specific language governing permissions and limitations
17
+ # under the License.
18
+ #++
19
+
20
+ require 'qpid_proton'
21
+ require 'optparse'
22
+
23
+ class DirectSend < Qpid::Proton::MessagingHandler
24
+
25
+ def initialize(url, address, expected)
26
+ super()
27
+ @url = url
28
+ @address = address
29
+ @sent = 0
30
+ @confirmed = 0
31
+ @expected = expected
32
+ end
33
+
34
+ class ListenOnce < Qpid::Proton::Listener::Handler
35
+ def on_open(l) STDOUT.puts "Listening\n"; STDOUT.flush; end
36
+ def on_accept(l) l.close; end
37
+ end
38
+
39
+ def on_container_start(container)
40
+ container.listen(@url, ListenOnce.new)
41
+ end
42
+
43
+ def on_sendable(sender)
44
+ while sender.credit > 0 && @sent < @expected
45
+ msg = Qpid::Proton::Message.new("sequence #{@sent}", { :id => @sent } )
46
+ sender.send(msg)
47
+ @sent = @sent + 1
48
+ end
49
+ end
50
+
51
+ def on_tracker_accept(tracker)
52
+ @confirmed = @confirmed + 1
53
+ if @confirmed == @expected
54
+ puts "All #{@expected} messages confirmed!"
55
+ tracker.connection.close
56
+ end
57
+ end
58
+ end
59
+
60
+ unless (2..3).include? ARGV.size
61
+ STDERR.puts "Usage: #{__FILE__} URL ADDRESS [COUNT]
62
+ Listen on URL and send COUNT messages to ADDRESS"
63
+ return 1
64
+ end
65
+ url, address, count = ARGV
66
+ count = Integer(count || 10)
67
+ Qpid::Proton::Container.new(DirectSend.new(url, address, count)).run
@@ -0,0 +1,109 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Licensed to the Apache Software Foundation (ASF) under one
4
+ # or more contributor license agreements. See the NOTICE file
5
+ # distributed with this work for additional information
6
+ # regarding copyright ownership. The ASF licenses this file
7
+ # to you under the Apache License, Version 2.0 (the
8
+ # "License"); you may not use this file except in compliance
9
+ # with the License. You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing,
14
+ # software distributed under the License is distributed on an
15
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16
+ # KIND, either express or implied. See the License for the
17
+ # specific language governing permissions and limitations
18
+ # under the License.
19
+ #
20
+
21
+ require 'minitest/autorun'
22
+ require 'qpid_proton'
23
+ require 'socket'
24
+ require 'rbconfig'
25
+
26
+ begin
27
+ MiniTest::Test
28
+ rescue NameError # For older versions of MiniTest
29
+ MiniTest::Test = MiniTest::Unit::TestCase
30
+ end
31
+
32
+ # URL with an unused port
33
+ def test_url()
34
+ "amqp://:#{TCPServer.open(0) { |s| s.addr[1] }}"
35
+ end
36
+
37
+
38
+ class ExampleTest < MiniTest::Test
39
+
40
+ def run_script(*args)
41
+ return IO.popen([ RbConfig.ruby ] + args.map { |a| a.to_s })
42
+ end
43
+
44
+ def assert_output(want, *args)
45
+ assert_equal(want.strip, run_script(*args).read.strip)
46
+ end
47
+
48
+ def test_helloworld
49
+ assert_output("Hello world!", "helloworld.rb", $url, __method__)
50
+ end
51
+
52
+ def test_client_server
53
+ want = <<EOS
54
+ -> Twas brillig, and the slithy toves
55
+ <- TWAS BRILLIG, AND THE SLITHY TOVES
56
+ -> Did gire and gymble in the wabe.
57
+ <- DID GIRE AND GYMBLE IN THE WABE.
58
+ -> All mimsy were the borogroves,
59
+ <- ALL MIMSY WERE THE BOROGROVES,
60
+ -> And the mome raths outgrabe.
61
+ <- AND THE MOME RATHS OUTGRABE.
62
+ EOS
63
+ server = run_script("server.rb", $url, __method__)
64
+ assert_output(want.strip, "client.rb", $url, __method__)
65
+ ensure
66
+ Process.kill :TERM, server.pid if server
67
+ end
68
+
69
+ def test_send_recv
70
+ assert_output("All 10 messages confirmed!", "simple_send.rb", $url, __method__)
71
+ want = (0..9).reduce("") { |x,y| x << "Received: sequence #{y}\n" }
72
+ assert_output(want.strip, "simple_recv.rb", $url, __method__)
73
+ end
74
+
75
+ def test_ssl_send_recv
76
+ out = run_script("ssl_send.rb", $url, __method__).read.strip
77
+ assert_match(/Connection secured with "...*\"\nAll 10 messages confirmed!/, out)
78
+ want = (0..9).reduce("") { |x,y| x << "Received: sequence #{y}\n" }
79
+ assert_output(want.strip, "simple_recv.rb", $url, __method__)
80
+ end
81
+
82
+ def test_direct_recv
83
+ url = test_url
84
+ p = run_script("direct_recv.rb", url, __method__)
85
+ p.readline # Wait till ready
86
+ assert_output("All 10 messages confirmed!", "simple_send.rb", url, __method__)
87
+ want = (0..9).reduce("") { |x,y| x << "Received: sequence #{y}\n" }
88
+ assert_equal(want.strip, p.read.strip)
89
+ end
90
+
91
+ def test_direct_send
92
+ url = test_url
93
+ p = run_script("direct_send.rb", url, __method__)
94
+ p.readline # Wait till ready
95
+ want = (0..9).reduce("") { |x,y| x << "Received: sequence #{y}\n" }
96
+ assert_output(want.strip, "simple_recv.rb", url, __method__)
97
+ assert_equal("All 10 messages confirmed!", p.read.strip)
98
+ end
99
+ end
100
+
101
+ # Start the broker before all tests.
102
+ $url = test_url
103
+ $broker = IO.popen([RbConfig.ruby, 'broker.rb', $url])
104
+ $broker.readline
105
+
106
+ # Kill the broker after all tests
107
+ MiniTest.after_run do
108
+ Process.kill(:TERM, $broker.pid) if $broker
109
+ end
@@ -0,0 +1,57 @@
1
+ #--
2
+ # Licensed to the Apache Software Foundation (ASF) under one
3
+ # or more contributor license agreements. See the NOTICE file
4
+ # distributed with this work for additional information
5
+ # regarding copyright ownership. The ASF licenses this file
6
+ # to you under the Apache License, Version 2.0 (the
7
+ # "License"); you may not use this file except in compliance
8
+ # with the License. You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing,
13
+ # software distributed under the License is distributed on an
14
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
+ # KIND, either express or implied. See the License for the
16
+ # specific language governing permissions and limitations
17
+ # under the License.
18
+ #++
19
+
20
+ require 'qpid_proton'
21
+ require 'optparse'
22
+
23
+ class HelloWorld < Qpid::Proton::MessagingHandler
24
+
25
+ def initialize(url, address)
26
+ super()
27
+ @url, @address = url, address
28
+ end
29
+
30
+ def on_container_start(container)
31
+ conn = container.connect(@url)
32
+ conn.open_sender(@address)
33
+ conn.open_receiver(@address)
34
+ end
35
+
36
+ def on_sendable(sender)
37
+ sender.send(Qpid::Proton::Message.new("Hello world!"))
38
+ sender.close
39
+ end
40
+
41
+ def on_message(delivery, message)
42
+ puts message.body
43
+ delivery.connection.close
44
+ end
45
+
46
+ def on_transport_error(transport)
47
+ raise "Connection error: #{transport.condition}"
48
+ end
49
+ end
50
+
51
+ if ARGV.size != 2
52
+ STDERR.puts "Usage: #{__FILE__} URL ADDRESS
53
+ Connect to URL, send a message to ADDRESS and receive it back"
54
+ return 1
55
+ end
56
+ url, address = ARGV
57
+ Qpid::Proton::Container.new(HelloWorld.new(url, address)).run
@@ -0,0 +1,70 @@
1
+ #--
2
+ # Licensed to the Apache Software Foundation (ASF) under one
3
+ # or more contributor license agreements. See the NOTICE file
4
+ # distributed with this work for additional information
5
+ # regarding copyright ownership. The ASF licenses this file
6
+ # to you under the Apache License, Version 2.0 (the
7
+ # "License"); you may not use this file except in compliance
8
+ # with the License. You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing,
13
+ # software distributed under the License is distributed on an
14
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
+ # KIND, either express or implied. See the License for the
16
+ # specific language governing permissions and limitations
17
+ # under the License.
18
+ #++
19
+
20
+ require 'qpid_proton'
21
+ require 'optparse'
22
+
23
+ class Server < Qpid::Proton::MessagingHandler
24
+
25
+ def initialize(url, address)
26
+ super()
27
+ @url = url
28
+ @address = address
29
+ @senders = {}
30
+ end
31
+
32
+ def on_container_start(container)
33
+ c = container.connect(@url)
34
+ c.open_receiver(@address)
35
+ @relay = nil
36
+ end
37
+
38
+ def on_connection_open(connection)
39
+ if connection.offered_capabilities &&
40
+ connection.offered_capabilities.contain?("ANONYMOUS-RELAY")
41
+ @relay = connection.open_sender({:target => nil})
42
+ end
43
+ end
44
+
45
+ def on_message(delivery, message)
46
+ return unless message.reply_to # Not a request message
47
+ puts "<- #{message.body}"
48
+ unless (sender = @relay)
49
+ sender = (@senders[message.reply_to] ||= delivery.connection.open_sender(message.reply_to))
50
+ end
51
+ reply = Qpid::Proton::Message.new
52
+ reply.address = message.reply_to
53
+ reply.body = message.body.upcase
54
+ puts "-> #{reply.body}"
55
+ reply.correlation_id = message.correlation_id
56
+ sender.send(reply)
57
+ end
58
+
59
+ def on_transport_error(transport)
60
+ raise "Connection error: #{transport.condition}"
61
+ end
62
+ end
63
+
64
+ if ARGV.size != 2
65
+ STDERR.puts "Usage: #{__FILE__} URL ADDRESS
66
+ Server listening on URL, reply to messages to ADDRESS"
67
+ return 1
68
+ end
69
+ url, address = ARGV
70
+ Qpid::Proton::Container.new(Server.new(url, address)).run