qpid_proton 0.4 → 0.5

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