qpid_proton 0.4 → 0.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.
@@ -18,7 +18,12 @@
18
18
  #
19
19
 
20
20
  require "cproton"
21
+ require "date"
21
22
 
23
+ require "qpid_proton/described"
24
+ require "qpid_proton/mapping"
25
+ require "qpid_proton/array"
26
+ require "qpid_proton/hash"
22
27
  require "qpid_proton/exceptions"
23
28
  require "qpid_proton/exception_handling"
24
29
  require "qpid_proton/message_format"
@@ -0,0 +1,173 @@
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
+ #--
21
+ # Patch the Array class to provide methods for adding its contents
22
+ # to a Qpid::Proton::Data instance.
23
+ #++
24
+
25
+ module Qpid
26
+
27
+ module Proton
28
+
29
+ # Holds the information for an AMQP Array compound type.
30
+ #
31
+ # It holds the type for the array and the descriptor if the
32
+ # array is described.
33
+ #
34
+ class ArrayHeader
35
+ attr_reader :type
36
+ attr_reader :descriptor
37
+
38
+ def initialize(type, descriptor = nil)
39
+ @type = type
40
+ @descriptor = descriptor
41
+ end
42
+
43
+ # Returns true if the array is described.
44
+ def described?
45
+ !@descriptor.nil?
46
+ end
47
+
48
+ def ==(that)
49
+ ((@type == that.type) && (@descriptor == that.descriptor))
50
+ end
51
+ end
52
+
53
+ end
54
+
55
+ end
56
+
57
+ class Array
58
+
59
+ # Used to declare an array as an AMQP array.
60
+ #
61
+ # The value, if defined, is an instance of Qpid::Proton::ArrayHeader
62
+ attr_accessor :proton_array_header
63
+
64
+ # Returns true if the array is the a Proton described type.
65
+ def proton_described?
66
+ !@proton_array_header.nil? && @proton_array_header.described?
67
+ end
68
+
69
+ # Puts the elements of the array into the specified Qpid::Proton::Data object.
70
+ def proton_put(data)
71
+ raise TypeError, "data object cannot be nil" if data.nil?
72
+
73
+ if @proton_array_header.nil?
74
+ proton_put_list(data)
75
+ else
76
+ proton_put_array(data)
77
+ end
78
+ end
79
+
80
+ private
81
+
82
+ def proton_put_list(data)
83
+ # create a list, then enter it and add each element
84
+ data.put_list
85
+ data.enter
86
+ each do |element|
87
+ # get the proton type for the element
88
+ mapping = Qpid::Proton::Mapping.for_class(element.class)
89
+ # add the element
90
+ mapping.put(data, element)
91
+ end
92
+ # exit the list
93
+ data.exit
94
+ end
95
+
96
+ def proton_put_array(data)
97
+ data.put_array(@proton_array_header.described?, @proton_array_header.type)
98
+ data.enter
99
+ if @proton_array_header.described?
100
+ data.symbol = @proton_array_header.descriptor
101
+ end
102
+
103
+ each do |element|
104
+ @proton_array_header.type.put(data, element)
105
+ end
106
+
107
+ data.exit
108
+ end
109
+
110
+ class << self
111
+
112
+ # Gets the elements of an array or list out of the specified
113
+ # Qpid::Proton::Data object.
114
+ def proton_get(data)
115
+ raise TypeError, "can't convert nil into Qpid::Proton::Data" if data.nil?
116
+
117
+ type = data.type
118
+
119
+ if type == Qpid::Proton::LIST
120
+ result = proton_get_list(data)
121
+ elsif type == Qpid::Proton::ARRAY
122
+ result = proton_get_array(data)
123
+ else
124
+ raise TypeError, "element is not a list and not an array"
125
+ end
126
+ end
127
+
128
+ private
129
+
130
+ def proton_get_list(data)
131
+ size = data.list
132
+ raise TypeError, "not a list" unless data.enter
133
+ elements = []
134
+ (0...size).each do
135
+ data.next
136
+ type = data.type
137
+ raise TypeError, "missing next element in list" unless type
138
+ elements << type.get(data)
139
+ end
140
+ data.exit
141
+ return elements
142
+ end
143
+
144
+ def proton_get_array(data)
145
+ count, described, type = data.array
146
+
147
+ raise TypeError, "not an array" unless data.enter
148
+ elements = []
149
+
150
+ descriptor = nil
151
+
152
+ if described
153
+ data.next
154
+ descriptor = data.symbol
155
+ end
156
+
157
+ elements.proton_array_header = Qpid::Proton::ArrayHeader.new(type, descriptor)
158
+ (0...count).each do |which|
159
+ if data.next
160
+ etype = data.type
161
+ raise TypeError, "missing next element in array" unless etype
162
+ raise TypeError, "invalid array element: #{etype}" unless etype == type
163
+ elements << type.get(data)
164
+ end
165
+ end
166
+ data.exit
167
+ return elements
168
+ end
169
+
170
+ end
171
+
172
+ end
173
+
@@ -17,6 +17,8 @@
17
17
  # under the License.
18
18
  #
19
19
 
20
+ require 'cproton'
21
+
20
22
  module Qpid
21
23
 
22
24
  module Proton
@@ -51,27 +53,34 @@ module Qpid
51
53
  #
52
54
  # The following types of scalar values are supported:
53
55
  #
54
- # * *:NULL*
55
- # * *:BOOL*
56
- # * *:UBYTE*
57
- # * *:USHORT*
58
- # * *:SHORT*
59
- # * *:UINT*
60
- # * *:INT*
61
- # * *:ULONG*
62
- # * *:LONG*
63
- # * *:FLOAT*
64
- # * *:DOUBLE*
65
- # * *:BINARY*
66
- # * *:STRING*
67
- # * *:SYMBOL*
56
+ # * *NULL*
57
+ # * *BOOL*
58
+ # * *UBYTE*
59
+ # * *BYTE*
60
+ # * *USHORT*
61
+ # * *SHORT*
62
+ # * *UINT*
63
+ # * *INT*
64
+ # * *CHAR*
65
+ # * *ULONG*
66
+ # * *LONG*
67
+ # * *TIMESTAMP*
68
+ # * *FLOAT*
69
+ # * *DOUBLE*
70
+ # * *DECIMAL32*
71
+ # * *DECIMAL64*
72
+ # * *DECIMAL128*
73
+ # * *UUID*
74
+ # * *BINARY*
75
+ # * *STRING*
76
+ # * *SYMBOL*
68
77
  #
69
78
  # The following types of compound values are supported:
70
79
  #
71
- # * *:DESCRIBED*
72
- # * *:ARRAY*
73
- # * *:LIST*
74
- # * *:MAP*
80
+ # * *DESCRIBED*
81
+ # * *ARRAY*
82
+ # * *LIST*
83
+ # * *MAP*
75
84
  #
76
85
  class Data
77
86
 
@@ -115,13 +124,12 @@ module Qpid
115
124
  Cproton.pn_data_rewind(@data)
116
125
  end
117
126
 
118
- # Advances the current node to tits next sibling and returns its types.
127
+ # Advances the current node to its next sibling and returns its types.
119
128
  #
120
129
  # If there is no next sibling the current node remains unchanged
121
130
  # and nil is returned.
122
- def next
123
- found = Cproton.pn_data_next(@data)
124
- return found ? found : nil
131
+ def next(print = false)
132
+ Cproton.pn_data_next(@data)
125
133
  end
126
134
 
127
135
  # Advances the current node to its previous sibling and returns its type.
@@ -129,8 +137,7 @@ module Qpid
129
137
  # If there is no previous sibling then the current node remains unchanged
130
138
  # and nil is return.
131
139
  def prev
132
- found = Cproton.pn_data_prev(@data)
133
- return found ? found : nil
140
+ return Cproton.pn_data_prev(@data) ? type : nil
134
141
  end
135
142
 
136
143
  # Sets the parent node to the current node and clears the current node.
@@ -146,21 +153,26 @@ module Qpid
146
153
  Cproton.pn_data_exit(@data)
147
154
  end
148
155
 
149
- # Returns the type of the current node.
150
- def node_type
156
+ # Returns the numeric type code of the current node.
157
+ def type_code
151
158
  dtype = Cproton.pn_data_type(@data)
152
159
  return (dtype == -1) ? nil : dtype
153
160
  end
154
161
 
155
- # Returns a representation of the data encoded. in AMQP format.
162
+ # Return the Type object for the current node
163
+ def type
164
+ Mapping.for_code(type_code)
165
+ end
166
+
167
+ # Returns a representation of the data encoded in AMQP format.
156
168
  def encode
157
- size = 1024
169
+ buffer = "\0"*1024
158
170
  loop do
159
- (cd, enc) = Cproton.pn_data_encode(@data, size)
171
+ cd = Cproton.pn_data_encode(@data, buffer, buffer.length)
160
172
  if cd == Cproton::PN_OVERFLOW
161
- size *= 2
173
+ buffer *= 2
162
174
  elsif cd >= 0
163
- return enc
175
+ return buffer[0...cd]
164
176
  else
165
177
  check(cd)
166
178
  end
@@ -175,7 +187,7 @@ module Qpid
175
187
  # * encoded - the encoded data
176
188
  #
177
189
  def decode(encoded)
178
- check(Cproton.pn_data_decode(@data, encoded))
190
+ check(Cproton.pn_data_decode(@data, encoded, encoded.length))
179
191
  end
180
192
 
181
193
  # Puts a list value.
@@ -208,7 +220,7 @@ module Qpid
208
220
  # @data.enter
209
221
  # (0...count).each
210
222
  # type = @data.next
211
- # puts "Value: #{@data.string}" if type == :STRING
223
+ # puts "Value: #{@data.string}" if type == STRING
212
224
  # # ... process other node types
213
225
  # end
214
226
  def list
@@ -244,10 +256,10 @@ module Qpid
244
256
  # @data.enter
245
257
  # (0...count).each do
246
258
  # type = @data.next
247
- # puts "Key=#{@data.string}" if type == :STRING
259
+ # puts "Key=#{@data.string}" if type == STRING
248
260
  # # ... process other key types
249
261
  # type = @data.next
250
- # puts "Value=#{@data.string}" if type == :STRING
262
+ # puts "Value=#{@data.string}" if type == STRING
251
263
  # # ... process other value types
252
264
  # end
253
265
  # @data.exit
@@ -255,6 +267,10 @@ module Qpid
255
267
  Cproton.pn_data_get_map(@data)
256
268
  end
257
269
 
270
+ def get_map # :nodoc:
271
+ ::Hash.proton_data_get(self)
272
+ end
273
+
258
274
  # Puts an array value.
259
275
  #
260
276
  # Elements may be filled by entering the array node and putting the
@@ -273,7 +289,7 @@ module Qpid
273
289
  #
274
290
  # # create an array of integer values
275
291
  # data = Qpid::Proton::Data.new
276
- # data.put_array(false, :INT)
292
+ # data.put_array(false, INT)
277
293
  # data.enter
278
294
  # data.int = 1
279
295
  # data.int = 2
@@ -281,7 +297,7 @@ module Qpid
281
297
  # data.exit
282
298
  #
283
299
  # # create an array of double values
284
- # data.put_array(true, :DOUBLE)
300
+ # data.put_array(true, DOUBLE)
285
301
  # data.enter
286
302
  # data.symbol = "array-descriptor"
287
303
  # data.double = 1.1
@@ -290,8 +306,7 @@ module Qpid
290
306
  # data.exit
291
307
  #
292
308
  def put_array(described, element_type)
293
- check(Cproton.pn_data_put_array(@data, described,
294
- Data.type_value(element_type)))
309
+ check(Cproton.pn_data_put_array(@data, described, element_type.code))
295
310
  end
296
311
 
297
312
  # If the current node is an array, returns a tuple of the element count, a
@@ -319,12 +334,12 @@ module Qpid
319
334
  count = Cproton.pn_data_get_array(@data)
320
335
  described = Cproton.pn_data_is_array_described(@data)
321
336
  array_type = Cproton.pn_data_get_array_type(@data)
322
- if array_type == -1
323
- array_type = nil
324
- else
325
- array_type = Data.type_name(array_type)
326
- end
327
- [count, described, array_type]
337
+ return nil if array_type == -1
338
+ [count, described, Mapping.for_code(array_type) ]
339
+ end
340
+
341
+ def get_array # :nodoc:
342
+ ::Array.proton_get(self)
328
343
  end
329
344
 
330
345
  # Puts a described value.
@@ -346,6 +361,19 @@ module Qpid
346
361
  check(Cproton.pn_data_put_described(@data))
347
362
  end
348
363
 
364
+ def get_described # :nodoc:
365
+ raise TypeError, "not a described type" unless self.described?
366
+ self.enter
367
+ self.next
368
+ type = self.type
369
+ descriptor = type.get(self)
370
+ self.next
371
+ type = self.type
372
+ value = type.get(self)
373
+ self.exit
374
+ Described.new(descriptor, value)
375
+ end
376
+
349
377
  # Checks if the current node is a described value.
350
378
  #
351
379
  # The described and value may be accessed by entering the described value.
@@ -366,6 +394,11 @@ module Qpid
366
394
  check(Cproton.pn_data_put_null(@data))
367
395
  end
368
396
 
397
+ # Utility method for Qpid::Proton::Mapping
398
+ def null=(value) # :nodoc:
399
+ null
400
+ end
401
+
369
402
  # Checks if the current node is null.
370
403
  def null?
371
404
  Cproton.pn_data_is_null(@data)
@@ -719,38 +752,22 @@ module Qpid
719
752
  Cproton.pn_data_get_symbol(@data)
720
753
  end
721
754
 
722
- def self.add_item(key, value, name) # :nodoc:
723
- @@type_value ||= {}
724
- @@type_value[key] = value
725
-
726
- @@type_name ||= {}
727
- @@type_name[value] = key
728
- end
729
-
730
- # Returns the typename for the specified type.
731
- #
732
- # ==== Examples
733
- # # returns "null"
734
- # name = Qpid::Proton::Data.type_name(:NULL)
735
- #
736
- def self.type_name(key)
737
- @@type_name[key]
755
+ # Get the current value as a single object.
756
+ def get
757
+ type.get(self);
738
758
  end
739
759
 
740
- def self.type_value(key) # :nodoc:
741
- @@type_value[key]
742
- end
743
-
744
- def self.const_missing(key) # :nodoc:
745
- @@type_value[key]
760
+ # Put value as an object of type type_
761
+ def put(value, type_);
762
+ type_.put(self, value);
746
763
  end
747
764
 
748
765
  private
749
766
 
750
767
  def valid_uuid?(value)
751
- # ensure that the UUID is in the right format
752
- # xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
753
- value =~ /[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}/
768
+ # ensure that the UUID is in the right format
769
+ # xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
770
+ value =~ /[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}/
754
771
  end
755
772
 
756
773
  def check(err) # :nodoc:
@@ -760,35 +777,6 @@ module Qpid
760
777
  return err
761
778
  end
762
779
  end
763
-
764
- self.add_item(:NULL, Cproton::PN_NULL, "null")
765
- self.add_item(:BOOL, Cproton::PN_BOOL, "bool")
766
- self.add_item(:UBYTE, Cproton::PN_UBYTE, "ubyte")
767
- self.add_item(:BYTE, Cproton::PN_BYTE, "byte")
768
- self.add_item(:USHORT, Cproton::PN_USHORT, "ushort")
769
- self.add_item(:SHORT, Cproton::PN_SHORT, "short")
770
- self.add_item(:UINT, Cproton::PN_UINT, "uint")
771
- self.add_item(:INT, Cproton::PN_INT, "int")
772
- self.add_item(:CHAR, Cproton::PN_CHAR, "char")
773
- self.add_item(:ULONG, Cproton::PN_ULONG, "ulong")
774
- self.add_item(:LONG, Cproton::PN_LONG, "long")
775
- self.add_item(:TIMESTAMP, Cproton::PN_TIMESTAMP, "timestamp")
776
- self.add_item(:FLOAT, Cproton::PN_FLOAT, "float")
777
- self.add_item(:DOUBLE, Cproton::PN_DOUBLE, "double")
778
- self.add_item(:DECIMAL32, Cproton::PN_DECIMAL32, "decimal32")
779
- self.add_item(:DECIMAL64, Cproton::PN_DECIMAL64, "decimal64")
780
- self.add_item(:DECIMAL128, Cproton::PN_DECIMAL128, "decimal128")
781
- self.add_item(:UUID, Cproton::PN_UUID, "uuid")
782
- self.add_item(:BINARY, Cproton::PN_BINARY, "binary")
783
- self.add_item(:STRING, Cproton::PN_STRING, "string")
784
- self.add_item(:SYMBOL, Cproton::PN_SYMBOL, "symbol")
785
- self.add_item(:DESCRIBED, Cproton::PN_DESCRIBED, "described")
786
- self.add_item(:ARRAY, Cproton::PN_ARRAY, "array")
787
- self.add_item(:LIST, Cproton::PN_LIST, "list")
788
- self.add_item(:MAP, Cproton::PN_MAP, "map")
789
-
790
780
  end
791
-
792
781
  end
793
-
794
782
  end