qpid_proton 0.4 → 0.5

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