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