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.
- checksums.yaml +7 -0
- data/ChangeLog +18 -0
- data/ext/cproton/cproton.c +4868 -1733
- data/lib/qpid_proton.rb +5 -0
- data/lib/qpid_proton/array.rb +173 -0
- data/lib/qpid_proton/data.rb +87 -99
- data/lib/qpid_proton/described.rb +66 -0
- data/lib/qpid_proton/exception_handling.rb +3 -0
- data/lib/qpid_proton/exceptions.rb +1 -0
- data/lib/qpid_proton/hash.rb +86 -0
- data/lib/qpid_proton/mapping.rb +142 -0
- data/lib/qpid_proton/message.rb +180 -1
- data/lib/qpid_proton/messenger.rb +60 -51
- metadata +18 -21
@@ -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
|
@@ -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
|
data/lib/qpid_proton/message.rb
CHANGED
@@ -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
|