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.
@@ -0,0 +1,66 @@
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 # :nodoc:
21
+
22
+ module Proton # :nodoc:
23
+
24
+ class Described
25
+
26
+ attr_reader :descriptor
27
+ attr_reader :value
28
+
29
+ def initialize(descriptor, value)
30
+ @descriptor = descriptor
31
+ @value = value
32
+ end
33
+
34
+ # Puts the description into the Data object.
35
+ #
36
+ # ==== Arguments
37
+ #
38
+ # * data - the Qpid::Proton::Data instance
39
+ #
40
+ # ==== Examples
41
+ #
42
+ # described = Qpid::Proton::Described.new("my-descriptor", "the value")
43
+ # data = Qpid::Proton::Data.new
44
+ # ...
45
+ # described.put(data)
46
+ #
47
+ def put(data)
48
+ data.symbol = @descriptor
49
+ data.string = @value
50
+ end
51
+
52
+ def ==(that) # :nodoc:
53
+ (that.is_a?(Qpid::Proton::Described) &&
54
+ (self.descriptor == that.descriptor) &&
55
+ (self.value == that.value))
56
+ end
57
+
58
+ def to_s # :nodoc:
59
+ "descriptor=#{descriptor} value=#{value}"
60
+ end
61
+
62
+ end
63
+
64
+ end
65
+
66
+ end
@@ -54,6 +54,9 @@ module Qpid
54
54
  when Qpid::Proton::Error::TIMEOUT
55
55
  raise Qpid::Proton::TimeoutError.new(self.error)
56
56
 
57
+ when Qpid::Proton::Error::INPROGRESS
58
+ return
59
+
57
60
  else
58
61
 
59
62
  raise ::ArgumentError.new("Unknown error code: #{code}")
@@ -31,6 +31,7 @@ module Qpid
31
31
  STATE = Cproton::PN_STATE_ERR
32
32
  ARGUMENT = Cproton::PN_ARG_ERR
33
33
  TIMEOUT = Cproton::PN_TIMEOUT
34
+ INPROGRESS = Cproton::PN_INPROGRESS
34
35
 
35
36
  end
36
37
 
@@ -0,0 +1,86 @@
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 Hash class to provide methods for adding its contents
22
+ # to a Qpid::Proton::Data instance.
23
+ #++
24
+
25
+ class Hash
26
+
27
+ # Places the contents of the hash into the specified data object.
28
+ #
29
+ # ==== Arguments
30
+ #
31
+ # * data - the Qpid::Proton::Data instance
32
+ #
33
+ # ==== Examples
34
+ #
35
+ # data = Qpid::Proton::Data.new
36
+ # values = {:foo => :bar}
37
+ # values.proton_data_put(data)
38
+ #
39
+ def proton_data_put(data)
40
+ raise TypeError, "data object cannot be nil" if data.nil?
41
+
42
+ data.put_map
43
+ data.enter
44
+
45
+ each_pair do |key, value|
46
+ type = Qpid::Proton::Mapping.for_class(key.class)
47
+ type.put(data, key)
48
+ type = Qpid::Proton::Mapping.for_class(value.class)
49
+ type.put(data, value)
50
+ end
51
+
52
+ data.exit
53
+ end
54
+
55
+ class << self
56
+
57
+ def proton_data_get(data)
58
+ raise TypeError, "data object cannot be nil" if data.nil?
59
+
60
+ type = data.type
61
+
62
+ raise TypeError, "element is not a map" unless type == Qpid::Proton::MAP
63
+
64
+ count = data.map
65
+ result = {}
66
+
67
+ data.enter
68
+
69
+ (0...(count/2)).each do
70
+ data.next
71
+ type = data.type
72
+ key = type.get(data)
73
+ data.next
74
+ type = data.type
75
+ value = type.get(data)
76
+ result[key] = value
77
+ end
78
+
79
+ data.exit
80
+
81
+ return result
82
+ end
83
+
84
+ end
85
+
86
+ end
@@ -0,0 +1,142 @@
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 # :nodoc:
21
+
22
+ module Proton # :nodoc:
23
+
24
+ # Maps between Proton types and their Ruby native language counterparts.
25
+ #
26
+ class Mapping
27
+
28
+ attr_reader :code
29
+ attr_reader :put_method
30
+ attr_reader :get_method
31
+
32
+ # Creates a new mapping.
33
+ #
34
+ # ==== Arguments
35
+ #
36
+ # * code - the AMQP code for this type
37
+ # * name - the AMQP name for this type
38
+ # * klasses - the Ruby classes for this type
39
+ # * getter - overrides the get method for the type
40
+ def initialize(code, name, klasses = nil, getter = nil)
41
+
42
+ @debug = (name == "bool")
43
+
44
+ @code = code
45
+ @name = name
46
+
47
+ @@by_preferred ||= {}
48
+ @@by_code ||= {}
49
+ @@by_code["#{code}"] = self
50
+ @@by_name ||= {}
51
+ @@by_name[name] = self
52
+ @@by_class ||= {}
53
+
54
+ unless klasses.nil?
55
+ klasses.each do |klass|
56
+ raise "entry exists for #{klass}" if @@by_class.keys.include? klass
57
+ @@by_class[klass] = self unless klass.nil?
58
+ end
59
+ end
60
+
61
+ @put_method = (name + "=").intern
62
+
63
+ if getter.nil?
64
+ @get_method = name.intern
65
+ else
66
+ @get_method = getter.intern
67
+ end
68
+ end
69
+
70
+ def to_s; @name; end
71
+
72
+ def put(data, value)
73
+ data.send(@put_method, value)
74
+ end
75
+
76
+ def get(data)
77
+ data.send(@get_method)
78
+ end
79
+
80
+ def self.for_class(klass) # :nodoc:
81
+ @@by_class[klass]
82
+ end
83
+
84
+ def self.for_code(code)
85
+ @@by_code["#{code}"]
86
+ end
87
+
88
+ end
89
+
90
+ NULL = Mapping.new(Cproton::PN_NULL, "null", [NilClass], "nil?")
91
+ BOOL = Mapping.new(Cproton::PN_BOOL, "bool", [TrueClass, FalseClass], "bool")
92
+ UBYTE = Mapping.new(Cproton::PN_UBYTE, "ubyte")
93
+ BYTE = Mapping.new(Cproton::PN_BYTE, "byte")
94
+ USHORT = Mapping.new(Cproton::PN_USHORT, "ushort")
95
+ SHORT = Mapping.new(Cproton::PN_SHORT, "short")
96
+ UINT = Mapping.new(Cproton::PN_UINT, "uint")
97
+ INT = Mapping.new(Cproton::PN_INT, "int")
98
+ CHAR = Mapping.new(Cproton::PN_CHAR, "char")
99
+ ULONG = Mapping.new(Cproton::PN_ULONG, "ulong")
100
+ LONG = Mapping.new(Cproton::PN_LONG, "long", [Fixnum, Bignum])
101
+ TIMESTAMP = Mapping.new(Cproton::PN_TIMESTAMP, "timestamp", [Date, Time])
102
+ FLOAT = Mapping.new(Cproton::PN_FLOAT, "float")
103
+ DOUBLE = Mapping.new(Cproton::PN_DOUBLE, "double", [Float])
104
+ DECIMAL32 = Mapping.new(Cproton::PN_DECIMAL32, "decimal32")
105
+ DECIMAL64 = Mapping.new(Cproton::PN_DECIMAL64, "decimal64")
106
+ DECIMAL128 = Mapping.new(Cproton::PN_DECIMAL128, "decimal128")
107
+ UUID = Mapping.new(Cproton::PN_UUID, "uuid")
108
+ BINARY = Mapping.new(Cproton::PN_BINARY, "binary")
109
+ STRING = Mapping.new(Cproton::PN_STRING, "string", [String, Symbol])
110
+
111
+ class << STRING
112
+ def put(data, value)
113
+ data.string = value.to_s
114
+ end
115
+ end
116
+
117
+ SYMBOL = Mapping.new(Cproton::PN_SYMBOL, "symbol")
118
+ DESCRIBED = Mapping.new(Cproton::PN_DESCRIBED, "described", [Qpid::Proton::Described], "get_described")
119
+ ARRAY = Mapping.new(Cproton::PN_ARRAY, "array", nil, "get_array")
120
+ LIST = Mapping.new(Cproton::PN_LIST, "list", [::Array], "get_array")
121
+ MAP = Mapping.new(Cproton::PN_MAP, "map", [::Hash], "get_map")
122
+
123
+ class << MAP
124
+ def put(data, map)
125
+ data.put_map
126
+ data.enter
127
+ map.each_pair do |key, value|
128
+ Mapping.for_class(key.class).put(data, key)
129
+
130
+ if value.nil?
131
+ data.null
132
+ else
133
+ Mapping.for_class(value.class).put(data, value)
134
+ end
135
+ end
136
+ data.exit
137
+ end
138
+ end
139
+
140
+ end
141
+
142
+ end
@@ -27,10 +27,99 @@ module Qpid
27
27
  #
28
28
  class Message
29
29
 
30
+ # Decodes a message from supplied AMQP data and returns the number
31
+ # of bytes consumed.
32
+ #
33
+ # ==== Options
34
+ #
35
+ # * encoded - the encoded data
36
+ #
37
+ def decode(encoded)
38
+ check(Cproton.pn_message_decode(@impl, encoded, encoded.length))
39
+
40
+ post_decode
41
+ end
42
+
43
+ def post_decode # :nodoc:
44
+ # decode elements from the message
45
+ @properties = {}
46
+ props = Qpid::Proton::Data.new(Cproton::pn_message_properties(@impl))
47
+ if props.next
48
+ @properties = props.type.get(props)
49
+ end
50
+ @instructions = nil
51
+ insts = Qpid::Proton::Data.new(Cproton::pn_message_instructions(@impl))
52
+ if insts.next
53
+ @instructions = insts.type.get(insts)
54
+ end
55
+ @annotations = nil
56
+ annts = Qpid::Proton::Data.new(Cproton::pn_message_annotations(@impl))
57
+ if annts.next
58
+ @annotations = annts.type.get(annts)
59
+ end
60
+ @body = nil
61
+ body = Qpid::Proton::Data.new(Cproton::pn_message_body(@impl))
62
+ if body.next
63
+ @body = body.type.get(body)
64
+ end
65
+ end
66
+
67
+ # Encodes the message.
68
+ def encode
69
+ pre_encode
70
+ size = 16
71
+ loop do
72
+ error, data = Cproton::pn_message_encode(@impl, size)
73
+ if error == Qpid::Proton::Error::OVERFLOW
74
+ size *= 2
75
+ else
76
+ check(error)
77
+ return data
78
+ end
79
+ end
80
+ end
81
+
82
+ def pre_encode # :nodoc:
83
+ # encode elements from the message
84
+ props = Qpid::Proton::Data.new(Cproton::pn_message_properties(@impl))
85
+ props.clear
86
+ Qpid::Proton::Mapping.for_class(@properties.class).put(props, @properties) unless @properties.empty?
87
+ insts = Qpid::Proton::Data.new(Cproton::pn_message_instructions(@impl))
88
+ insts.clear
89
+ if !@instructions.nil?
90
+ mapping = Qpid::Proton::Mapping.for_class(@instructions.class)
91
+ mapping.put(insts, @instructions)
92
+ end
93
+ annts = Qpid::Proton::Data.new(Cproton::pn_message_annotations(@impl))
94
+ annts.clear
95
+ if !@annotations.nil?
96
+ mapping = Qpid::Proton::Mapping.for_class(@annotations.class)
97
+ mapping.put(annts, @annotations)
98
+ end
99
+ body = Qpid::Proton::Data.new(Cproton::pn_message_body(@impl))
100
+ body.clear
101
+ if !@body.nil?
102
+ mapping = Qpid::Proton::Mapping.for_class(@body.class)
103
+ mapping.put(body, @body)
104
+ end
105
+ end
106
+
30
107
  # Creates a new +Message+ instance.
31
108
  def initialize
32
109
  @impl = Cproton.pn_message
33
110
  ObjectSpace.define_finalizer(self, self.class.finalize!(@impl))
111
+ @properties = {}
112
+ @instructions = {}
113
+ @annotations = {}
114
+ @body = nil
115
+ end
116
+
117
+ def to_s
118
+ tmp = Cproton.pn_string("")
119
+ Cproton.pn_inspect(@impl, tmp)
120
+ result = Cproton.pn_string_get(tmp)
121
+ Cproton.pn_free(tmp)
122
+ return result
34
123
  end
35
124
 
36
125
  # Invoked by garbage collection to clean up resources used
@@ -51,6 +140,10 @@ module Qpid
51
140
  #
52
141
  def clear
53
142
  Cproton.pn_message_clear(@impl)
143
+ @properties.clear unless @properties.nil?
144
+ @instructions.clear unless @instructions.nil?
145
+ @annotations.clear unless @annotations.nil?
146
+ @body = nil
54
147
  end
55
148
 
56
149
  # Returns the most recent error number.
@@ -62,7 +155,7 @@ module Qpid
62
155
  # Returns the most recent error message.
63
156
  #
64
157
  def error
65
- Cproton.pn_message_error(@impl)
158
+ Cproton.pn_error_text(Cproton.pn_message_error(@impl))
66
159
  end
67
160
 
68
161
  # Returns whether there is currently an error reported.
@@ -427,6 +520,92 @@ module Qpid
427
520
  Cproton.pn_message_get_reply_to_group_id(@impl)
428
521
  end
429
522
 
523
+ # Returns the list of property names for associated with this message.
524
+ #
525
+ # ==== Examples
526
+ #
527
+ # msg.properties.each do |name|
528
+ # end
529
+ #
530
+ def properties
531
+ @properties
532
+ end
533
+
534
+ # Replaces the entire set of properties with the specified hash.
535
+ #
536
+ def properties=(properties)
537
+ @properties = properties
538
+ end
539
+
540
+ # Assigns the value given to the named property.
541
+ #
542
+ # ==== Arguments
543
+ #
544
+ # * name - the property name
545
+ # * value - the property value
546
+ #
547
+ def []=(name, value)
548
+ @properties[name] = value
549
+ end
550
+
551
+ # Retrieves the value for the specified property name. If not found, then
552
+ # it returns nil.
553
+ #
554
+ def [](name)
555
+ @properties[name]
556
+ end
557
+
558
+ # Deletes the named property.
559
+ #
560
+ def delete_property(name)
561
+ @properties.delete(name)
562
+ end
563
+
564
+ # Returns the instructions for this message.
565
+ #
566
+ def instructions
567
+ @instructions
568
+ end
569
+
570
+ # Assigns instructions to this message.
571
+ #
572
+ def instructions=(instr)
573
+ @instructions = instr
574
+ end
575
+
576
+ # Returns the annotations for this message.
577
+ #
578
+ def annotations
579
+ @annotations
580
+ end
581
+
582
+ # Assigns annotations to this message.
583
+ #
584
+ def annotations=(annotations)
585
+ @annotations = annotations
586
+ end
587
+
588
+ # Returns the body property of the message.
589
+ #
590
+ def body
591
+ @body
592
+ end
593
+
594
+ # Assigns a new value to the body of the message.
595
+ #
596
+ def body=(body)
597
+ @body = body
598
+ end
599
+
600
+ private
601
+
602
+ def check(err) # :nodoc:
603
+ if err < 0
604
+ raise DataError, "[#{err}]: #{Cproton.pn_message_error(@data)}"
605
+ else
606
+ return err
607
+ end
608
+ end
430
609
  end
431
610
 
432
611
  end