diff options
Diffstat (limited to 'cpp/bindings/qpid/ruby/lib/qpid_messaging')
-rw-r--r-- | cpp/bindings/qpid/ruby/lib/qpid_messaging/address.rb | 200 | ||||
-rw-r--r-- | cpp/bindings/qpid/ruby/lib/qpid_messaging/connection.rb | 189 | ||||
-rw-r--r-- | cpp/bindings/qpid/ruby/lib/qpid_messaging/duration.rb | 128 | ||||
-rw-r--r-- | cpp/bindings/qpid/ruby/lib/qpid_messaging/encoding.rb | 75 | ||||
-rw-r--r-- | cpp/bindings/qpid/ruby/lib/qpid_messaging/message.rb | 353 | ||||
-rw-r--r-- | cpp/bindings/qpid/ruby/lib/qpid_messaging/receiver.rb | 177 | ||||
-rw-r--r-- | cpp/bindings/qpid/ruby/lib/qpid_messaging/sender.rb | 135 | ||||
-rw-r--r-- | cpp/bindings/qpid/ruby/lib/qpid_messaging/session.rb | 264 |
8 files changed, 1521 insertions, 0 deletions
diff --git a/cpp/bindings/qpid/ruby/lib/qpid_messaging/address.rb b/cpp/bindings/qpid/ruby/lib/qpid_messaging/address.rb new file mode 100644 index 0000000000..0879f0fcd1 --- /dev/null +++ b/cpp/bindings/qpid/ruby/lib/qpid_messaging/address.rb @@ -0,0 +1,200 @@ +#-- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +#++ + +module Qpid + + module Messaging + + # Address represents an address to which messages can be sent or from + # which they can be received. + # + # == The +Address+ String + # + # An +Address+ can be described using the following pattern: + # + # <address> [ / <subject> ] ; [ { <key> : <value> , ... } ] + # + # where *address* is a simple name and *subject* is a subject or subject + # pattern. + # + # === Options + # + # The options, enclosed in curly braces, are key:value pairs delimited by + # a comma. The values can be nested maps also enclosed in curly braces. + # Or they can be lists of values, where they are contained within square + # brackets but still comma delimited, such as: + # + # [value1,value2,value3] + # + # The following are the list of supported options: + # + # [create] + # Indicates if the address should be created; values are *always*, + # *never*, *sender* or *reciever*. + # + # [assert] + # Indicates whether or not to assert any specified node properties; + # values are *always*, *never*, *sender* or *receiver*. + # + # [delete] + # Indicates whether or not to delete the addressed node when a sender + # or receiver is cancelled; values are *always*, *never*, *sender* or + # *receiver*. + # + # [node] + # A nested map describing properties for the addressed node. Properties + # are *type* (*topic* or *queue*), *durable* (a boolean), *x-declare* + # (a nested map of amqp 0.10-specific options) and *x-bindings* (nested + # list which specifies a queue, exchange or a binding key and arguments). + # + # [link] + # A nested map through which properties of the link can be specified; + # properties are *durable*, *reliability*, *x-declare*, *x-subscribe* + # and *x-bindings*. + # + # [mode] + # (*For receivers only*) indicates whether the receiver should consume + # or browse messages; values are *consume* (the default) and *browse*. + class Address + + # Creates a new +Address+ from an address string. + # + # ==== Attributes + # + # * +address+ - the address string + # + # ==== Examples + # + # # create a new address for a queue named "my-queue" that will + # # be created if it doesn't already exist + # addr = Qpid::Messaging::Address.new "my-queue;{create:always}" + # + def initialize(address, address_impl = nil) + @address_impl = address_impl || Cqpid::Address.new(address) + end + + def address_impl # :nodoc: + @address_impl + end + + # Returns the name for the +Address+. + # + # ==== Examples + # + # # display the name of the address + # addr = Qpid::Messaging::Address.new "foo;{create:always}" + # # outputs the word 'foo' + # puts addr.name + # + def name; @address_impl.getName; end + + # Sets the name for the +Address+. + # + # ==== Examples + # + # # create a new address with the name "my-queue" + # addr = Qpid::Messaging::Address.new "my-queue/my-subject;{create:always}" + # # changes the name to "my-new-queue" + # addr.name = "my-new-queue" + # + def name=(name); @address_impl.setName name; end + + # Returns the subject for the +Address+. + # + # ==== Examples + # + # # creates a new address with the subject "bar" + # addr = Qpid::Messaging::Address.new "my-queue/bar;{create:always}" + # + def subject; @address_impl.getSubject; end + + # Sets the subject for the +Address+. + # + # ==== Examples + # + # # creates an address with the subject "example" + # addr = Qpid::Messaging::Address.new "my-queue/example;{create:always}" + # # changes the subject to "test" + # addr.subject = "test" + # + def subject=(subject); @address_impl.setSubject(subject); end + + # Returns the type for the +Address+. + #-- + # We cannot use "type" since that clashes with the Ruby object.type + # identifier. + #++ + def address_type; @address_impl.getType; end + + # Sets the type for the +Address+. + # + # The type of the address determines how +Sender+ and +Receiver+ objects + # are constructed for it. It also affects how a reply-to address is + # encoded. + # + # If no type is specified then it will be determined by querying the + # broker. Explicitly setting the type prevents this. + # + # Values are either *queue* or *topic*. + # + # ==== Options + # + # * +type+ - the address type + # + # ==== Examples + # + # # creates an queue address + # addr = Qpid::Messaging::Address.new "my-queue;{create:always}" + # addr.address_type = "queue" + # + def address_type=(type); @address_impl.setType(type); end + + # Returns the options. + def options; @address_impl.getOptions; end + + # Sets the options for the address. + # + # *NOTE:* See the class documentation for more details on options. + # + # ==== Examples + # + # addr.options = :create => :always + # addr.options = :create => :always, :delete => :always + # + def options=(options = {}); @address_impl.setOptions(convert_options(options)); end + + def to_s # :nodoc: + @address_impl.str + end + + private + + def convert_options(options) + result = {} + options.each_pair {|key, value| result[key.to_s] = value.to_s} + + return result + end + + end + + end + +end + diff --git a/cpp/bindings/qpid/ruby/lib/qpid_messaging/connection.rb b/cpp/bindings/qpid/ruby/lib/qpid_messaging/connection.rb new file mode 100644 index 0000000000..6d637a1665 --- /dev/null +++ b/cpp/bindings/qpid/ruby/lib/qpid_messaging/connection.rb @@ -0,0 +1,189 @@ +#-- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +#++ + +module Qpid + + module Messaging + + # A +Connection+ represents a network connection to a remote endpoint. + class Connection + + attr_reader :options # :nodoc: + + # Creates a connection object. Raises a MessagingError if an invalid + # connection option is used. + # + # == Options + # + # * +:url+ - the URL for the broker + # * +:options+ - connection options + # + # == Controlling Reconnect Behavior + # + # The following connection options can be used to configure + # the reconnection behavior for this connection. + # + # * +:username+ - the authentication username + # * +:password+ - the authentication password + # * +:heartbeat+ + # * +:tcp_nodelay+ + # * +:sasl_mechanism+ + # * +:sasl_service+ + # * +:sasl_min_ssf+ + # * +:sasl_max_ssf+ + # * +:transport+ + # * +:reconnect+ - indicates whether to attempt reconnections + # * +:reconnect_timeout+ - the number of seconds to attempt reconnecting + # * +:reconnect_limit+ - the number of retries before reporting failure + # * +:reconnect_interval_min+ - initial delay, in seconds, before attempting a reconnection + # * +:reconnect_interval_max+ - number of seconds to wait before additional reconnect attempts + # * +:reconnect_interval+ - shorthand for setting both min and max values + # * +:reconnect_urls+ - a list of alternate URLs to use for reconnection attempts + # + # == Examples + # + # # creates a connection to the broker running local *localhost* + # conn = Qpid::Messaging::Connnection.new + # # creates a connection to *broker1.domain.com* on port *5672* + # conn = Qpid::Messaging::Connection.new :url => "amqp:tcp:broker1.domain.com:5672" + # # creates a connection to localhost with the specified authentication credentials + # conn = Qpid::Messaging::Connection.new :options => {:username => "login", :password => "password"} + # + def initialize(opts = {}) + @url = opts[:url] || "localhost" + @options = Qpid::Messaging.stringify(opts[:options] || {}) + @connection_impl = opts[:impl] || Cqpid::Connection.new(@url, @options) + end + + def connection_impl # :nodoc: + @connection_impl + end + + # Establishes the connection. + # + # == Examples + # + # # open a connection if it's not already open + # conn.open unless conn.open? + # + def open + @connection_impl.open + end + + # Reports whether the connection is open. + # + # == Examples + # + # # close the connection if it's not already closed + # conn.close if conn.open? + # + def open?; true && !@connection_impl.nil? && @connection_impl.isOpen; end + + # Closes the connection. + # + # == Examples + # + # # close a connection + # conn.close + # + def close; @connection_impl.close; end + + # Creates a new session. + # + # == Arguments + # + # * +:name+ - specifies the name for this session + # * +:transactional+ - if +true+ then a creates a transaction session (def. +false+) + # + # == Examples + # + # # create a session named 'session1' + # session = conn.create_session :name => "session1" + # # create a transactional session + # session = conn.create_session :transaction => true + # + def create_session(args = {}) + name = args[:name] || "" + if open? + if args[:transactional] + session = @connection_impl.createTransactionalSession name + else + session = @connection_impl.createSession name + end + return Session.new(self, session) + else + raise RuntimeError.new "No connection available." + end + end + + # Returns a Session with the given name. Raises an exception if no + # session with the given name exists. + # + # == Options + # + # * +name+ - the existing session's name + # + # == Examples + # + # # retrieve a session named 'mysession' from the current connection + # name = "my-session" + # # if no such session exists then catchh the exception raised + # begin + # session = conn.session name + # rescue MessagingException => error + # puts "No such session: #{name}." + # end + # + def session name + session_impl = @connection_impl.getSession name + Qpid::Messaging::Session.new self, session_impl if session_impl + end + + # Returns the username used to authenticate with the connection. + # + # If the connection did not user authentication credentials, then the + # username returned is "anonymous". + # + # == Examples + # + # # create a new connection for user "qpiduser" + # conn = Qpid::Messaging::Connection.new :username => "qpiduser" + # conn.open + # # displays the authenticate username + # puts "Connected as #{conn.authenticated_username}" # should say 'qpiduser' + # + def authenticated_username; @connection_impl.getAuthenticatedUsername if open?; end + + private + + def convert_options(options) + result = {} + unless options.nil? || options.empty? + options.each_pair {|key, value| result[key.to_s] = value.to_s} + end + + return result + end + + end + + end + +end + diff --git a/cpp/bindings/qpid/ruby/lib/qpid_messaging/duration.rb b/cpp/bindings/qpid/ruby/lib/qpid_messaging/duration.rb new file mode 100644 index 0000000000..11c903dade --- /dev/null +++ b/cpp/bindings/qpid/ruby/lib/qpid_messaging/duration.rb @@ -0,0 +1,128 @@ +#-- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +#++ + +module Qpid + + module Messaging + + # A Duration represents a period of time in milliseconds + # + # == Named Durations + # + # The following named +Durations+ are available as symbols: + # + # [FOREVER] + # The maximum integer value for the platform. Effectively this will wait + # forever. + # + # [IMMEDIATE] + # An alias for 0 milliseconds. + # + # [SECOND] + # An alias for 1,000 milliseconds. + # + # [MINUTE] + # And alias for 60,000 millisecons. + # + class Duration + + # Creates a Duration with the specified length, in milliseconds. + # + # ==== Options + # + # * +length+ - The duration in +milliseconds+. + # + # ==== Examples + # + # # creates a duration of 15 seconds + # # REMEMBER: Duration deals in milliseconds + # delay = Qpid::Messaging::Duration.new 15000 + # + def initialize length + @duration_impl = Cqpid::Duration.new length + end + + def duration_impl # :nodoc: + @duration_impl + end + + # Returns the period of time in +milliseconds+. + # + # ==== Examples + # + # # doubling growth in waiting for messages in a loop + # do loop + # set the base duration waiting length + # timeout = Qpid::Messaging::Duration::SECOND + # msg = nil + # # loop until we receive a message + # while msg.nil? + # puts "Waiting #{timeout.milliseconds}ms" + # msg = recv.get timeout + # # if nothing was received, double the duration + # if msg.nil? + # # double out timeout + # timeout = timeout * 2 + # else + # # do something with the message + # puts "Received: #{msg.content}" + # end + # end + # end + # + def milliseconds + @duration_impl.getMilliseconds + end + + # Multiplies the duration of the +Duration+ and returns a new instance. + # + # Raises exceptions on a negative factor. Returns + # Qpid::Messaging::Duration::IMMEDIATE when the factor is 0. + # + # ==== Examples + # + # # return a duration that is 2 minutes (120,000 ms) + # twominutes = Qpid::Messaging::Duration::MINUTE * 2 + # + def *(factor) + raise TypeError.new "Factors must be non-zero positive values" if factor < 0 + return Qpid::Messaging::Duration::IMMEDIATE if factor.zero? + Qpid::Messaging::Duration.new((self.milliseconds * factor).floor) + end + + def self.add_item(key, value) # :nodoc: + @hash ||= {} + @hash[key] = Duration.new value + end + + def self.const_missing(key) # :nodoc: + @hash[key] + end + + self.add_item :FOREVER, Cqpid::Duration.FOREVER.getMilliseconds + self.add_item :IMMEDIATE, Cqpid::Duration.IMMEDIATE.getMilliseconds + self.add_item :SECOND, Cqpid::Duration.SECOND.getMilliseconds + self.add_item :MINUTE, Cqpid::Duration.MINUTE.getMilliseconds + + end + + end + +end + diff --git a/cpp/bindings/qpid/ruby/lib/qpid_messaging/encoding.rb b/cpp/bindings/qpid/ruby/lib/qpid_messaging/encoding.rb new file mode 100644 index 0000000000..ac0fbc32a7 --- /dev/null +++ b/cpp/bindings/qpid/ruby/lib/qpid_messaging/encoding.rb @@ -0,0 +1,75 @@ +#-- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +#++ + +module Qpid + + module Messaging + + # Encodes the supplied content into the given message. + def self.encode content, message, encoding = nil # :nodoc: + Cqpid::encode content, message.message_impl, encoding + end + + # Decodes and returns the message's content. + def self.decode(message, content_type = nil) # :nodoc: + content_type = message.content_type if content_type.nil? + + case content_type + when "amqp/map" + return Cqpid.decodeMap message.message_impl + when "amqp/list" + return Cqpid.decodeList message.message_impl + end + + message.content + end + + # Takes as input any type and converts anything that's a symbol + # into a string. + def self.stringify(value) # :nodoc: + # set the default value + result = value + + case value + + when Symbol + result = value.to_s + + when Hash + result = {} + value.each_pair do |key, value| + result[stringify(key)] = stringify(value) + end + + when Array + result = [] + value.each do |element| + result << stringify(element) + end + + end + + return result + + end + + end + +end + diff --git a/cpp/bindings/qpid/ruby/lib/qpid_messaging/message.rb b/cpp/bindings/qpid/ruby/lib/qpid_messaging/message.rb new file mode 100644 index 0000000000..e167800455 --- /dev/null +++ b/cpp/bindings/qpid/ruby/lib/qpid_messaging/message.rb @@ -0,0 +1,353 @@ +#-- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +#++ + +module Qpid + + module Messaging + + # A +Message+ represents an routable piece of information. + class Message + + # Creates a +Message+. + # + # ==== Options + # + # * +:content+ - the content + # + # ==== Examples + # + # # create a simple message and sends it + # message = Qpid::Messaging::Message.new :content => "This is a message." + # sender.send message + # + def initialize(args = {}) + @message_impl = (args[:impl] if args[:impl]) || nil + @message_impl = Cqpid::Message.new if @message_impl.nil? + @content = nil + args = {} if args.nil? + self.content = args[:content] if args[:content] + end + + def message_impl # :nodoc: + @message_impl + end + + # Sets the reply-to address. + # + # The address can either be an instance of Address or else and + # address string. + # + # ==== Options + # + # * +address+ - the address + # + # ==== Examples + # + # # set replies using an Address + # msg.reply_to = Qpid:Messaging::Address.new "my-responses" + # # set replies using an address string + # msg.reply_to = "my-feed/responses" + # + def reply_to=(address) + address = Qpid::Messaging::Address.new "#{address}" if !address.is_a? Qpid::Messaging::Address + + @message_impl.setReplyTo address.address_impl + end + + # Returns the reply to address for the +Message+. + def reply_to + address_impl = @message_impl.getReplyTo + # only return an address if a reply to was specified + Qpid::Messaging::Address.new(nil, address_impl) if address_impl + end + + # Sets the subject for the +Message+. + # + # ==== Options + # + # * +subject+ - the subject + def subject=(subject); @message_impl.setSubject subject; end + + # Returns the subject of the +Message+. + def subject; @message_impl.getSubject; end + + # Sets the content type for the +Message+. + # + # This should be set by the sending application and indicates to the + # recipients of the message how to interpret or decode the content. + # + # By default, only dictionaries and maps are automatically given a content + # type. If this content type is replaced then retrieving the content will + # not behave correctly. + # + # ==== Options + # + # * +content_type+ - the content type + # + # ==== Examples + # + # # send base64 encoded data in a mesage + # msg = Qpid::Messaging::Message.new :content = "UXBpZCBSdWxlcyEK" + # msg.content_type = "application/base64" + # + def content_type=(content_type); @message_impl.setContentType content_type; end + + # Returns the content type for the +Message+. + def content_type; @message_impl.getContentType; end + + # Sets the message id. + # + # *NOTE:* this field must be a UUID type currently. A non-UUID value will + # be converted to a zero UUID, though a blank ID will be left untouched. + # + # ==== Options + # + # * +id+ - the id + # + # ==== Examples + # + # # this example only works in Ruby >= 1.9, for 1.8 use a UUID library + # require 'SecureRandom' + # msg.message_id = SecureRandom.uuid + # + def message_id=(message_id); @message_impl.setMessageId message_id.to_s; end + + # Returns the message id. + def message_id; @message_impl.getMessageId; end + + # Sets the user id for the +Message+. + # + # This should in general be the user-id which was used when authenticating + # the connection itself, as the messaging infrastructure will verify + # this. + # + # See Qpid::Messaging::Connection.authenticated_username + # + # *NOTE:* If the id is not a +String+ then the id is set using + # the object's string representation. + # + # ==== Options + # + # * +id+ - the id + # + def user_id=(user_id); @message_impl.setUserId user_id; end + + # Returns the user id for the +Message+. + def user_id; @message_impl.getUserId; end + + # Sets the correlation id of the +Message+. + # + # The correlation id can be used as part of a protocol for message + # exchange patterns; e.g., a request-response pattern might require + # the correlation id of the request and the response to match, or it + # might use the message id of the request as the correlation id on + # the response. + # + # *NOTE:* If the id is not a +String+ then the id is setup using + # the object's string representation. + # + # ==== Options + # + # * +id+ - the id + # + def correlation_id=(correlation_id); @message_impl.setCorrelationId correlation_id; end + + # Returns the correlation id of the +Message+. + def correlation_id; @message_impl.getCorrelationId; end + + # Sets the priority of the +Message+. + # + # This may be used by the messaging infrastructure to prioritize + # delivery of messages with higher priority. + # + # *NOTE:* If the priority is not an integer type then it is set using + # the object's integer representation. If the integer value is greater + # than 8-bits then only the first 8-bits are used. + # + # ==== Options + # + # * +priority+ - the priority + # + def priority=(priority); @message_impl.setPriority priority; end + + # Returns the priority for the +Message+. + def priority; @message_impl.getPriority; end + + # Sets the time-to-live in milliseconds. + # + # This can be used by the messaging infrastructure to discard messages + # that are no longer of relevance. + # + # ==== Options + # + # * +duration+ - the number of milliseconds + # + def ttl=(duration) + if duration.is_a? Qpid::Messaging::Duration + @message_impl.setTtl duration.duration_impl + else + @message_impl.setTtl Cqpid::Duration.new duration.to_i + end + end + + # Returns the time-to-live in milliseconds. + def ttl; Qpid::Messaging::Duration.new @message_impl.getTtl.getMilliseconds; end + + # Sets the durability of the +Message+. + # + # This is a hint to the messaging infrastructure that the message + # should be persisted or otherwise stored. This helps to ensure + # that the message is not lost due to failures or a shutdown. + # + # ==== Options + # + # * +durable+ - the durability flag (def. false) + # + def durable=(durable); @message_impl.setDurable durable; end + + # Returns the durability for the +Message+. + def durable; @message_impl.getDurable; end + + # This is a hint to the messaging infrastructure that if de-duplication + # is required, that this message should be examined to determine if it + # is a duplicate. + # + # ==== Options + # + # * +redelivered+ - sets the redelivered state (def. false) + # + # ==== Examples + # + # # processed is a collection of messages already received + # msg.redelivered = true if processed.include? msg.message_id + # + def redelivered=(redelivered); @message_impl.setRedelivered redelivered; end + + # Returns whether the +Message+ has been marked as redelivered. + def redelivered; @message_impl.getRedelivered; end + + # Returns all named properties. + # + # *NOTE:* It is recommended to use the []= method for + # retrieving and setting properties. Using this method may + # result in non-deterministic behavior. + def properties; @message_impl.getProperties; end + + # Returns the value for the named property. + # + # ==== Options + # + # * +name+ - the property name + # + # ==== Examples + # + # # use of message properties to mark a message as digitally signed + # verify(msg) if msg[:signed] + # + def [](key); self.properties[key.to_s]; end + + # Assigns a value to the named property. + # + # A property's name or value, if a symbol, will be converted to a string + # representation. However, you will still be able to access them using + # a symbol for the name. + # + # ==== Options + # + # * +name+ - the property name + # * +value+ - the property value + # + # ==== Examples + # + # # set the signed attribute on a message and then retrieve it + # msg[:signed] = true # sets "signed" => true + # puts "It's signed" if msg["signed"] # outputs "It's signed" + # + def []=(key, value) + @message_impl.setProperty(key.to_s, + Qpid::Messaging.stringify(value)) + end + + # Sets the content for the +Message+. + # + # Content is automatically encoded for Array and Hash types. Other types + # need to set their own content types (via content_type) in order to + # specify how recipients should process the content. + # + # ==== Options + # + # * +content+ - the content + # + # ==== Examples + # + # # set a simple content for a message + # msg.content = "This is a simple message." + # # sets content that is automatically encoded + # msg.content = {:foo => :bar} + # + def content=(content) + content_type = nil + @content = Qpid::Messaging.stringify(content) + case @content + when Hash + content_type = "amqp/map" + when Array + content_type = "amqp/list" + end + if content_type.nil? + @message_impl.setContent @content + else + Qpid::Messaging.encode @content, self, content_type + end + end + + # Returns the content of the +Message+. + # + # Content is automatically decoded based on the specified content type. + # If the content type is application-specific, then no decoding is + # performed and the content is returnedas a +String+ representation. + # + # For example, if an array of integers are sent, then the receiver will + # find the message content to be an array of String objects, where each + # String is a representation of the sent integer value. + # + def content + if @content.nil? + @content = @message_impl.getContent + + # decode the content is necessary if it + # has an encoded content type + if ["amqp/list", "amqp/map"].include? @message_impl.getContentType + @content = Qpid::Messaging.decode(self, + @message_impl.getContentType) + end + + end + @content + end + + # Returns the content's size in bytes. + def content_size; @message_impl.getContentSize; end + + end + + end + +end + diff --git a/cpp/bindings/qpid/ruby/lib/qpid_messaging/receiver.rb b/cpp/bindings/qpid/ruby/lib/qpid_messaging/receiver.rb new file mode 100644 index 0000000000..05ee925212 --- /dev/null +++ b/cpp/bindings/qpid/ruby/lib/qpid_messaging/receiver.rb @@ -0,0 +1,177 @@ +#-- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +#++ + +module Qpid + + module Messaging + + # +Receiver+ is the entity through which messages are received. + # + # An instance of +Receiver+ can only be created using an active (i.e., not + # previously closed) Session. See Qpid::Messaging::Session.create_receiver + # for more details. + # + # ==== Example + # + # # create a connection and a session + # conn = Qpid::Messaging::Connection.new :url => "mybroker:5762" + # conn.open + # session = conn.create_session + # + # # create a receiver that listens on the "updates" topic of "alerts" + # receiver = session.create_receiver "alerts/updates" + # + # # wait for an incoming message and process it + # incoming = receiver.get Qpid::Messaging::Duration::FOREVER + # process(incoming) + # + class Receiver + + def initialize(session, receiver_impl) # :nodoc: + @session = session + @receiver_impl = receiver_impl + end + + def receiver_impl # :nodoc: + @receiver_impl + end + + # Retrieves a message from the local queue, or waits for up to + # the duration specified for one to become available. + # + # If no message is received within the specified time then a + # MessagingException is raised. + # + # ==== Options + # + # * duration - the timeout to wait + # + # ==== Examples + # + # # retrieves a message, also handles exceptions raised on no messages + # begin + # # checks for a message, returning immediately + # msg = recv.get Qpid::Messaging::Duration::IMMEDIATE + # puts "Received this message: #{message.content}" + # rescue + # puts "No messages available. + # end + # + def get(duration = Qpid::Messaging::Duration::FOREVER) + message_impl = @receiver_impl.get duration.duration_impl + create_message_wrapper message_impl unless message_impl.nil? + end + + # Retrieves a message from the receiver's subscription, or waits + # for up to the duration specified for one to become available. + # + # If no message is fetched within the specified time then a + # MessagingException is raised. + # + # ==== Options + # + # * duration - the timeout to wait (def. Duration::FOREVER) + # + # ==== Examples + # + # # retrieves a message, also handles exceptions raised on no messages + # begin + # # checks for a message, times out after one second + # msg = recv.fetch Qpid::Messaging::Duration::SECOND + # puts "Fetched this message: #{message.content}" + # rescue + # puts "No messages available. + # end + # + def fetch(duration = Qpid::Messaging::Duration::FOREVER) + message_impl = @receiver_impl.fetch duration.duration_impl + create_message_wrapper message_impl unless message_impl.nil? + end + + # Sets the capacity. + # + # The capacity of a +Receiver+ is the number of Messages that can be + # pre-fetched from the broker and held locally. If capacity is 0 then + # messages will never be pre-fetched and all messages must instead be + # retrieved using #fetch. + # + # ==== Options + # + # * capacity - the capacity + # + # ==== Examples + # + # # create a receiver and give it a capacity of 50 + # recv = session.create_receiver "alerts/minor" + # recv.capacity = 50 + # + def capacity=(capacity); @receiver_impl.setCapacity capacity; end + + # Returns the capacity. + def capacity; @receiver_impl.getCapacity; end + + # Returns the number of messages locally held. + # + # The available is always 0 <= available <= capacity. + # + # If the #capacity is set to 0 then available will always be 0. + # + # ==== Examples + # + # # output the number of messages waiting while processing + # loop do + # puts "There are #{recv.available} messages pending..." + # # wait forever (the default) for the next message + # msg = recv.get + # # process the message + # dispatch_message msg + # end + # + def available; @receiver_impl.getAvailable; end + + # Returns the number of messages that have been received and acknowledged + # but whose acknowledgements have not been confirmed by the sender. + def unsettled; @receiver_impl.getUnsettled; end + + # Closes this +Receiver+. + # + # This does not affect the owning Session or Connection. + def close; @receiver_impl.close; end + + # Returns whether the +Receiver+ is closed. + def closed?; @receiver_impl.isClosed; end + + # Returns the name of this +Receiver+. + def name; @receiver_impl.getName; end + + # Returns the owning Session for this +Receiver+. + def session; @session; end + + private + + def create_message_wrapper message_impl # :nodoc: + Qpid::Messaging::Message.new(:impl => message_impl) + end + + end + + end + +end + diff --git a/cpp/bindings/qpid/ruby/lib/qpid_messaging/sender.rb b/cpp/bindings/qpid/ruby/lib/qpid_messaging/sender.rb new file mode 100644 index 0000000000..4ce1393dc7 --- /dev/null +++ b/cpp/bindings/qpid/ruby/lib/qpid_messaging/sender.rb @@ -0,0 +1,135 @@ +#-- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +#++ + +module Qpid + + module Messaging + + # +Sender+ is the entity through which messages are sent. + # + # An instance of +Sender+ can only be created using an active (not previously + # closed) Session. See Qpid::Messaging::Session.create_sender for more details. + # + # ==== Examples + # + # # create a connection + # conn = Qpid::Messaging::Connection.new "mybroker:5672" + # conn.open + # + # if conn.open? + # + # # create a session + # session = conn.create_session + # + # # create a sender that posts messages to the "updates" queue + # sender = session.create_sender "updates;{create:always} + # + # # begin sending updates + # loop do + # # wait for the next event content then send it + # content = wait_for_event + # sender.send Qpid::Messaging::Message.new :content => content + # end + # end + # + class Sender + + def initialize(session, sender_impl) # :nodoc: + @session = session + @sender_impl = sender_impl + end + + def sender_impl # :nodoc: + @sender_impl + end + + # Sends a message, optionally blocking until the message is received + # by the broker. + # + # ==== Options + # + # * +message+ - The message to send. + # * +:sync+ - Block until received. See note below on synching. + # + # ==== Synching + # + # If :sync => true, then the call will block until the broker confirms + # receipt of the message. Otherwise it will only block for available + # capacity; i.e., until pending is equal to capacity. + # + # ==== Examples + # + # # send a message + # outgoing = Qpid::Messaging::Message.new :content => content + # sender.send outgoing + # + # # send a message, wait for confirmation from the broker + # outgoing = Qpid::Messaging::Message.new :content => content + # sender.send outgoing, :sync => true + # + def send(message, args = {}, &block) + sync = args[:sync] || false + @sender_impl.send message.message_impl, sync + block.call message unless block.nil? + end + + # Closes this +Sender+. + # + # This does not affect the owning Session or Connection. + def close; @sender_impl.close; end + + # Returns the human-readable name for this +Sender+. + def name; @sender_impl.getName; end + + # Sets the capacity for this +Sender+. + # + # The capacity is the number of outgoing messages that can be held + # pending confirmation of receipt by the broker. + # + # ==== Options + # + # * +capacity+ - the capacity + def capacity=(capacity); @sender_impl.setCapacity capacity; end + + # Returns the capacity. + def capacity; @sender_impl.getCapacity; end + + # Returns the number of messages sent that are pending receipt + # confirmation by the broker. + def unsettled; @sender_impl.getUnsettled; end + + # Returns the available slots for sending messages. + # + # This differs from +capacity+ in that it is the available slots in + # the senders capacity for holding outgoing messages. The difference + # between capacity and available is the number of messages that + # have not been delivered yet. + def available + @sender_impl.getAvailable + end + + # Returns the Session for this sender. + def session; @session; end + + end + + end + +end + diff --git a/cpp/bindings/qpid/ruby/lib/qpid_messaging/session.rb b/cpp/bindings/qpid/ruby/lib/qpid_messaging/session.rb new file mode 100644 index 0000000000..7e6e11f654 --- /dev/null +++ b/cpp/bindings/qpid/ruby/lib/qpid_messaging/session.rb @@ -0,0 +1,264 @@ +#-- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +#++ + +module Qpid + + module Messaging + + # A +Session+ represents a distinct conversation between end points. They are + # created from an active (i.e., not closed) Connection. + # + # A +Session+ is used to acknowledge individual or all messages that have + # passed through it + class Session + + def initialize(connection, session) # :nodoc: + @connection = connection + @session_impl = session + end + + def session_impl # :nodoc: + @session_impl + end + + # Returns the Connection associated with this session. + def connection + @connection + end + + # Creates a new endpoint for sending messages. + # + # The address can either be an instance Address or else an + # address string. + # + # ==== Arguments + # + # * +address+ - the end point address. + def create_sender(address) + _address = address + + if address.class == Qpid::Messaging::Address + _address = address.address_impl + end + + sender_impl = @session_impl.createSender(_address) + sender_name = sender_impl.getName + + Qpid::Messaging::Sender.new(self, sender_impl) + end + + # Retrieves the Sender with the specified name. + # + # Raises an exception if no such Sender exists. + # + # ==== Arguments + # + # * +name+ - the name of the Sender + def sender(name) + Qpid::Messaging::Sender.new self, @session_impl.getSender(name) + end + + # Creates a new endpoint for receiving messages. + # + # The +address+ can either be an instance Address or else an + # address string. + # + # ==== Arguments + # + # * +address+ - the end point address. + def create_receiver(address) + result = nil + receiver_impl = nil + + if address.class == Qpid::Messaging::Address + address_impl = address.address_impl + receiver_impl = @session_impl.createReceiver address_impl + else + receiver_impl = @session_impl.createReceiver(address) + end + + Qpid::Messaging::Receiver.new self, receiver_impl + end + + # Retrieves the +Receiver+ with the specified name, or nil if no such + # Receiver exists. + # + # ==== Arguments + # + # * +name+ - the name of the Receiver + def receiver(name) + Qpid::Messaging::Receiver.new self, @session_impl.getReceiver(name) + end + + # Closes the +Session+ and all associated +Sender+ and +Receiver+ instances. + # + # *NOTE:* All +Session+ instances for a Connection are closed when the + # Connection is closed. But closing a +Session+ does not affect the + # owning Connection. + def close; @session_impl.close; end + + # Commits any pending transactions for a transactional session. + def commit; @session_impl.commit; end + + # Rolls back any uncommitted transactions on a transactional session. + def rollback; @session_impl.rollback; end + + # Acknowledges one or more outstanding messages that have been received + # on this session. + # + # ==== Arguments + # + # * +options+ - the set of options + # + # ==== Options + # + # * :message - if specified, then only that Message is acknowledged + # * :sync - if true, the call will block until processed by the broker + # + # ==== Examples + # + # # acknowledge all received messages + # session.acknowledge + # + # # acknowledge a single message + # session.acknowledge :message => message + # + # # acknowledge all messages, wait until the call finishes + # session.acknowledge :sync => true + # + #-- + # TODO: Add an optional block to be used for blocking calls. + #++ + def acknowledge(options = {}) + sync = options[:sync] || false + message = options[:message] if options[:message] + + unless message.nil? + @session_impl.acknowledge message.message_impl, sync + else + @session_impl.acknowledge sync + end + end + + # Rejects the specified message. A rejected message will not be + # redelivered. + # + # NOTE: A message cannot be rejected once it has been acknowledged. + def reject(message); @session_impl.reject message.message_impl; end + + # Releases the message, which allows the broker to attempt to + # redeliver it. + # + # NOTE: A message connot be released once it has been acknowled. + def release(message); @session_impl.release message.message_impl; end + + # Requests synchronization with the broker. + # + # ==== Arguments + # + # * +options+ - the list of options + # + # ==== Options + # + # * +:block+ - if true, the call blocks until the broker acknowledges it + # + #-- + # TODO: Add an optional block to be used for blocking calls. + #++ + def sync(args = {}) + block = args[:block] || false + @session_impl.sync block + end + + # Returns the total number of receivable messages, and messages already + # received, by Receiver instances associated with this +Session+. + def receivable; @session_impl.getReceivable; end + + # Returns the number of messages that have been acknowledged by this + # +Session+ whose acknowledgements have not been confirmed as processed + # by the broker. + def unsettled_acks; @session_impl.getUnsettledAcks; end + + # Fetches the next Receiver with a message pending. Waits the specified + # number of milliseconds before timing out. + # + # For a Receiver to be returned, it must have a capacity > 0 and have + # Messages locally queued. + # + # If no Receiver is found within the time out period, then a MessageError + # is raised. + # + # ==== Arguments + # + # * +timeout+ - the duration + # + # ==== Examples + # + # loop do + # + # begin + # # wait a maximum of one minute for the next receiver to be ready + # recv = session.next_receiver Qpid::Messaging::Duration::MINUTE + # + # # get and dispatch the message + # msg = recv.get + # dispatch_message msg + # + # rescue + # puts "No receivers were returned" + # end + # + # end + def next_receiver(timeout = Qpid::Messaging::Duration::FOREVER, &block) + receiver_impl = @session_impl.nextReceiver(timeout.duration_impl) + + unless receiver_impl.nil? + recv = Qpid::Messaging::Receiver.new self, receiver_impl + block.call recv unless block.nil? + end + + return recv + end + + # Returns true if there were exceptions on this session. + def errors?; @session_impl.hasError; end + + # If the +Session+ has been rendered invalid due to some exception, + # this method will result in that exception being raised. + # + # If none have occurred, then no exceptions are raised. + # + # ==== Examples + # + # # show any errors that occurred during the Session + # if @session.errors? + # begin + # @session.errors + # rescue Exception => error + # puts "An error occurred: #{error}" + # end + # end + def errors; @session_impl.checkError; end + + end + + end + +end + |