qpid_proton 0.9.0 → 0.10
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 +4 -4
- data/lib/codec/data.rb +912 -0
- data/lib/codec/mapping.rb +169 -0
- data/lib/{qpid_proton/tracker.rb → core/base_handler.rb} +4 -15
- data/lib/core/connection.rb +328 -0
- data/lib/core/delivery.rb +271 -0
- data/lib/core/disposition.rb +158 -0
- data/lib/core/endpoint.rb +140 -0
- data/lib/{qpid_proton → core}/exceptions.rb +43 -2
- data/lib/core/link.rb +387 -0
- data/lib/core/message.rb +633 -0
- data/lib/core/receiver.rb +95 -0
- data/lib/core/sasl.rb +94 -0
- data/lib/core/selectable.rb +130 -0
- data/lib/core/sender.rb +76 -0
- data/lib/core/session.rb +163 -0
- data/lib/core/ssl.rb +164 -0
- data/lib/{qpid_proton/version.rb → core/ssl_details.rb} +7 -6
- data/lib/core/ssl_domain.rb +156 -0
- data/lib/core/terminus.rb +218 -0
- data/lib/core/transport.rb +411 -0
- data/lib/core/url.rb +77 -0
- data/lib/event/collector.rb +148 -0
- data/lib/event/event.rb +318 -0
- data/lib/event/event_base.rb +91 -0
- data/lib/event/event_type.rb +71 -0
- data/lib/handler/acking.rb +70 -0
- data/lib/handler/c_adaptor.rb +47 -0
- data/lib/handler/c_flow_controller.rb +33 -0
- data/lib/handler/endpoint_state_handler.rb +217 -0
- data/lib/handler/incoming_message_handler.rb +74 -0
- data/lib/handler/messaging_handler.rb +218 -0
- data/lib/handler/outgoing_message_handler.rb +98 -0
- data/lib/handler/wrapped_handler.rb +76 -0
- data/lib/messenger/messenger.rb +702 -0
- data/lib/messenger/subscription.rb +37 -0
- data/lib/messenger/tracker.rb +38 -0
- data/lib/messenger/tracker_status.rb +69 -0
- data/lib/qpid_proton.rb +106 -16
- data/lib/reactor/acceptor.rb +41 -0
- data/lib/reactor/backoff.rb +41 -0
- data/lib/reactor/connector.rb +98 -0
- data/lib/reactor/container.rb +272 -0
- data/lib/reactor/global_overrides.rb +44 -0
- data/lib/reactor/link_option.rb +90 -0
- data/lib/reactor/reactor.rb +198 -0
- data/lib/reactor/session_per_connection.rb +45 -0
- data/lib/reactor/ssl_config.rb +41 -0
- data/lib/reactor/task.rb +39 -0
- data/lib/{qpid_proton/subscription.rb → reactor/urls.rb} +12 -13
- data/lib/{qpid_proton → types}/array.rb +28 -29
- data/lib/types/described.rb +63 -0
- data/lib/{qpid_proton → types}/hash.rb +4 -3
- data/lib/types/strings.rb +62 -0
- data/lib/util/class_wrapper.rb +54 -0
- data/lib/util/condition.rb +45 -0
- data/lib/util/constants.rb +85 -0
- data/lib/util/engine.rb +82 -0
- data/lib/util/error_handler.rb +127 -0
- data/lib/util/handler.rb +41 -0
- data/lib/util/reactor.rb +32 -0
- data/lib/util/swig_helper.rb +114 -0
- data/lib/util/timeout.rb +50 -0
- data/lib/util/uuid.rb +32 -0
- data/lib/util/version.rb +30 -0
- data/lib/util/wrapper.rb +124 -0
- metadata +67 -21
- data/ext/cproton/cproton.c +0 -22196
- data/lib/qpid_proton/data.rb +0 -788
- data/lib/qpid_proton/described.rb +0 -66
- data/lib/qpid_proton/exception_handling.rb +0 -127
- data/lib/qpid_proton/filters.rb +0 -67
- data/lib/qpid_proton/mapping.rb +0 -170
- data/lib/qpid_proton/message.rb +0 -621
- data/lib/qpid_proton/messenger.rb +0 -702
- data/lib/qpid_proton/selectable.rb +0 -126
- data/lib/qpid_proton/strings.rb +0 -65
- data/lib/qpid_proton/tracker_status.rb +0 -73
@@ -1,66 +0,0 @@
|
|
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
|
@@ -1,127 +0,0 @@
|
|
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
|
-
# Provides mixin functionality for dealing with exception conditions.
|
25
|
-
#
|
26
|
-
module ExceptionHandling
|
27
|
-
|
28
|
-
def self.included(base)
|
29
|
-
base.extend(self)
|
30
|
-
|
31
|
-
unless defined? base.to_be_wrapped
|
32
|
-
class << base
|
33
|
-
@@to_be_wrapped = []
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
define_method :method_added do |name|
|
38
|
-
if (!@@to_be_wrapped.nil?) && (@@to_be_wrapped.include? name)
|
39
|
-
@@to_be_wrapped.delete name
|
40
|
-
create_exception_handler_wrapper(name)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
def can_raise_exception(method_names)
|
46
|
-
# coerce the names to be an array
|
47
|
-
Array(method_names).each do |method_name|
|
48
|
-
# if the method doesn't already exist then queue this aliasing
|
49
|
-
unless self.method_defined? method_name
|
50
|
-
@@to_be_wrapped ||= []
|
51
|
-
@@to_be_wrapped << method_name
|
52
|
-
else
|
53
|
-
create_exception_handler_wrapper(method_name)
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
def create_exception_handler_wrapper(method_name)
|
59
|
-
original_method_name = method_name.to_s
|
60
|
-
wrapped_method_name = "_excwrap_#{original_method_name}"
|
61
|
-
alias_method wrapped_method_name, original_method_name
|
62
|
-
define_method original_method_name do |*args, &block|
|
63
|
-
# need to get a reference to the method object itself since
|
64
|
-
# calls to Class.send interfere with Messenger.send
|
65
|
-
method = self.method(wrapped_method_name.to_sym)
|
66
|
-
rc = method.call(*args, &block)
|
67
|
-
check_for_error(rc)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
# Raises an Proton-specific error if a return code is non-zero.
|
72
|
-
#
|
73
|
-
# Expects the class to provide an +error+ method.
|
74
|
-
def check_for_error(code)
|
75
|
-
|
76
|
-
raise ::ArgumentError.new("Invalid error code: #{code}") if code.nil?
|
77
|
-
|
78
|
-
return code if code > 0
|
79
|
-
|
80
|
-
case(code)
|
81
|
-
|
82
|
-
when Qpid::Proton::Error::NONE
|
83
|
-
return
|
84
|
-
|
85
|
-
when Qpid::Proton::Error::EOS
|
86
|
-
raise Qpid::Proton::EOSError.new(self.error)
|
87
|
-
|
88
|
-
when Qpid::Proton::Error::ERROR
|
89
|
-
raise Qpid::Proton::ProtonError.new(self.error)
|
90
|
-
|
91
|
-
when Qpid::Proton::Error::OVERFLOW
|
92
|
-
raise Qpid::Proton::OverflowError.new(self.error)
|
93
|
-
|
94
|
-
when Qpid::Proton::Error::UNDERFLOW
|
95
|
-
raise Qpid::Proton::UnderflowError.new(self.error)
|
96
|
-
|
97
|
-
when Qpid::Proton::Error::ARGUMENT
|
98
|
-
raise Qpid::Proton::ArgumentError.new(self.error)
|
99
|
-
|
100
|
-
when Qpid::Proton::Error::STATE
|
101
|
-
raise Qpid::Proton::StateError.new(self.error)
|
102
|
-
|
103
|
-
when Qpid::Proton::Error::TIMEOUT
|
104
|
-
raise Qpid::Proton::TimeoutError.new(self.error)
|
105
|
-
|
106
|
-
when Qpid::Proton::Error::INPROGRESS
|
107
|
-
return
|
108
|
-
|
109
|
-
when Qpid::Proton::Error::INTERRUPTED
|
110
|
-
raise Qpid::Proton::InterruptedError.new(self.error)
|
111
|
-
|
112
|
-
when Qpid::Proton::Error::INPROGRESS
|
113
|
-
raise Qpid::Proton::InProgressError.new(self.error)
|
114
|
-
|
115
|
-
else
|
116
|
-
|
117
|
-
raise ::ArgumentError.new("Unknown error code: #{code}")
|
118
|
-
|
119
|
-
end
|
120
|
-
|
121
|
-
end
|
122
|
-
|
123
|
-
end
|
124
|
-
|
125
|
-
end
|
126
|
-
|
127
|
-
end
|
data/lib/qpid_proton/filters.rb
DELETED
@@ -1,67 +0,0 @@
|
|
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
|
-
module Filters
|
25
|
-
|
26
|
-
def self.included(base)
|
27
|
-
base.class_eval do
|
28
|
-
extend ClassMethods
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
module ClassMethods
|
33
|
-
|
34
|
-
def method_added(method_name)
|
35
|
-
@@hooked_methods ||= []
|
36
|
-
return if @@hooked_methods.include?(method_name)
|
37
|
-
@@hooked_methods << method_name
|
38
|
-
hooks = @@before_hooks[method_name]
|
39
|
-
return if hooks.nil?
|
40
|
-
orig_method = instance_method(method_name)
|
41
|
-
define_method(method_name) do |*args, &block|
|
42
|
-
hooks = @@before_hooks[method_name]
|
43
|
-
hooks.each do |hook|
|
44
|
-
method(hook).call
|
45
|
-
end
|
46
|
-
|
47
|
-
orig_method.bind(self).call(*args, &block)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
def call_before(before_method, *methods)
|
52
|
-
@@before_hooks ||= {}
|
53
|
-
methods.each do |method|
|
54
|
-
hooks = @@before_hooks[method] || []
|
55
|
-
raise "Repeat filter: #{before_method}" if hooks.include? before_method
|
56
|
-
hooks << before_method
|
57
|
-
@@before_hooks[method] = hooks
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
end
|
62
|
-
|
63
|
-
end
|
64
|
-
|
65
|
-
end
|
66
|
-
|
67
|
-
end
|
data/lib/qpid_proton/mapping.rb
DELETED
@@ -1,170 +0,0 @@
|
|
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
|
-
UTFString,
|
111
|
-
BinaryString])
|
112
|
-
|
113
|
-
class << STRING # :nodoc:
|
114
|
-
def put(data, value)
|
115
|
-
# if we have a symbol then convert it to a string
|
116
|
-
value = value.to_s if value.is_a?(Symbol)
|
117
|
-
|
118
|
-
isutf = false
|
119
|
-
|
120
|
-
if value.is_a?(Qpid::Proton::UTFString)
|
121
|
-
isutf = true
|
122
|
-
else
|
123
|
-
# For Ruby 1.8 we will just treat all strings as binary.
|
124
|
-
# For Ruby 1.9+ we can check the encoding first to see what it is
|
125
|
-
if RUBY_VERSION >= "1.9"
|
126
|
-
# If the string is ASCII-8BIT then treat is as binary. Otherwise,
|
127
|
-
# try to convert it to UTF-8 and, if successful, send as that.
|
128
|
-
if value.encoding != Encoding::ASCII_8BIT &&
|
129
|
-
value.encode(Encoding::UTF_8).valid_encoding?
|
130
|
-
isutf = true
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
data.string = value if isutf
|
136
|
-
data.binary = value if !isutf
|
137
|
-
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
SYMBOL = Mapping.new(Cproton::PN_SYMBOL, "symbol")
|
142
|
-
DESCRIBED = Mapping.new(Cproton::PN_DESCRIBED, "described", [Qpid::Proton::Described], "get_described")
|
143
|
-
ARRAY = Mapping.new(Cproton::PN_ARRAY, "array", nil, "get_array")
|
144
|
-
LIST = Mapping.new(Cproton::PN_LIST, "list", [::Array], "get_array")
|
145
|
-
MAP = Mapping.new(Cproton::PN_MAP, "map", [::Hash], "get_map")
|
146
|
-
|
147
|
-
class << MAP # :nodoc:
|
148
|
-
def put(data, map, options = {})
|
149
|
-
data.put_map
|
150
|
-
data.enter
|
151
|
-
map.each_pair do |key, value|
|
152
|
-
if options[:keys] == :SYMBOL
|
153
|
-
SYMBOL.put(data, key)
|
154
|
-
else
|
155
|
-
Mapping.for_class(key.class).put(data, key)
|
156
|
-
end
|
157
|
-
|
158
|
-
if value.nil?
|
159
|
-
data.null
|
160
|
-
else
|
161
|
-
Mapping.for_class(value.class).put(data, value)
|
162
|
-
end
|
163
|
-
end
|
164
|
-
data.exit
|
165
|
-
end
|
166
|
-
end
|
167
|
-
|
168
|
-
end
|
169
|
-
|
170
|
-
end
|
data/lib/qpid_proton/message.rb
DELETED
@@ -1,621 +0,0 @@
|
|
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
|
-
# A Message represents an addressable quantity of data.
|
25
|
-
#
|
26
|
-
# ==== Message Body
|
27
|
-
#
|
28
|
-
# The message body can be set using the #body= method. The message will
|
29
|
-
# then attempt to determine how exactly to encode the content.
|
30
|
-
#
|
31
|
-
# ==== Examples
|
32
|
-
#
|
33
|
-
# To create a message for sending:
|
34
|
-
#
|
35
|
-
# # send a simple text message
|
36
|
-
# msg = Qpid::Proton::Message.new
|
37
|
-
# msg.body = "STATE: update"
|
38
|
-
#
|
39
|
-
# # send a binary chunk of data
|
40
|
-
# data = File.binread("/home/qpid/binfile.tar.gz")
|
41
|
-
# msg = Qpid::Proton::Message.new
|
42
|
-
# msg.body = Qpid::Proton::BinaryString.new(data)
|
43
|
-
#
|
44
|
-
class Message
|
45
|
-
|
46
|
-
# Decodes a message from supplied AMQP data and returns the number
|
47
|
-
# of bytes consumed.
|
48
|
-
#
|
49
|
-
# ==== Options
|
50
|
-
#
|
51
|
-
# * encoded - the encoded data
|
52
|
-
#
|
53
|
-
def decode(encoded)
|
54
|
-
check(Cproton.pn_message_decode(@impl, encoded, encoded.length))
|
55
|
-
|
56
|
-
post_decode
|
57
|
-
end
|
58
|
-
|
59
|
-
def post_decode # :nodoc:
|
60
|
-
# decode elements from the message
|
61
|
-
@properties = {}
|
62
|
-
props = Qpid::Proton::Data.new(Cproton::pn_message_properties(@impl))
|
63
|
-
if props.next
|
64
|
-
@properties = props.type.get(props)
|
65
|
-
end
|
66
|
-
@instructions = nil
|
67
|
-
insts = Qpid::Proton::Data.new(Cproton::pn_message_instructions(@impl))
|
68
|
-
if insts.next
|
69
|
-
@instructions = insts.type.get(insts)
|
70
|
-
end
|
71
|
-
@annotations = nil
|
72
|
-
annts = Qpid::Proton::Data.new(Cproton::pn_message_annotations(@impl))
|
73
|
-
if annts.next
|
74
|
-
@annotations = annts.type.get(annts)
|
75
|
-
end
|
76
|
-
@body = nil
|
77
|
-
body = Qpid::Proton::Data.new(Cproton::pn_message_body(@impl))
|
78
|
-
if body.next
|
79
|
-
@body = body.type.get(body)
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
# Encodes the message.
|
84
|
-
def encode
|
85
|
-
pre_encode
|
86
|
-
size = 16
|
87
|
-
loop do
|
88
|
-
error, data = Cproton::pn_message_encode(@impl, size)
|
89
|
-
if error == Qpid::Proton::Error::OVERFLOW
|
90
|
-
size *= 2
|
91
|
-
else
|
92
|
-
check(error)
|
93
|
-
return data
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
def pre_encode # :nodoc:
|
99
|
-
# encode elements from the message
|
100
|
-
props = Qpid::Proton::Data.new(Cproton::pn_message_properties(@impl))
|
101
|
-
props.clear
|
102
|
-
Qpid::Proton::Mapping.for_class(@properties.class).put(props, @properties) unless @properties.empty?
|
103
|
-
insts = Qpid::Proton::Data.new(Cproton::pn_message_instructions(@impl))
|
104
|
-
insts.clear
|
105
|
-
if !@instructions.nil?
|
106
|
-
mapping = Qpid::Proton::Mapping.for_class(@instructions.class)
|
107
|
-
mapping.put(insts, @instructions)
|
108
|
-
end
|
109
|
-
annts = Qpid::Proton::Data.new(Cproton::pn_message_annotations(@impl))
|
110
|
-
annts.clear
|
111
|
-
if !@annotations.nil?
|
112
|
-
mapping = Qpid::Proton::Mapping.for_class(@annotations.class)
|
113
|
-
mapping.put(annts, @annotations, :keys => :SYMBOL)
|
114
|
-
end
|
115
|
-
body = Qpid::Proton::Data.new(Cproton::pn_message_body(@impl))
|
116
|
-
body.clear
|
117
|
-
if !@body.nil?
|
118
|
-
mapping = Qpid::Proton::Mapping.for_class(@body.class)
|
119
|
-
mapping.put(body, @body)
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
# Creates a new +Message+ instance.
|
124
|
-
def initialize
|
125
|
-
@impl = Cproton.pn_message
|
126
|
-
ObjectSpace.define_finalizer(self, self.class.finalize!(@impl))
|
127
|
-
@properties = {}
|
128
|
-
@instructions = {}
|
129
|
-
@annotations = {}
|
130
|
-
@body = nil
|
131
|
-
end
|
132
|
-
|
133
|
-
def to_s
|
134
|
-
tmp = Cproton.pn_string("")
|
135
|
-
Cproton.pn_inspect(@impl, tmp)
|
136
|
-
result = Cproton.pn_string_get(tmp)
|
137
|
-
Cproton.pn_free(tmp)
|
138
|
-
return result
|
139
|
-
end
|
140
|
-
|
141
|
-
# Invoked by garbage collection to clean up resources used
|
142
|
-
# by the underlying message implementation.
|
143
|
-
def self.finalize!(impl) # :nodoc:
|
144
|
-
proc {
|
145
|
-
Cproton.pn_message_free(impl)
|
146
|
-
}
|
147
|
-
end
|
148
|
-
|
149
|
-
# Returns the underlying message implementation.
|
150
|
-
def impl # :nodoc:
|
151
|
-
@impl
|
152
|
-
end
|
153
|
-
|
154
|
-
# Clears the state of the +Message+. This allows a single instance of
|
155
|
-
# +Message+ to be reused.
|
156
|
-
#
|
157
|
-
def clear
|
158
|
-
Cproton.pn_message_clear(@impl)
|
159
|
-
@properties.clear unless @properties.nil?
|
160
|
-
@instructions.clear unless @instructions.nil?
|
161
|
-
@annotations.clear unless @annotations.nil?
|
162
|
-
@body = nil
|
163
|
-
end
|
164
|
-
|
165
|
-
# Returns the most recent error number.
|
166
|
-
#
|
167
|
-
def errno
|
168
|
-
Cproton.pn_message_errno(@impl)
|
169
|
-
end
|
170
|
-
|
171
|
-
# Returns the most recent error message.
|
172
|
-
#
|
173
|
-
def error
|
174
|
-
Cproton.pn_error_text(Cproton.pn_message_error(@impl))
|
175
|
-
end
|
176
|
-
|
177
|
-
# Returns whether there is currently an error reported.
|
178
|
-
#
|
179
|
-
def error?
|
180
|
-
!Cproton.pn_message_errno(@impl).zero?
|
181
|
-
end
|
182
|
-
|
183
|
-
# Sets the durable flag.
|
184
|
-
#
|
185
|
-
# See ::durable for more details on message durability.
|
186
|
-
#
|
187
|
-
# ==== Options
|
188
|
-
#
|
189
|
-
# * state - the durable state
|
190
|
-
#
|
191
|
-
def durable=(state)
|
192
|
-
raise TypeError.new("state cannot be nil") if state.nil?
|
193
|
-
Cproton.pn_message_set_durable(@impl, state)
|
194
|
-
end
|
195
|
-
|
196
|
-
# Returns the durable property.
|
197
|
-
#
|
198
|
-
# The durable property indicates that the emessage should be held durably
|
199
|
-
# by any intermediaries taking responsibility for the message.
|
200
|
-
#
|
201
|
-
# ==== Examples
|
202
|
-
#
|
203
|
-
# msg = Qpid::Proton::Message.new
|
204
|
-
# msg.durable = true
|
205
|
-
#
|
206
|
-
def durable
|
207
|
-
Cproton.pn_message_is_durable(@impl)
|
208
|
-
end
|
209
|
-
|
210
|
-
# Sets the priority.
|
211
|
-
#
|
212
|
-
# +NOTE:+ Priority values are limited to the range [0,255].
|
213
|
-
#
|
214
|
-
# ==== Options
|
215
|
-
#
|
216
|
-
# * priority - the priority value
|
217
|
-
#
|
218
|
-
def priority=(priority)
|
219
|
-
raise TypeError.new("invalid priority: #{priority}") if priority.nil? || !([Float, Fixnum].include?(priority.class))
|
220
|
-
raise RangeError.new("priority out of range: #{priority}") if ((priority > 255) || (priority < 0))
|
221
|
-
Cproton.pn_message_set_priority(@impl, priority.floor)
|
222
|
-
end
|
223
|
-
|
224
|
-
# Returns the priority.
|
225
|
-
#
|
226
|
-
def priority
|
227
|
-
Cproton.pn_message_get_priority(@impl)
|
228
|
-
end
|
229
|
-
|
230
|
-
# Sets the time-to-live for the message.
|
231
|
-
#
|
232
|
-
# ==== Options
|
233
|
-
#
|
234
|
-
# * time - the time in milliseconds
|
235
|
-
#
|
236
|
-
def ttl=(time)
|
237
|
-
raise TypeError.new("invalid ttl: #{time}") if time.nil? || !([Float, Fixnum].include?(time.class))
|
238
|
-
raise RangeError.new("time out of range: #{time}") if ((time < 0))
|
239
|
-
Cproton.pn_message_set_ttl(@impl, time.floor)
|
240
|
-
end
|
241
|
-
|
242
|
-
# Returns the time-to-live, in milliseconds.
|
243
|
-
#
|
244
|
-
def ttl
|
245
|
-
Cproton.pn_message_get_ttl(@impl)
|
246
|
-
end
|
247
|
-
|
248
|
-
# Sets whether this is the first time the message was acquired.
|
249
|
-
#
|
250
|
-
# See ::first_acquirer? for more details.
|
251
|
-
#
|
252
|
-
# ==== Options
|
253
|
-
#
|
254
|
-
# * state - true if claiming the message
|
255
|
-
#
|
256
|
-
def first_acquirer=(state)
|
257
|
-
raise TypeError.new("invalid state: #{state}") if state.nil? || !([TrueClass, FalseClass].include?(state.class))
|
258
|
-
Cproton.pn_message_set_first_acquirer(@impl, state)
|
259
|
-
end
|
260
|
-
|
261
|
-
# Sets the delivery count for the message.
|
262
|
-
#
|
263
|
-
# See ::delivery_count for more details.
|
264
|
-
#
|
265
|
-
# ==== Options
|
266
|
-
#
|
267
|
-
# * count - the delivery count
|
268
|
-
#
|
269
|
-
def delivery_count=(count)
|
270
|
-
raise ArgumentError.new("invalid count: #{count}") if count.nil? || !([Float, Fixnum].include?(count.class))
|
271
|
-
raise RangeError.new("count out of range: #{count}") if count < 0
|
272
|
-
|
273
|
-
Cproton.pn_message_set_delivery_count(@impl, count.floor)
|
274
|
-
end
|
275
|
-
|
276
|
-
# Returns the delivery count for the message.
|
277
|
-
#
|
278
|
-
# This is the number of delivery attempts for the given message.
|
279
|
-
#
|
280
|
-
def delivery_count
|
281
|
-
Cproton.pn_message_get_delivery_count(@impl)
|
282
|
-
end
|
283
|
-
|
284
|
-
# Returns whether this is the first acquirer.
|
285
|
-
#
|
286
|
-
#
|
287
|
-
def first_acquirer?
|
288
|
-
Cproton.pn_message_is_first_acquirer(@impl)
|
289
|
-
end
|
290
|
-
|
291
|
-
# Sets the message id.
|
292
|
-
#
|
293
|
-
# ==== Options
|
294
|
-
#
|
295
|
-
# * id = the id
|
296
|
-
#
|
297
|
-
def id=(id)
|
298
|
-
Cproton.pn_message_set_id(@impl, id)
|
299
|
-
end
|
300
|
-
|
301
|
-
# Returns the message id.
|
302
|
-
#
|
303
|
-
def id
|
304
|
-
Cproton.pn_message_get_id(@impl)
|
305
|
-
end
|
306
|
-
|
307
|
-
# Sets the user id.
|
308
|
-
#
|
309
|
-
# ==== Options
|
310
|
-
#
|
311
|
-
# * id - the user id
|
312
|
-
#
|
313
|
-
def user_id=(id)
|
314
|
-
Cproton.pn_message_set_user_id(@impl, id)
|
315
|
-
end
|
316
|
-
|
317
|
-
# Returns the user id.
|
318
|
-
#
|
319
|
-
def user_id
|
320
|
-
Cproton.pn_message_get_user_id(@impl)
|
321
|
-
end
|
322
|
-
|
323
|
-
# Sets the destination address.
|
324
|
-
#
|
325
|
-
# ==== Options
|
326
|
-
#
|
327
|
-
# * address - the address
|
328
|
-
#
|
329
|
-
def address=(address)
|
330
|
-
Cproton.pn_message_set_address(@impl, address)
|
331
|
-
end
|
332
|
-
|
333
|
-
# Returns the destination address.
|
334
|
-
#
|
335
|
-
def address
|
336
|
-
Cproton.pn_message_get_address(@impl)
|
337
|
-
end
|
338
|
-
|
339
|
-
# Sets the subject.
|
340
|
-
#
|
341
|
-
# ==== Options
|
342
|
-
#
|
343
|
-
# * subject - the subject
|
344
|
-
#
|
345
|
-
def subject=(subject)
|
346
|
-
Cproton.pn_message_set_subject(@impl, subject)
|
347
|
-
end
|
348
|
-
|
349
|
-
# Returns the subject
|
350
|
-
#
|
351
|
-
def subject
|
352
|
-
Cproton.pn_message_get_subject(@impl)
|
353
|
-
end
|
354
|
-
|
355
|
-
# Sets the reply-to address.
|
356
|
-
#
|
357
|
-
# ==== Options
|
358
|
-
#
|
359
|
-
# * address - the reply-to address
|
360
|
-
#
|
361
|
-
def reply_to=(address)
|
362
|
-
Cproton.pn_message_set_reply_to(@impl, address)
|
363
|
-
end
|
364
|
-
|
365
|
-
# Returns the reply-to address
|
366
|
-
#
|
367
|
-
def reply_to
|
368
|
-
Cproton.pn_message_get_reply_to(@impl)
|
369
|
-
end
|
370
|
-
|
371
|
-
# Sets the correlation id.
|
372
|
-
#
|
373
|
-
# ==== Options
|
374
|
-
#
|
375
|
-
# * id - the correlation id
|
376
|
-
#
|
377
|
-
def correlation_id=(id)
|
378
|
-
Cproton.pn_message_set_correlation_id(@impl, id)
|
379
|
-
end
|
380
|
-
|
381
|
-
# Returns the correlation id.
|
382
|
-
#
|
383
|
-
def correlation_id
|
384
|
-
Cproton.pn_message_get_correlation_id(@impl)
|
385
|
-
end
|
386
|
-
|
387
|
-
# Sets the message format.
|
388
|
-
#
|
389
|
-
# See MessageFormat for more details on formats.
|
390
|
-
#
|
391
|
-
# *Warning:* This method has been deprecated.
|
392
|
-
#
|
393
|
-
# ==== Options
|
394
|
-
#
|
395
|
-
# * format - the format
|
396
|
-
#
|
397
|
-
def format=(format)
|
398
|
-
raise TypeError.new("invalid message format: #{format}") if (format.nil? || !format.kind_of?(Qpid::Proton::MessageFormat))
|
399
|
-
Cproton.pn_message_set_format(@impl, format.value)
|
400
|
-
end
|
401
|
-
|
402
|
-
# Returns the message format
|
403
|
-
#
|
404
|
-
# *Warning:* This method has been deprecated.
|
405
|
-
#
|
406
|
-
# ==== Note
|
407
|
-
#
|
408
|
-
# This method is now deprecated.
|
409
|
-
#
|
410
|
-
def format
|
411
|
-
Qpid::Proton::MessageFormat.by_value(Cproton.pn_message_get_format(@impl))
|
412
|
-
end
|
413
|
-
|
414
|
-
# Sets the content type.
|
415
|
-
#
|
416
|
-
# ==== Options
|
417
|
-
#
|
418
|
-
# * content_type - the content type
|
419
|
-
#
|
420
|
-
def content_type=(content_type)
|
421
|
-
Cproton.pn_message_set_content_type(@impl, content_type)
|
422
|
-
end
|
423
|
-
|
424
|
-
# Returns the content type
|
425
|
-
#
|
426
|
-
def content_type
|
427
|
-
Cproton.pn_message_get_content_type(@impl)
|
428
|
-
end
|
429
|
-
|
430
|
-
# Sets the content encoding type.
|
431
|
-
#
|
432
|
-
# ==== Options
|
433
|
-
#
|
434
|
-
# * encoding - the content encoding
|
435
|
-
#
|
436
|
-
def content_encoding=(encoding)
|
437
|
-
Cproton.pn_message_set_content_encoding(@impl, encoding)
|
438
|
-
end
|
439
|
-
|
440
|
-
# Returns the content encoding type.
|
441
|
-
#
|
442
|
-
def content_encoding
|
443
|
-
Cproton.pn_message_get_content_encoding(@impl)
|
444
|
-
end
|
445
|
-
|
446
|
-
# Sets the expiration time.
|
447
|
-
#
|
448
|
-
# ==== Options
|
449
|
-
#
|
450
|
-
# * time - the expiry time
|
451
|
-
#
|
452
|
-
def expires=(time)
|
453
|
-
raise TypeError.new("invalid expiry time: #{time}") if time.nil?
|
454
|
-
raise ArgumentError.new("expiry time cannot be negative: #{time}") if time < 0
|
455
|
-
Cproton.pn_message_set_expiry_time(@impl, time)
|
456
|
-
end
|
457
|
-
|
458
|
-
# Returns the expiration time.
|
459
|
-
#
|
460
|
-
def expires
|
461
|
-
Cproton.pn_message_get_expiry_time(@impl)
|
462
|
-
end
|
463
|
-
|
464
|
-
# Sets the creation time.
|
465
|
-
#
|
466
|
-
# ==== Options
|
467
|
-
#
|
468
|
-
# * time - the creation time
|
469
|
-
#
|
470
|
-
def creation_time=(time)
|
471
|
-
raise TypeError.new("invalid time: #{time}") if time.nil?
|
472
|
-
raise ArgumentError.new("time cannot be negative") if time < 0
|
473
|
-
Cproton.pn_message_set_creation_time(@impl, time)
|
474
|
-
end
|
475
|
-
|
476
|
-
# Returns the creation time.
|
477
|
-
#
|
478
|
-
def creation_time
|
479
|
-
Cproton.pn_message_get_creation_time(@impl)
|
480
|
-
end
|
481
|
-
|
482
|
-
# Sets the group id.
|
483
|
-
#
|
484
|
-
# ==== Options
|
485
|
-
#
|
486
|
-
# * id - the group id
|
487
|
-
#
|
488
|
-
def group_id=(id)
|
489
|
-
Cproton.pn_message_set_group_id(@impl, id)
|
490
|
-
end
|
491
|
-
|
492
|
-
# Returns the group id.
|
493
|
-
#
|
494
|
-
def group_id
|
495
|
-
Cproton.pn_message_get_group_id(@impl)
|
496
|
-
end
|
497
|
-
|
498
|
-
# Sets the group sequence number.
|
499
|
-
#
|
500
|
-
# ==== Options
|
501
|
-
#
|
502
|
-
# * seq - the sequence number
|
503
|
-
#
|
504
|
-
def group_sequence=(seq)
|
505
|
-
raise TypeError.new("invalid seq: #{seq}") if seq.nil?
|
506
|
-
Cproton.pn_message_set_group_sequence(@impl, seq)
|
507
|
-
end
|
508
|
-
|
509
|
-
# Returns the group sequence number.
|
510
|
-
#
|
511
|
-
def group_sequence
|
512
|
-
Cproton.pn_message_get_group_sequence(@impl)
|
513
|
-
end
|
514
|
-
|
515
|
-
# Sets the reply-to group id.
|
516
|
-
#
|
517
|
-
# ==== Options
|
518
|
-
#
|
519
|
-
# * id - the id
|
520
|
-
#
|
521
|
-
def reply_to_group_id=(id)
|
522
|
-
Cproton.pn_message_set_reply_to_group_id(@impl, id)
|
523
|
-
end
|
524
|
-
|
525
|
-
# Returns the reply-to group id.
|
526
|
-
#
|
527
|
-
def reply_to_group_id
|
528
|
-
Cproton.pn_message_get_reply_to_group_id(@impl)
|
529
|
-
end
|
530
|
-
|
531
|
-
# Returns the list of property names for associated with this message.
|
532
|
-
#
|
533
|
-
# ==== Examples
|
534
|
-
#
|
535
|
-
# msg.properties.each do |name|
|
536
|
-
# end
|
537
|
-
#
|
538
|
-
def properties
|
539
|
-
@properties
|
540
|
-
end
|
541
|
-
|
542
|
-
# Replaces the entire set of properties with the specified hash.
|
543
|
-
#
|
544
|
-
def properties=(properties)
|
545
|
-
@properties = properties
|
546
|
-
end
|
547
|
-
|
548
|
-
# Assigns the value given to the named property.
|
549
|
-
#
|
550
|
-
# ==== Arguments
|
551
|
-
#
|
552
|
-
# * name - the property name
|
553
|
-
# * value - the property value
|
554
|
-
#
|
555
|
-
def []=(name, value)
|
556
|
-
@properties[name] = value
|
557
|
-
end
|
558
|
-
|
559
|
-
# Retrieves the value for the specified property name. If not found, then
|
560
|
-
# it returns nil.
|
561
|
-
#
|
562
|
-
def [](name)
|
563
|
-
@properties[name]
|
564
|
-
end
|
565
|
-
|
566
|
-
# Deletes the named property.
|
567
|
-
#
|
568
|
-
def delete_property(name)
|
569
|
-
@properties.delete(name)
|
570
|
-
end
|
571
|
-
|
572
|
-
# Returns the instructions for this message.
|
573
|
-
#
|
574
|
-
def instructions
|
575
|
-
@instructions
|
576
|
-
end
|
577
|
-
|
578
|
-
# Assigns instructions to this message.
|
579
|
-
#
|
580
|
-
def instructions=(instr)
|
581
|
-
@instructions = instr
|
582
|
-
end
|
583
|
-
|
584
|
-
# Returns the annotations for this message.
|
585
|
-
#
|
586
|
-
def annotations
|
587
|
-
@annotations
|
588
|
-
end
|
589
|
-
|
590
|
-
# Assigns annotations to this message.
|
591
|
-
#
|
592
|
-
def annotations=(annotations)
|
593
|
-
@annotations = annotations
|
594
|
-
end
|
595
|
-
|
596
|
-
# Returns the body property of the message.
|
597
|
-
#
|
598
|
-
def body
|
599
|
-
@body
|
600
|
-
end
|
601
|
-
|
602
|
-
# Assigns a new value to the body of the message.
|
603
|
-
#
|
604
|
-
def body=(body)
|
605
|
-
@body = body
|
606
|
-
end
|
607
|
-
|
608
|
-
private
|
609
|
-
|
610
|
-
def check(err) # :nodoc:
|
611
|
-
if err < 0
|
612
|
-
raise DataError, "[#{err}]: #{Cproton.pn_message_error(@impl)}"
|
613
|
-
else
|
614
|
-
return err
|
615
|
-
end
|
616
|
-
end
|
617
|
-
end
|
618
|
-
|
619
|
-
end
|
620
|
-
|
621
|
-
end
|