qpid_messaging 0.16.0

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 (51) hide show
  1. data/LICENSE +234 -0
  2. data/README.rdoc +46 -0
  3. data/Rakefile +87 -0
  4. data/TODO +7 -0
  5. data/examples/client.rb +50 -0
  6. data/examples/drain.rb +111 -0
  7. data/examples/hello_world.rb +49 -0
  8. data/examples/map_receiver.rb +63 -0
  9. data/examples/map_sender.rb +52 -0
  10. data/examples/server.rb +51 -0
  11. data/examples/spout.rb +126 -0
  12. data/ext/cqpid/cqpid.cpp +9903 -0
  13. data/ext/cqpid/extconf.rb +73 -0
  14. data/features/closing_a_connection.feature +13 -0
  15. data/features/closing_a_session.feature +13 -0
  16. data/features/connecting_to_a_broker.feature +13 -0
  17. data/features/creating_a_receiver.feature +29 -0
  18. data/features/creating_a_sender.feature +25 -0
  19. data/features/creating_a_session.feature +12 -0
  20. data/features/getting_the_connections_authenticated_username.feature +8 -0
  21. data/features/receiving_a_message.feature +28 -0
  22. data/features/sending_a_message.feature +21 -0
  23. data/features/session_returns_its_connection.feature +12 -0
  24. data/features/sessions_have_names.feature +8 -0
  25. data/features/step_definitions/address_steps.rb +24 -0
  26. data/features/step_definitions/connection_steps.rb +93 -0
  27. data/features/step_definitions/receiver_steps.rb +61 -0
  28. data/features/step_definitions/sender_steps.rb +34 -0
  29. data/features/step_definitions/session_steps.rb +99 -0
  30. data/features/support/env.rb +22 -0
  31. data/lib/qpid_messaging.rb +30 -0
  32. data/lib/qpid_messaging/address.rb +187 -0
  33. data/lib/qpid_messaging/connection.rb +162 -0
  34. data/lib/qpid_messaging/duration.rb +95 -0
  35. data/lib/qpid_messaging/encoding.rb +61 -0
  36. data/lib/qpid_messaging/errors.rb +33 -0
  37. data/lib/qpid_messaging/message.rb +368 -0
  38. data/lib/qpid_messaging/receiver.rb +184 -0
  39. data/lib/qpid_messaging/sender.rb +152 -0
  40. data/lib/qpid_messaging/session.rb +269 -0
  41. data/lib/qpid_messaging/version.rb +33 -0
  42. data/spec/qpid/address_spec.rb +87 -0
  43. data/spec/qpid/connection_spec.rb +191 -0
  44. data/spec/qpid/duration_spec.rb +56 -0
  45. data/spec/qpid/encoding_spec.rb +63 -0
  46. data/spec/qpid/message_spec.rb +292 -0
  47. data/spec/qpid/receiver_spec.rb +170 -0
  48. data/spec/qpid/sender_spec.rb +135 -0
  49. data/spec/qpid/session_spec.rb +353 -0
  50. data/spec/spec_helper.rb +20 -0
  51. metadata +106 -0
@@ -0,0 +1,95 @@
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 'cqpid'
21
+
22
+ module Qpid
23
+
24
+ module Messaging
25
+
26
+ # A Duration represents a period of time in milliseconds
27
+ #
28
+ # It defines the following named values as symbols:
29
+ #
30
+ # [:FOREVER]
31
+ # The maximum integer value for the platform. Effectively this will wait
32
+ # forever.
33
+ #
34
+ # [:IMMEDIATE]
35
+ # An alias for 0 milliseconds.
36
+ #
37
+ # [:SECOND]
38
+ # An alias for 1,000 milliseconds.
39
+ #
40
+ # [:MINUTE]
41
+ # And alias for 60,000 millisecons.
42
+ #
43
+ class Duration
44
+
45
+ # Creates a Duration with the specified length, in milliseconds.
46
+ #
47
+ # ==== Options
48
+ #
49
+ # * length - The duration in milliseconds.
50
+ #
51
+ # ==== Examples
52
+ #
53
+ # # Wait up to 10 seconds for an incoming message
54
+ # receiver.get Qpid::Messaging::Duration.new 10000
55
+ #
56
+ def initialize length
57
+ @duration_impl = Cqpid::Duration.new length
58
+ end
59
+
60
+ def duration_impl # :nodoc:
61
+ @duration_impl
62
+ end
63
+
64
+ # Returns the period of time in milliseconds
65
+ #
66
+ # ==== Examples
67
+ #
68
+ # duration = Qpid::Messaging::Duration.new :length => 5000
69
+ # puts "Waiting #{duration.milliseconds} ms for a message."
70
+ # msg = receiver.fetch duration
71
+ #
72
+ def milliseconds
73
+ @duration_impl.getMilliseconds
74
+ end
75
+
76
+ def self.add_item(key, value) # :nodoc:
77
+ @hash ||= {}
78
+ @hash[key] = Duration.new value
79
+ end
80
+
81
+ def self.const_missing(key) # :nodoc:
82
+ @hash[key]
83
+ end
84
+
85
+ self.add_item :FOREVER, Cqpid::Duration.FOREVER.getMilliseconds
86
+ self.add_item :IMMEDIATE, Cqpid::Duration.IMMEDIATE.getMilliseconds
87
+ self.add_item :SECOND, Cqpid::Duration.SECOND.getMilliseconds
88
+ self.add_item :MINUTE, Cqpid::Duration.MINUTE.getMilliseconds
89
+
90
+ end
91
+
92
+ end
93
+
94
+ end
95
+
@@ -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 'cqpid'
21
+
22
+ module Qpid
23
+
24
+ module Messaging
25
+
26
+ # Encodes the supplied content into the given message.
27
+ def self.encode content, message, encoding = nil
28
+ prepared = content
29
+ case content
30
+ when Hash
31
+ prepared = {}
32
+ content.each_pair do |key,value|
33
+ prepared[key.to_s] = value.to_s
34
+ end
35
+ Cqpid::encode prepared, message.message_impl
36
+ when Array
37
+ prepared = []
38
+ content.each {|value| prepared << value.to_s}
39
+ Cqpid::encode prepared, message.message_impl
40
+ end
41
+ end
42
+
43
+ # Decodes and returns the message's content.
44
+ def self.decode(message, content_type = nil)
45
+ content_type = message.content_type unless content_type
46
+
47
+ case content_type
48
+ when "amqp/map"
49
+ Cqpid.decodeMap message.message_impl
50
+
51
+ when "amqp/list"
52
+ Cqpid.decodeList message.message_impl
53
+ end
54
+
55
+ message.content
56
+ end
57
+
58
+ end
59
+
60
+ end
61
+
@@ -0,0 +1,33 @@
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
+ module Qpid
21
+
22
+ module Messaging
23
+
24
+ class KeyError < RuntimeError; end
25
+
26
+ class SessionNameException < Exception
27
+ def initialize(msg); super(msg); end
28
+ end
29
+
30
+ end
31
+
32
+ end
33
+
@@ -0,0 +1,368 @@
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 'cqpid'
21
+
22
+ module Qpid
23
+
24
+ module Messaging
25
+
26
+ # A +Message+ represents an routable piece of information.
27
+ #
28
+ # The content for a message is automatically encoded and decoded.
29
+ #
30
+ class Message
31
+
32
+ # Creates a new instance of +Message+.
33
+ #
34
+ # ==== Options
35
+ #
36
+ # * :content - The content.
37
+ #
38
+ # ==== Examples
39
+ #
40
+ # message = Qpid::Messaging::Message.new :content => "This is a message."
41
+ #
42
+ def initialize(args = {})
43
+ @message_impl = (args[:impl] if args[:impl]) || nil
44
+ @message_impl = Cqpid::Message.new if @message_impl.nil?
45
+ @content = nil
46
+ args = {} if args.nil?
47
+ self.content = args[:content] if args[:content]
48
+ end
49
+
50
+ def message_impl # :nodoc:
51
+ @message_impl
52
+ end
53
+
54
+ # Sets the address to which replies should be sent for the +Message+.
55
+ #
56
+ # *NOTE:* The address must be an instance of Address.
57
+ #
58
+ # ==== Options
59
+ #
60
+ # * address - an instance of +Address+
61
+ #
62
+ # ==== Examples
63
+ #
64
+ # msg.reply_to = Qpid:Messaging::Address.new "my-responses"
65
+ #
66
+ def reply_to=(address)
67
+ raise ArgumentError, "Agument must be an Address" unless address.is_a? Qpid::Messaging::Address
68
+ @message_impl.setReplyTo address.address_impl
69
+ end
70
+
71
+ # Returns the reply to address for the +Message+.
72
+ #
73
+ def reply_to
74
+ address_impl = @message_impl.getReplyTo
75
+ # only return an address if a reply to was specified
76
+ Qpid::Messaging::Address.new(nil, nil, nil, nil, address_impl) if address_impl
77
+ end
78
+
79
+ # Sets the subject for the +Message+.
80
+ #
81
+ # ==== Options
82
+ #
83
+ # * subject - the subject
84
+ #
85
+ # ==== Examples
86
+ #
87
+ # msg.subject = "mysubject"
88
+ #
89
+ def subject=(subject); @message_impl.setSubject subject; end
90
+
91
+ # Returns the subject of the +Message+.
92
+ #
93
+ # ==== Options
94
+ #
95
+ # puts "The subject is #{msg.subject}"
96
+ #
97
+ def subject; @message_impl.getSubject; end
98
+
99
+ # Sets the content type for the +Message+.
100
+ #
101
+ # This should be set by the sending applicaton and indicates to
102
+ # recipients of the message how to interpret or decode the content.
103
+ #
104
+ # By default, only dictionaries and maps are automatically given a content
105
+ # type. If this content type is replaced then retrieving the content will
106
+ # not behave correctly.
107
+ #
108
+ # ==== Options
109
+ #
110
+ # * content_type - the content type.
111
+ #
112
+ def content_type=(content_type); @message_impl.setContentType content_type; end
113
+
114
+ # Returns the content type for the +Message+.
115
+ #
116
+ # ==== Examples
117
+ #
118
+ # case msg.content_type
119
+ # when "myapp/image"
120
+ # ctl.handle_image msg
121
+ # end
122
+ # when "myapp/audio"
123
+ # ctl.handle_audio msg
124
+ # end
125
+ # end
126
+ #
127
+ def content_type; @message_impl.getContentType; end
128
+
129
+ # Sets the message id.
130
+ #
131
+ # *NOTE:* this field must be a UUID type currently. A non-UUID value will
132
+ # be converted to a zero UUID, though a blank ID will be left untouched.
133
+ #
134
+ # ==== Options
135
+ #
136
+ # * id - the id
137
+ #
138
+ # ==== Examples
139
+ #
140
+ #
141
+ def message_id=(message_id); @message_impl.setMessageId message_id.to_s; end
142
+
143
+ # Returns the message id.
144
+ #
145
+ # See +message_id=+ for details.
146
+ def message_id; @message_impl.getMessageId; end
147
+
148
+ # Sets the user id for the +Message+.
149
+ #
150
+ # This should in general be the user-id which was used when authenticating
151
+ # the connection itself, as the messaging infrastructure will verify
152
+ # this.
153
+ #
154
+ # See +Qpid::Messaging::Connection.authenticated_username+
155
+ #
156
+ # *NOTE:* If the id is not a +String+ then the id is set using
157
+ # the object's string representation.
158
+ #
159
+ # ==== Options
160
+ #
161
+ # * id - the id
162
+ #
163
+ def user_id=(user_id); @message_impl.setUserId user_id; end
164
+
165
+ # Returns the user id for the +Message+.
166
+ #
167
+ # See +user_id=+ for details.
168
+ #
169
+ def user_id; @message_impl.getUserId; end
170
+
171
+ # Sets the correlation id of the +Message+.
172
+ #
173
+ # The correlation id can be used as part of a protocol for message
174
+ # exchange patterns; e.g., a requestion-response pattern might require
175
+ # the correlation id of the request and the response to match, or it
176
+ # might use the message id of the request as the correlation id on
177
+ # the response
178
+ #
179
+ # *NOTE:* If the id is not a +String+ then the id is setup using
180
+ # the object's string representation.
181
+ #
182
+ # ==== Options
183
+ #
184
+ # * id - the id
185
+ #
186
+ def correlation_id=(correlation_id); @message_impl.setCorrelationId correlation_id; end
187
+
188
+ # Returns the correlation id of the +Message+.
189
+ #
190
+ # *NOTE:* See +correlation_id=+ for details.
191
+ #
192
+ def correlation_id; @message_impl.getCorrelationId; end
193
+
194
+ # Sets the priority of the +Message+.
195
+ #
196
+ # This may be used by the messaging infrastructure to prioritize
197
+ # delivery of messages with higher priority.
198
+ #
199
+ # *NOTE:* If the priority is not an integer type then it is set using
200
+ # the object's integer representation. If the integer value is greater
201
+ # than 8-bits then only the first 8-bits are used.
202
+ #
203
+ # ==== Options
204
+ #
205
+ # * priority - the priority
206
+ #
207
+ def priority=(priority); @message_impl.setPriority priority; end
208
+
209
+ # Returns the priority for the +Message+.
210
+ #
211
+ def priority; @message_impl.getPriority; end
212
+
213
+ # Sets the time-to-live in milliseconds.
214
+ #
215
+ # ==== Options
216
+ #
217
+ # * duration - the number of milliseconds
218
+ #
219
+ def ttl=(duration)
220
+ if duration.is_a? Qpid::Messaging::Duration
221
+ @message_impl.setTtl duration.duration_impl
222
+ else
223
+ @message_impl.setTtl Cqpid::Duration.new duration.to_i
224
+ end
225
+ end
226
+
227
+ # Returns the time-to-live in milliseconds.
228
+ def ttl; Qpid::Messaging::Duration.new @message_impl.getTtl.getMilliseconds; end
229
+
230
+ # Sets the durability of the +Message+.
231
+ #
232
+ # This is a hint to the messaging infrastructure that the message
233
+ # should be persisted or otherwise stored. This helps to ensure
234
+ # that th emessage is not lost during to failures or a shutdown.
235
+ #
236
+ # ==== Options
237
+ #
238
+ # * durable - the durability flag (def. false)
239
+ #
240
+ def durable=(durable); @message_impl.setDurable durable; end
241
+
242
+ # Returns the durability for the +Message+.
243
+ #
244
+ def durable; @message_impl.getDurable; end
245
+
246
+ # This is a hint to the messaging infrastructure that if de-duplication
247
+ # is required, that this message should be examined to determine if it
248
+ # is a duplicate.
249
+ #
250
+ # ==== Options
251
+ #
252
+ # * redelivered - sets the redelivered state (def. false)
253
+ #
254
+ # ==== Examples
255
+ #
256
+ # # processed is an array of processed message ids
257
+ # msg.redelivered = true if processed.include? msg.message_id
258
+ #
259
+ def redelivered=(redelivered); @message_impl.setRedelivered redelivered; end
260
+
261
+ # Returns whether the +Message+ has been marked as redelivered.
262
+ #
263
+ def redelivered; @message_impl.getRedelivered; end
264
+
265
+ # Returns all named properties.
266
+ #
267
+ # *NOTE:* It is recommended to use the []= method for
268
+ # retrieving and setting properties. Using this method may
269
+ # result in non-deterministic behavior.
270
+ #
271
+ def properties; @message_impl.getProperties; end
272
+
273
+ # Returns the value for the named property.
274
+ #
275
+ # ==== Options
276
+ #
277
+ # * name - the property name
278
+ #
279
+ # ==== Examples
280
+ #
281
+ # # use of message properties to mark a message as digitally signed
282
+ # verify(msg) if msg[:signed]
283
+ #
284
+ def [](key); self.properties[key.to_s]; end
285
+
286
+ # Assigns a value to the named property.
287
+ #
288
+ # *NOTE:* Both the key or the value may be a symbol, but they will
289
+ # both be converted to a +String+ for ease of transport.
290
+ #
291
+ # ==== Options
292
+ #
293
+ # * name - the property name
294
+ # * value - the property value
295
+ def []=(key, value); @message_impl.setProperty(key.to_s, value.to_s); end
296
+
297
+ # Sets the content for the +Message+.
298
+ #
299
+ # Content is automatically encoded for Array and Hash types. Other types
300
+ # need to set their own content types (via +content_type+) in order to
301
+ # specify how recipients should process the content.
302
+ #
303
+ # ==== Options
304
+ #
305
+ # * content - the content
306
+ #
307
+ # ==== Examples
308
+ #
309
+ # msg.content = "This is a simple message." # a simple message
310
+ # msg.content = {:foo => :bar} # content is automatically encoded
311
+ #
312
+ def content=(content)
313
+ content_type = nil
314
+ @content = content
315
+ case @content
316
+ when Hash
317
+ content_type = "amqp/map"
318
+ new_content = {}
319
+ content.each_pair{|key, value| new_content[key.to_s] = value.to_s}
320
+ @content = new_content
321
+ when Array
322
+ new_content = []
323
+ content_type = "amqp/list"
324
+ content.each {|element| new_content << element.to_s}
325
+ @content = new_content
326
+ end
327
+ if content_type.nil?
328
+ @message_impl.setContent @content
329
+ else
330
+ Qpid::Messaging.encode @content, self, content_type
331
+ end
332
+ end
333
+
334
+ # Returns the content of the +Message+.
335
+ #
336
+ # Content is automatically decoded based on the specified content type.
337
+ # If the content type is application-specific, then no decoding is
338
+ # performed and the content is returnedas a +String+ representation.
339
+ #
340
+ # For example, if an array of integers are sent, then the receiver will
341
+ # find the message content to be an array of String objects, where each
342
+ # String is a representation of the sent integer value.
343
+ #
344
+ def content
345
+ if @content.nil?
346
+ @content = @message_impl.getContent
347
+
348
+ # decode the content is necessary if it
349
+ # has an encoded content type
350
+ if ["amqp/list", "amqp/map"].include? @message_impl.getContentType
351
+ @content = Qpid::Messaging.decode(self,
352
+ @message_impl.getContentType)
353
+ end
354
+
355
+ end
356
+ @content
357
+ end
358
+
359
+ # Returns the content's size.
360
+ #
361
+ def content_size; @message_impl.getContentSize; end
362
+
363
+ end
364
+
365
+ end
366
+
367
+ end
368
+