[DRE-commits] [SCM] ruby-stomp.git branch, upstream, updated. upstream/1.2.4-1-gb0c95a3
Jonas Genannt
jonas at brachium-system.net
Mon Aug 13 15:09:44 UTC 2012
The following commit has been merged in the upstream branch:
commit b0c95a39d4b68d32ef4a2ce136568ca7dc2249f9
Author: Jonas Genannt <jonas at brachium-system.net>
Date: Mon Aug 13 17:02:45 2012 +0200
Adding upstream version 1.2.5.
diff --git a/CHANGELOG.rdoc b/CHANGELOG.rdoc
index c5112fc..ccd4b68 100644
--- a/CHANGELOG.rdoc
+++ b/CHANGELOG.rdoc
@@ -1,3 +1,14 @@
+== 1.2.5 20120804
+
+* Issue #48 any forks with modifications will be affected!
+* Source code restructured into individual files
+* Common indentation used throughout the source
+* Many method comments have been added
+* See notes in source regarding making methods private in the next release
+* See notes in source regarding removal of methods in the next release
+* Include examples and tests in rdoc generated during install
+* Issue #47 socket is open during retries
+
== 1.2.4 20120625
* Add ability for client to request flush on write to the connection (Issue #45)
diff --git a/README.rdoc b/README.rdoc
index 104f771..e7d2bb5 100644
--- a/README.rdoc
+++ b/README.rdoc
@@ -10,35 +10,16 @@ An implementation of the Stomp protocol for Ruby. See:
===New
-* Gem version 1.2.2. Stomp 1.1 heartbeat fix, autoflush capability, miscellaneous fixes
-* Gem version 1.2.3. Miscellaneous fixes, see changelog for details.
-* Gem version 1.2.2. Performance and more SSL enhancements.
+* Gem version 1.2.5. Restructure. Forks with modifcations will be affected. See _CHANGELOG.rdoc_ for details.
+* Gem version 1.2.4. Stomp 1.1 heartbeat fix, autoflush capability, miscellaneous fixes.
+* Gem version 1.2.3. Miscellaneous fixes, see changelog for details.
+* Gem version 1.2.2. Performance and more SSL enhancements.
* Full support of SSL certificates is announced as of gem version 1.2.1.
* Support of Stomp protocol level 1.1 is announced as of gem version 1.2.0.
-See the change log for details.
+See _CHANGELOG.rdoc_ for details.
-===Example Usage
-
- client = Stomp::Client.new("test", "user", "localhost", 61613)
- client.send("/queue/mine", "hello world!")
- client.subscribe("/queue/mine") do |msg|
- p msg
- end
-
-===Failover + SSL Example URL Usage
-
- options = "initialReconnectDelay=5000&randomize=false&useExponentialBackOff=false"
-
- # remotehost1 uses SSL, remotehost2 doesn't
- client = Stomp::Client.new("failover:(stomp+ssl://login1:passcode1@remotehost1:61612,stomp://login2:passcode2@remotehost2:61613)?#{options}")
-
- client.publish("/queue/mine", "hello world!")
- client.subscribe("/queue/mine") do |msg|
- p msg
- end
-
-===Hash Login Example Usage
+===Hash Login Example Usage (this is the recommended login technique)
hash = {
:hosts => [
@@ -67,8 +48,39 @@ See the change log for details.
# for connection
connection = Stomp::Connection.new(hash)
+===Positional Parameter Usage
+
+ client = Stomp::Client.new("test", "user", "localhost", 61613)
+ client.send("/queue/mine", "hello world!")
+ client.subscribe("/queue/mine") do |msg|
+ p msg
+ end
+
+===Stomp URL Usage
+
+ # Stomp URL :
+ A Stomp URL must begin with 'stomp://' and can be in one of the following forms:
+
+ stomp://host:port
+ stomp://host.domain.tld:port
+ stomp://login:passcode@host:port
+ stomp://login:passcode@host.domain.tld:port
+
+ e.g. c = Stomp::Client.new(urlstring)
+
+===Failover + SSL Example URL Usage
+
+ options = "initialReconnectDelay=5000&randomize=false&useExponentialBackOff=false"
+
+ # remotehost1 uses SSL, remotehost2 doesn't
+ client = Stomp::Client.new("failover:(stomp+ssl://login1:passcode1@remotehost1:61612,stomp://login2:passcode2@remotehost2:61613)?#{options}")
+
+ client.publish("/queue/mine", "hello world!")
+ client.subscribe("/queue/mine") do |msg|
+ p msg
+ end
-===Hstorical Information
+===Historical Information
Up until March 2009 the project was maintained and primarily developed by Brian McCallister.
diff --git a/Rakefile b/Rakefile
index 7ea82fd..2644257 100644
--- a/Rakefile
+++ b/Rakefile
@@ -37,6 +37,9 @@ begin
gem.authors = ["Brian McCallister", 'Marius Mathiesen', 'Thiago Morello',
'Guy M. Allard']
gem.add_development_dependency "rspec", '>= 2.3'
+ gem.extra_rdoc_files = [ "README.rdoc", "CHANGELOG.rdoc", "LICENSE",
+ "lib/**/*.rb", "examples/**/*.rb",
+ "test/**/*.rb" ]
end
Jeweler::GemcutterTasks.new
rescue LoadError
diff --git a/bin/catstomp b/bin/catstomp
index 746b3ef..98ac7ec 100755
--- a/bin/catstomp
+++ b/bin/catstomp
@@ -28,46 +28,46 @@ require 'stomp'
#
begin
- if ARGV[0] == '-h' || ARGV[0] == '--help'
- $stdout.puts
- $stdout.puts 'Usage: catstomp DESTINATION'
- $stdout.puts
- $stdout.puts 'Publishes STDIN to the desired stomp destination'
- $stdout.puts
- $stdout.puts 'Example: ls | catstomp /topic/foo'
- $stdout.puts
- $stdout.puts 'Defaults:'
- $stdout.puts "DESTINATION\t/topic/default"
- $stdout.puts "STOMP_HOST\tlocalhost"
- $stdout.puts "STOMP_PORT\t61613"
- $stdout.puts "STOMP_USER"
- $stdout.puts "STOMP_PASSWORD"
- $stdout.puts
- $stdout.puts 'You can override the stomp host, port, user, or password through environment variables'
- exit 0
- end
+ if ARGV[0] == '-h' || ARGV[0] == '--help'
+ $stdout.puts
+ $stdout.puts 'Usage: catstomp DESTINATION'
+ $stdout.puts
+ $stdout.puts 'Publishes STDIN to the desired stomp destination'
+ $stdout.puts
+ $stdout.puts 'Example: ls | catstomp /topic/foo'
+ $stdout.puts
+ $stdout.puts 'Defaults:'
+ $stdout.puts "DESTINATION\t/topic/default"
+ $stdout.puts "STOMP_HOST\tlocalhost"
+ $stdout.puts "STOMP_PORT\t61613"
+ $stdout.puts "STOMP_USER"
+ $stdout.puts "STOMP_PASSWORD"
+ $stdout.puts
+ $stdout.puts 'You can override the stomp host, port, user, or password through environment variables'
+ exit 0
+ end
- @port = 61613
- @host = "localhost"
- @user = ENV["STOMP_USER"];
- @password = ENV["STOMP_PASSWORD"]
+ @port = 61613
+ @host = "localhost"
+ @user = ENV["STOMP_USER"];
+ @password = ENV["STOMP_PASSWORD"]
- @host = ENV["STOMP_HOST"] if ENV["STOMP_HOST"] != nil
- @port = ENV["STOMP_PORT"] if ENV["STOMP_PORT"] != nil
+ @host = ENV["STOMP_HOST"] if ENV["STOMP_HOST"] != nil
+ @port = ENV["STOMP_PORT"] if ENV["STOMP_PORT"] != nil
- @destination = "/topic/default"
- @destination = $*[0] if $*[0] != nil
+ @destination = "/topic/default"
+ @destination = $*[0] if $*[0] != nil
- $stderr.print "Connecting to stomp://#{@host}:#{@port} as #{@user}\n"
- @conn = Stomp::Connection.open(@user, @password, @host, @port, true)
- $stderr.print "Sending input to #{@destination}\n"
+ $stderr.print "Connecting to stomp://#{@host}:#{@port} as #{@user}\n"
+ @conn = Stomp::Connection.open(@user, @password, @host, @port, true)
+ $stderr.print "Sending input to #{@destination}\n"
- @headers = {'persistent'=>'false'}
- @headers['reply-to'] = $*[1] if $*[1] != nil
+ @headers = {'persistent'=>'false'}
+ @headers['reply-to'] = $*[1] if $*[1] != nil
- STDIN.each_line { |line|
- @conn.publish @destination, line, @headers
- }
+ STDIN.each_line { |line|
+ @conn.publish @destination, line, @headers
+ }
rescue
end
diff --git a/bin/stompcat b/bin/stompcat
index 006a910..2bceaf2 100755
--- a/bin/stompcat
+++ b/bin/stompcat
@@ -28,47 +28,47 @@ require 'stomp'
#
begin
- if ARGV[0] == '-h' || ARGV[0] == '--help'
- $stdout.puts
- $stdout.puts 'Usage: stompcat DESTINATION'
- $stdout.puts
- $stdout.puts 'Receives data from a stomp destination and outputs it to STDOUT'
- $stdout.puts
- $stdout.puts 'Example: stompcat /topic/foo'
- $stdout.puts
- $stdout.puts 'Defaults:'
- $stdout.puts "DESTINATION\t/topic/default"
- $stdout.puts "STOMP_HOST\tlocalhost"
- $stdout.puts "STOMP_PORT\t61613"
- $stdout.puts "STOMP_USER\t"
- $stdout.puts "STOMP_PASSWORD\t"
- $stdout.puts
- $stdout.puts 'You can override the host, port, user, or password through environment variables'
- exit 0
- end
+ if ARGV[0] == '-h' || ARGV[0] == '--help'
+ $stdout.puts
+ $stdout.puts 'Usage: stompcat DESTINATION'
+ $stdout.puts
+ $stdout.puts 'Receives data from a stomp destination and outputs it to STDOUT'
+ $stdout.puts
+ $stdout.puts 'Example: stompcat /topic/foo'
+ $stdout.puts
+ $stdout.puts 'Defaults:'
+ $stdout.puts "DESTINATION\t/topic/default"
+ $stdout.puts "STOMP_HOST\tlocalhost"
+ $stdout.puts "STOMP_PORT\t61613"
+ $stdout.puts "STOMP_USER\t"
+ $stdout.puts "STOMP_PASSWORD\t"
+ $stdout.puts
+ $stdout.puts 'You can override the host, port, user, or password through environment variables'
+ exit 0
+ end
- @port = 61613
- @host = "localhost"
- @user = ENV["STOMP_USER"];
- @password = ENV["STOMP_PASSWORD"]
+ @port = 61613
+ @host = "localhost"
+ @user = ENV["STOMP_USER"];
+ @password = ENV["STOMP_PASSWORD"]
- @host = ENV["STOMP_HOST"] if ENV["STOMP_HOST"] != nil
- @port = ENV["STOMP_PORT"] if ENV["STOMP_PORT"] != nil
+ @host = ENV["STOMP_HOST"] if ENV["STOMP_HOST"] != nil
+ @port = ENV["STOMP_PORT"] if ENV["STOMP_PORT"] != nil
- @destination = "/topic/default"
- @destination = $*[0] if $*[0] != nil
+ @destination = "/topic/default"
+ @destination = $*[0] if $*[0] != nil
- $stderr.print "Connecting to stomp://#{@host}:#{@port} as #{@user}\n"
- @conn = Stomp::Connection.open(@user, @password, @host, @port, true)
- $stderr.print "Getting output from #{@destination}\n"
+ $stderr.print "Connecting to stomp://#{@host}:#{@port} as #{@user}\n"
+ @conn = Stomp::Connection.open(@user, @password, @host, @port, true)
+ $stderr.print "Getting output from #{@destination}\n"
- @conn.subscribe(@destination, { :ack =>"client" })
- while true
- @msg = @conn.receive
- $stdout.print @msg.body
- $stdout.flush
- @conn.ack @msg.headers["message-id"]
- end
+ @conn.subscribe(@destination, { :ack =>"client" })
+ while true
+ @msg = @conn.receive
+ $stdout.print @msg.body
+ $stdout.flush
+ @conn.ack @msg.headers["message-id"]
+ end
rescue
end
diff --git a/examples/client11_ex1.rb b/examples/client11_ex1.rb
index ea392eb..60c85f2 100644
--- a/examples/client11_ex1.rb
+++ b/examples/client11_ex1.rb
@@ -11,70 +11,79 @@ else
require "stomp11_common"
end
include Stomp11Common
+
#
-# Stomp 1.1 Client Example 1
-# ==============================
+# == Stomp 1.1 Client Example 1
#
# Purpose: to demonstrate a connect and disconnect sequence using Stomp 1.1
# with the Stomp#Client interface.
#
-# Note: Stomp#Client does not provide a positional set of parameters that
-# contain a 'connect_headers' parameter. To use the Stomp#Client interface
-# you _must_ use a 'hashed' set of parameters.
-#
-# Create connection headers
-# =========================
-#
-# The two headers used here are _required_ by the specification.
-#
-client_hdrs = {"accept-version" => "1.1", # Demand a 1.1 connection (use a CSV list if you will consider multiple versions)
+class Client11Example1
+ # Initialize.
+ def initialize
+ end
+ # Run example.
+ def run
+ # Note: Stomp#Client does not provide a positional set of parameters that
+ # contain a 'connect_headers' parameter. To use the Stomp#Client interface
+ # you _must_ use a 'hashed' set of parameters.
+ #
+ # Create connection headers
+ # =========================
+ #
+ # The two headers used here are _required_ by the specification.
+ #
+ client_hdrs = {"accept-version" => "1.1", # Demand a 1.1 connection (use a CSV list if you will consider multiple versions)
"host" => virt_host, # The 1.1 vhost (could be different than connection host)
} # No heartbeats here: there will be none for this connection
-#
-# Create the connect hash.
-# ========================
-#
-client_hash = { :hosts => [
- {:login => login, :passcode => passcode, :host => host, :port => port},
+ #
+ # Create the connect hash.
+ # ========================
+ #
+ client_hash = { :hosts => [
+ {:login => login, :passcode => passcode, :host => host, :port => port},
],
:connect_headers => client_hdrs,
}
+ #
+ # Get a connection
+ # ================
+ #
+ client = Stomp::Client.new(client_hash)
+ puts "Client Connect complete"
+ #
+ # Let's just do some sanity checks, and look around.
+ #
+ raise "Connection failed!!" unless client.open?
+ #
+ # Is this really a 1.1 conection? (For clients, 'protocol' is a public method.
+ # The value will be '1.0' for those types of connections.)
+ #
+ raise "Unexpected protocol level" if client.protocol() != Stomp::SPL_11
+ #
+ # The broker _could_ have returned an ERROR frame (unlikely).
+ # For clients, 'connection_frame' is a public method.
+ #
+ raise "Connect error: #{client.connection_frame().body}" if client.connection_frame().command == Stomp::CMD_ERROR
+ #
+ # Examine the CONNECT response (the connection_frame()).
+ #
+ puts "Connected Headers required to be present:"
+ puts "Connect version - \t#{client.connection_frame().headers['version']}"
+ puts
+ puts "Connected Headers that are optional:"
+ puts "Connect server - \t\t#{client.connection_frame().headers['server']}"
+ puts "Session ID - \t\t\t#{client.connection_frame().headers['session']}"
+ puts "Server requested heartbeats - \t#{client.connection_frame().headers['heart-beat']}"
+ #
+ # Finally close
+ # =============
+ #
+ client.close # Business as usual, just like 1.0
+ puts "Client close complete"
+ end
+end
#
-# Get a connection
-# ================
-#
-client = Stomp::Client.new(client_hash)
-puts "Client Connect complete"
-#
-# Let's just do some sanity checks, and look around.
-#
-raise "Connection failed!!" unless client.open?
-#
-# Is this really a 1.1 conection? (For clients, 'protocol' is a public method.
-# The value will be '1.0' for those types of connections.)
-#
-raise "Unexpected protocol level" if client.protocol() != Stomp::SPL_11
-#
-# The broker _could_ have returned an ERROR frame (unlikely).
-# For clients, 'connection_frame' is a public method.
-#
-raise "Connect error: #{client.connection_frame().body}" if client.connection_frame().command == Stomp::CMD_ERROR
-#
-# Examine the CONNECT response (the connection_frame()).
-#
-puts "Connected Headers required to be present:"
-puts "Connect version - \t#{client.connection_frame().headers['version']}"
-puts
-puts "Connected Headers that are optional:"
-puts "Connect broker - \t\t#{client.connection_frame().headers['broker']}"
-puts "Session ID - \t\t\t#{client.connection_frame().headers['session']}"
-puts "Server requested heartbeats - \t#{client.connection_frame().headers['heart-beat']}"
-#
-# Finally close
-# =============
-#
-client.close # Business as usual, just like 1.0
-puts "Client close complete"
-
-
+e = Client11Example1.new
+e.run
diff --git a/examples/client11_putget1.rb b/examples/client11_putget1.rb
index ddcc35d..2530ed5 100644
--- a/examples/client11_putget1.rb
+++ b/examples/client11_putget1.rb
@@ -11,49 +11,61 @@ else
require "stomp11_common"
end
include Stomp11Common
+
#
-# Stomp 1.1 Client Putter/Getter Example 1
-# ========================================
+# == Stomp 1.1 Client Putter/Getter Example 1
#
# This is much like sending and receiving with a Stomp::Connection.
#
-client_hdrs = {"accept-version" => "1.1", # Demand a 1.1 connection (use a CSV list if you will consider multiple versions)
+class Client11PutGet1
+ # Initialize.
+ def initialize
+ end
+ # Run example.
+ def run
+ #
+ client_hdrs = {"accept-version" => "1.1", # Demand a 1.1 connection (use a CSV list if you will consider multiple versions)
"host" => virt_host, # The 1.1 vhost (could be different than connection host)
} # No heartbeats here: there will be none for this connection
-#
-client_hash = { :hosts => [
- {:login => login, :passcode => passcode, :host => host, :port => port},
+ #
+ client_hash = { :hosts => [
+ {:login => login, :passcode => passcode, :host => host, :port => port},
],
:connect_headers => client_hdrs,
}
+ #
+ client = Stomp::Client.new(client_hash)
+ puts "Client Connect complete"
+ #
+ raise "Unexpected protocol level" if client.protocol() != Stomp::SPL_11
+ #
+ qname = "/queue/client.nodea.nodeb.nodec"
+ data = "message payload: #{Time.now.to_f}"
+ headers = {}
+ # Send it
+ client.publish qname, data
+ puts "Publish complete"
+ # Receive
+ uuid = client.uuid() # uuid for Stomp::Client is a public method
+ message = nil
+ # Clients must pass a receive block. This is business as usual, required for 1.0.
+ # For 1.1, a unique subscription id is required.
+ client.subscribe(qname, {'id' => uuid}) {|m|
+ message = m
+ }
+ sleep 0.1 until message # Wait for completion
+ puts "Subscribe and receive complete"
+ # Unsubscribe, with the unique id
+ client.unsubscribe qname, {'id' => uuid}
+ # Sanity checks for this example ....
+ raise "Unexpected data" if data != message.body
+ raise "Bad subscription header" if uuid != message.headers['subscription']
+ #
+ client.close # Business as usual, just like 1.0
+ puts "Client close complete"
+ end
+end
#
-client = Stomp::Client.new(client_hash)
-puts "Client Connect complete"
-#
-raise "Unexpected protocol level" if client.protocol() != Stomp::SPL_11
-#
-qname = "/queue/client.nodea.nodeb.nodec"
-data = "message payload: #{Time.now.to_f}"
-headers = {}
-# Send it
-client.publish qname, data
-# Receive
-uuid = client.uuid() # uuid for Stomp::Client is a public method
-message = nil
-# Clients must pass a receive block. This is business as usual, required for 1.0.
-# For 1.1, a unique subscription id is required.
-client.subscribe(qname, {'id' => uuid}) {|m|
- message = m
-}
-sleep 0.1 until message # Wait for completion
-# Unsubscribe, with the unique id
-client.unsubscribe qname, {'id' => uuid}
-# Sanity checks for this example ....
-raise "Unexpected data" if data != message.body
-raise "Bad subscription header" if uuid != message.headers['subscription']
-#
-client.close # Business as usual, just like 1.0
-puts "Client close complete"
-
-
+e = Client11PutGet1.new
+e.run
diff --git a/examples/conn11_ex1.rb b/examples/conn11_ex1.rb
index 758b919..f5e7579 100644
--- a/examples/conn11_ex1.rb
+++ b/examples/conn11_ex1.rb
@@ -11,13 +11,13 @@ else
require "stomp11_common"
end
include Stomp11Common
+
#
-# Stomp 1.1 Connection Example 1
-# ==============================
+# == Stomp 1.1 Connection Example 1
#
# Purpose: to demonstrate a connect and disconnect sequence using Stomp 1.1.
#
-# Note: this example assumes that you have at least the 1.2.0 gem release
+# Note: this example assumes that you have at least the 1.2.0 gem release
# installed.
#
# When you:
@@ -48,57 +48,65 @@ include Stomp11Common
# * heartbeat request
#
# Using the stomp gem, you can specify this data in the "connect_headers" Hash
-# parameter or a paramaterized connection request. This example uses a
+# parameter or a paramaterized connection request. This example uses a
# parameterized request.
#
-# So .........
-#
-# Create connection headers
-# =========================
-#
-# The two headers used here are _required_ by the specification.
-#
-conn_hdrs = {"accept-version" => "1.1", # Demand a 1.1 connection (use a CSV list if you will consider multiple versions)
+class Connection11Example1
+ # Initialize
+ def initialize
+ end
+ # Run example
+ def run
+ #
+ # Create connection headers
+ # =========================
+ #
+ # The two headers used here are _required_ by the specification.
+ #
+ conn_hdrs = {"accept-version" => "1.1", # Demand a 1.1 connection (use a CSV list if you will consider multiple versions)
"host" => virt_host, # The 1.1 vhost (could be different than connection host)
} # No heartbeats here: there will be none for this connection
+ #
+ # Get a connection
+ # ================
+ #
+ conn = Stomp::Connection.new(login, passcode, host, port, # Normal connect parms
+ false, # Not reliable, the default for a parameter connection
+ 5, # Connect redelay, the default
+ conn_hdrs) # The 1.1 connection parameters
+ puts "Connection connect complete"
+ #
+ # Let's just do some sanity checks, and look around.
+ #
+ raise "Connection failed!!" unless conn.open?
+ #
+ # Is this really a 1.1 conection? ('protocol' is a read only connection
+ # instance variable. The value will be '1.0' for those types of connections.)
+ #
+ raise "Unexpected protocol level" if conn.protocol != Stomp::SPL_11
+ #
+ # The broker _could_ have returned an ERROR frame (unlikely).
+ #
+ raise "Connect error: #{conn.connection_frame.body}" if conn.connection_frame.command == Stomp::CMD_ERROR
+ #
+ # Examine the CONNECT response (the connection_frame).
+ #
+ puts "Connected Headers required to be present:"
+ puts "Connect version - \t#{conn.connection_frame.headers['version']}"
+ puts
+ puts "Connected Headers that are optional:"
+ puts "Connect server - \t\t#{conn.connection_frame.headers['server']}"
+ puts "Session ID - \t\t\t#{conn.connection_frame.headers['session']}"
+ puts "Server requested heartbeats - \t#{conn.connection_frame.headers['heart-beat']}"
+ #
+ # Finally disconnect
+ # ==================
+ #
+ conn.disconnect # Business as usual, just like 1.0
+ puts "Connection disconnect complete"
+ end
+end
#
-# Get a connection
-# ================
-#
-conn = Stomp::Connection.new(login, passcode, host, port, # Normal connect parms
- false, # Not reliable, the default for a parameter connection
- 5, # Connect redelay, the default
- conn_hdrs) # The 1.1 connection parameters
-puts "Connection connect complete"
-#
-# Let's just do some sanity checks, and look around.
-#
-raise "Connection failed!!" unless conn.open?
-#
-# Is this really a 1.1 conection? ('protocol' is a read only connection
-# instance variable. The value will be '1.0' for those types of connections.)
-#
-raise "Unexpected protocol level" if conn.protocol != Stomp::SPL_11
-#
-# The broker _could_ have returned an ERROR frame (unlikely).
-#
-raise "Connect error: #{conn.connection_frame.body}" if conn.connection_frame.command == Stomp::CMD_ERROR
-#
-# Examine the CONNECT response (the connection_frame).
-#
-puts "Connected Headers required to be present:"
-puts "Connect version - \t#{conn.connection_frame.headers['version']}"
-puts
-puts "Connected Headers that are optional:"
-puts "Connect broker - \t\t#{conn.connection_frame.headers['broker']}"
-puts "Session ID - \t\t\t#{conn.connection_frame.headers['session']}"
-puts "Server requested heartbeats - \t#{conn.connection_frame.headers['heart-beat']}"
-#
-# Finally disconnect
-# ==================
-#
-conn.disconnect # Business as usual, just like 1.0
-puts "Connection disconnect complete"
-
-
+e = Connection11Example1.new
+e.run
diff --git a/examples/conn11_ex2.rb b/examples/conn11_ex2.rb
index 7eb1e73..0369c07 100644
--- a/examples/conn11_ex2.rb
+++ b/examples/conn11_ex2.rb
@@ -11,68 +11,77 @@ else
require "stomp11_common"
end
include Stomp11Common
+
#
-# Stomp 1.1 Connection Example 1
-# ==============================
+# == Stomp 1.1 Connection Example 2
#
# Purpose: to demonstrate a connect and disconnect sequence using Stomp 1.1.
#
# This example is like the 'conn11_ex1.rb' example except that a 'hashed'
# connect request is made.
#
-# Create connection headers
-# =========================
-#
-# The two headers used here are _required_ by the specification.
-#
-conn_hdrs = {"accept-version" => "1.1", # Demand a 1.1 connection (use a CSV list if you will consider multiple versions)
+class Connection11Example2
+ # Initialize.
+ def initialize
+ end
+ # Run example.
+ def run
+ # Create connection headers
+ # =========================
+ #
+ # The two headers used here are _required_ by the specification.
+ #
+ conn_hdrs = {"accept-version" => "1.1", # Demand a 1.1 connection (use a CSV list if you will consider multiple versions)
"host" => virt_host, # The 1.1 vhost (could be different than connection host)
} # No heartbeats here: there will be none for this connection
-#
-# Create the connect hash.
-# ========================
-#
-conn_hash = { :hosts => [
- {:login => login, :passcode => passcode, :host => host, :port => port},
+ #
+ # Create the connect hash.
+ # ========================
+ #
+ conn_hash = { :hosts => [
+ {:login => login, :passcode => passcode, :host => host, :port => port},
],
:reliable => false, # Override default
:connect_headers => conn_hdrs,
}
+ #
+ # Get a connection
+ # ================
+ #
+ conn = Stomp::Connection.new(conn_hash)
+ puts "Connection complete"
+ #
+ # Let's just do some sanity checks, and look around.
+ #
+ raise "Connection failed!!" unless conn.open?
+ #
+ # Is this really a 1.1 conection? ('protocol' is a read only connection
+ # instance variable. The value will be '1.0' for those types of connections.)
+ #
+ raise "Unexpected protocol level" if conn.protocol != Stomp::SPL_11
+ #
+ # The broker _could_ have returned an ERROR frame (unlikely).
+ #
+ raise "Connect error: #{conn.connection_frame.body}" if conn.connection_frame.command == Stomp::CMD_ERROR
+ #
+ # Examine the CONNECT response (the connection_frame).
+ #
+ puts "Connected Headers required to be present:"
+ puts "Connect version - \t#{conn.connection_frame.headers['version']}"
+ puts
+ puts "Connected Headers that are optional:"
+ puts "Connect server - \t\t#{conn.connection_frame.headers['server']}"
+ puts "Session ID - \t\t\t#{conn.connection_frame.headers['session']}"
+ puts "Server requested heartbeats - \t#{conn.connection_frame.headers['heart-beat']}"
+ #
+ # Finally disconnect
+ # ==================
+ #
+ conn.disconnect # Business as usual, just like 1.0
+ puts "Disconnect complete"
+ end
+end
#
-# Get a connection
-# ================
-#
-conn = Stomp::Connection.new(conn_hash)
-puts "Connection complete"
-#
-# Let's just do some sanity checks, and look around.
-#
-raise "Connection failed!!" unless conn.open?
-#
-# Is this really a 1.1 conection? ('protocol' is a read only connection
-# instance variable. The value will be '1.0' for those types of connections.)
-#
-raise "Unexpected protocol level" if conn.protocol != Stomp::SPL_11
-#
-# The broker _could_ have returned an ERROR frame (unlikely).
-#
-raise "Connect error: #{conn.connection_frame.body}" if conn.connection_frame.command == Stomp::CMD_ERROR
-#
-# Examine the CONNECT response (the connection_frame).
-#
-puts "Connected Headers required to be present:"
-puts "Connect version - \t#{conn.connection_frame.headers['version']}"
-puts
-puts "Connected Headers that are optional:"
-puts "Connect broker - \t\t#{conn.connection_frame.headers['broker']}"
-puts "Session ID - \t\t\t#{conn.connection_frame.headers['session']}"
-puts "Server requested heartbeats - \t#{conn.connection_frame.headers['heart-beat']}"
-#
-# Finally disconnect
-# ==================
-#
-conn.disconnect # Business as usual, just like 1.0
-puts "Disconnect complete"
-
-
+e = Connection11Example2.new
+e.run
diff --git a/examples/conn11_hb1.rb b/examples/conn11_hb1.rb
index 734e13c..8060cb7 100644
--- a/examples/conn11_hb1.rb
+++ b/examples/conn11_hb1.rb
@@ -13,36 +13,45 @@ else
require "slogger"
end
include Stomp11Common
+
#
-# Stomp 1.1 Heartbeat Example 1
-# =============================
+# == Stomp 1.1 Heartbeat Example 1
#
# Purpose: to demonstrate that heart beats can work.
#
-# Create connection headers
-# =========================
-#
-conn_hdrs = {"accept-version" => "1.1", # 1.1
- "host" => virt_host, # vhost
- "heart-beat" => "5000,10000", # heartbeats
+class HeartBeatExample1
+ # Initialize.
+ def initialize
+ end
+ # Run example.
+ def run
+ # Create connection headers
+ # =========================
+ #
+ conn_hdrs = {"accept-version" => "1.1", # 1.1
+ "host" => virt_host, # vhost
+ "heart-beat" => "5000,10000", # heartbeats
}
-# Create a logger for demonstration purposes
-logger = Slogger.new
-# Connect - a paramaterized request.
-conn = Stomp::Connection.new(login, passcode, host, port, # Normal connect parms
- false, # Not reliable, the default for a paramaterized connection
- 5, # Connect redelay, the default for a paramaterized connection
- conn_hdrs) # The 1.1 connection parameters / headers
-puts "Connection connect complete"
-#
-raise "Unexpected protocol level" if conn.protocol != Stomp::SPL_11
-#
-conn.set_logger(logger) # Connection uses a logger
-sleep 65
-conn.set_logger(nil) # No logging
+ # Create a logger for demonstration purposes
+ logger = Slogger.new
+ # Connect - a paramaterized request.
+ conn = Stomp::Connection.new(login, passcode, host, port, # Normal connect parms
+ false, # Not reliable, the default for a paramaterized connection
+ 5, # Connect redelay, the default for a paramaterized connection
+ conn_hdrs) # The 1.1 connection parameters / headers
+ puts "Connection connect complete"
+ #
+ raise "Unexpected protocol level" if conn.protocol != Stomp::SPL_11
+ #
+ conn.set_logger(logger) # Connection uses a logger
+ sleep 65
+ conn.set_logger(nil) # No logging
+ #
+ conn.disconnect # Get out
+ puts "Connection disconnect complete"
+ end
+end
#
-conn.disconnect # Get out
-puts "Connection disconnect complete"
-
-
+e = HeartBeatExample1.new
+e.run
diff --git a/examples/consumer.rb b/examples/consumer.rb
index c782130..feeb300 100644
--- a/examples/consumer.rb
+++ b/examples/consumer.rb
@@ -2,20 +2,33 @@
require 'rubygems'
require 'stomp'
+#
+# == Example message consumer.
+#
+class ExampleConsumer
+ # Initialize.
+ def initialize
+ end
+ # Run example.
+ def run
+ client = Stomp::Client.new("failover://(stomp://:@localhost:61613,stomp://:@remotehost:61613)?initialReconnectDelay=5000&randomize=false&useExponentialBackOff=false")
+ puts "Subscribing ronaldo"
+ client.subscribe("/queue/ronaldo", {:ack => "client", "activemq.prefetchSize" => 1, "activemq.exclusive" => true }) do |msg|
+ File.open("file", "a") do |f|
+ f.write(msg.body)
+ f.write("\n----------------\n")
+ end
+ client.acknowledge(msg)
+ end
-client = Stomp::Client.new("failover://(stomp://:@localhost:61613,stomp://:@remotehost:61613)?initialReconnectDelay=5000&randomize=false&useExponentialBackOff=false")
-puts "Subscribing ronaldo"
-client.subscribe("/queue/ronaldo", {:ack => "client", "activemq.prefetchSize" => 1, "activemq.exclusive" => true }) do |msg|
- File.open("file", "a") do |f|
- f.write(msg.body)
- f.write("\n----------------\n")
+ loop do
+ sleep(1)
+ puts "."
+ end
end
-
- client.acknowledge(msg)
end
+#
+e = ExampleConsumer.new
+e.run
-loop do
- sleep(1)
- puts "."
-end
diff --git a/examples/get11conn_ex1.rb b/examples/get11conn_ex1.rb
index e2f7145..9adb79a 100644
--- a/examples/get11conn_ex1.rb
+++ b/examples/get11conn_ex1.rb
@@ -12,98 +12,106 @@ else
end
include Stomp11Common
#
-# Stomp 1.1 Receive Example 1
-# ===========================
+# == Stomp 1.1 Receive Example 1
#
# Purpose: to demonstrate receiving messages using Stomp 1.1.
#
-conn = get_connection() # Use helper method to obtain a Stomp#connection
-raise "Unexpected protocol level" if conn.protocol != Stomp::SPL_11
-#
-# To start receiving messages, you must first subscribe. This is similar
-# to using Stomp 1.0.
-#
-# However, with Stomp 1.1:
-#
-# * for subscribe, the 'id' header is now _required_
-# * for unsubscribe, the 'id' header is now _required_
-#
-# The 'id' header specifies a 'subscription id' that _must_ be unique for
-# the current session.
-#
-qname = "/queue/nodea.nodeb.nodec"
-#
-# Here is an example of allowed functionality in 1.0 that is not allowed in 1.1:
-#
-begin
- conn.subscribe qname
-rescue RuntimeError => sre
- puts "Rescue: #{sre}, #{sre.message}"
+class Receive11Example1
+ # Initialize.
+ def initialize
+ end
+ # Run example.
+ def run
+ conn = get_connection() # Use helper method to obtain a Stomp#connection
+ raise "Unexpected protocol level" if conn.protocol != Stomp::SPL_11
+ #
+ # To start receiving messages, you must first subscribe. This is similar
+ # to using Stomp 1.0.
+ #
+ # However, with Stomp 1.1:
+ #
+ # * for subscribe, the 'id' header is now _required_
+ # * for unsubscribe, the 'id' header is now _required_
+ #
+ # The 'id' header specifies a 'subscription id' that _must_ be unique for
+ # the current session.
+ #
+ qname = "/queue/nodea.nodeb.nodec"
+ #
+ # Here is an example of allowed functionality in 1.0 that is not allowed in 1.1:
+ #
+ begin
+ conn.subscribe qname
+ rescue RuntimeError => sre
+ puts "Rescue: #{sre}, #{sre.message}"
+ end
+ #
+ # So, you must specify an 'id' header. And it must be unique within the
+ # current session.
+ #
+ # You can build your own unique ids of course. That is a valid option.
+ # In order to provide you with some assistance in generating unique ids,
+ # two convenience methods are provided with the connection:
+ #
+ # * sha1 - generate a sha1 hash of some data you supply. This may be sufficient for many purposes.
+ # * uuid - generate a type 4 UUID. This would be sufficient in all cases.
+ #
+ # Get a sha1:
+ #
+ sha1 = conn.sha1(qname) # sha1 of the queue name perhaps
+ puts "Queue name: #{qname}, sha1: #{sha1}"
+ #
+ # Or perhaps a different sha1:
+ #
+ tn = Time.now.to_f.to_s # Maybe unique itself.
+ sha1 = conn.sha1(tn)
+ puts "Time now: #{tn}, sha1: #{sha1}"
+ #
+ # Or a Type 4 UUID:
+ #
+ uuid = conn.uuid()
+ puts "Type 4 UUID: #{uuid}"
+ #
+ # You can specify the 'id' in the subscribe call in one of two ways:
+ #
+ # a) In the headers parameter
+ # b) In the third positional parameter, the subId
+ #
+ # So, using the 'uuid', either:
+ #
+ # a) conn.subscribe qname, {'id' => uuid}
+ # b) conn.subscribe qname, {}, uuid
+ #
+ conn.subscribe qname, {'id' => uuid} # First style
+ #
+ # Within a session, you may not subscribe to the same subscription id.
+ #
+ begin
+ conn.subscribe qname, {'id' => uuid} # Second time
+ rescue RuntimeError => sre
+ puts "Rescue: #{sre}, #{sre.message}"
+ end
+ #
+ # Once you have subscribed, you may receive as usual
+ #
+ 1.upto(nmsgs()) do
+ received = conn.receive
+ puts "Received data: #{received.body}"
+ end
+ #
+ # For unsubscribe, you must use the 'id' you used on subscribe.
+ #
+ # You have the same options for placing this id in the headers or in the 3rd
+ # positional parameter.
+ #
+ conn.unsubscribe qname, {}, uuid # Second style
+ #
+ # And finally, disconnect.
+ #
+ conn.disconnect
+ end
end
#
-# So, you must specify an 'id' header. And it must be unique within the
-# current session.
-#
-# You can build your own unique ids of course. That is a valid option.
-# In order to provide you with some assistance in generating unique ids,
-# two convenience methods are provided with the connection:
-#
-# * sha1 - generate a sha1 hash of some data you supply. This may be sufficient for many purposes.
-# * uuid - generate a type 4 UUID. This would be sufficient in all cases.
-#
-# Get a sha1:
-#
-sha1 = conn.sha1(qname) # sha1 of the queue name perhaps
-puts "Queue name: #{qname}, sha1: #{sha1}"
-#
-# Or perhaps a different sha1:
-#
-tn = Time.now.to_f.to_s # Maybe unique itself.
-sha1 = conn.sha1(tn)
-puts "Time now: #{tn}, sha1: #{sha1}"
-#
-# Or a Type 4 UUID:
-#
-uuid = conn.uuid()
-puts "Type 4 UUID: #{uuid}"
-#
-# You can specify the 'id' in the subscribe call in one of two ways:
-#
-# a) In the headers parameter
-# b) In the third positional parameter, the subId
-#
-# So, using the 'uuid', either:
-#
-# a) conn.subscribe qname, {'id' => uuid}
-# b) conn.subscribe qname, {}, uuid
-#
-conn.subscribe qname, {'id' => uuid} # First style
-#
-# Within a session, you may not subscribe to the same subscription id.
-#
-begin
- conn.subscribe qname, {'id' => uuid} # Second time
-rescue RuntimeError => sre
- puts "Rescue: #{sre}, #{sre.message}"
-end
-#
-# Once you have subscribed, you may receive as usual
-#
-1.upto(nmsgs()) do
- received = conn.receive
- puts "Received data: #{received.body}"
-end
-#
-# For unsubscribe, you must use the 'id' you used on subscribe.
-#
-# You have the same options for placing this id in the headers or in the 3rd
-# positional parameter.
-#
-conn.unsubscribe qname, {}, uuid # Second style
-#
-# And finally, disconnect.
-#
-conn.disconnect
-
-
+e = Receive11Example1.new
+e.run
diff --git a/examples/get11conn_ex2.rb b/examples/get11conn_ex2.rb
index 6023c71..82413b8 100644
--- a/examples/get11conn_ex2.rb
+++ b/examples/get11conn_ex2.rb
@@ -12,58 +12,66 @@ else
end
include Stomp11Common
#
-# Stomp 1.1 Receive Example 2
-# ===========================
+# == Stomp 1.1 Receive Example 2
#
# Purpose: to demonstrate receiving messages using Stomp 1.1, and using
# 'ack => client'.
#
-conn = get_connection() # Use helper method to obtain a Stomp#connection
-raise "Unexpected protocol level" if conn.protocol != Stomp::SPL_11
-#
-qname = "/queue/nodea.nodeb.nodec"
-#
-uuid = conn.uuid()
-puts "Subscribe id: #{uuid}"
-#
-# Subscribe with client ack mode
-#
-conn.subscribe qname, {'id' => uuid, 'ack' => 'client'} #
-#
-# Once you have subscribed, you may receive as usual
-#
-1.upto(nmsgs()) do
- received = conn.receive
- puts "Received data: #{received.body}"
- #
- # We want now to ACK this message. In Stomp 1.0, a 'message-id' header was
- # required for the ACK. In Stomp 1.1, and additional header is required:
- #
- # * 'subscription' => id
- #
- msgid = received.headers['message-id']
- #
- # What you cannot do:
- #
- begin
- conn.ack msgid
- rescue RuntimeError => sre
- puts "Rescue: #{sre}, #{sre.message}"
+class Receive11Example2
+ # Initialize.
+ def initialize
+ end
+ # Run example.
+ def run
+ conn = get_connection() # Use helper method to obtain a Stomp#connection
+ raise "Unexpected protocol level" if conn.protocol != Stomp::SPL_11
+ #
+ qname = "/queue/nodea.nodeb.nodec"
+ #
+ uuid = conn.uuid()
+ puts "Subscribe id: #{uuid}"
+ #
+ # Subscribe with client ack mode
+ #
+ conn.subscribe qname, {'id' => uuid, 'ack' => 'client'} #
+ #
+ # Once you have subscribed, you may receive as usual
+ #
+ 1.upto(nmsgs()) do
+ received = conn.receive
+ puts "Received data: #{received.body}"
+ #
+ # We want now to ACK this message. In Stomp 1.0, a 'message-id' header was
+ # required for the ACK. In Stomp 1.1, and additional header is required:
+ #
+ # * 'subscription' => id
+ #
+ msgid = received.headers['message-id']
+ #
+ # What you cannot do:
+ #
+ begin
+ conn.ack msgid
+ rescue RuntimeError => sre
+ puts "Rescue: #{sre}, #{sre.message}"
+ end
+ #
+ # Try a valid 1.1 ACK
+ #
+ conn.ack msgid, {'subscription' => uuid}
+ puts "ACK - msgid: #{msgid}, subscription: #{uuid}"
+ end
+ #
+ # Unsubscribe
+ #
+ conn.unsubscribe qname, {}, uuid # Second style
+ #
+ # And finally, disconnect.
+ #
+ conn.disconnect
end
- #
- # Try a valid 1.1 ACK
- #
- conn.ack msgid, {'subscription' => uuid}
- puts "ACK - msgid: #{msgid}, subscription: #{uuid}"
end
#
-# Unsubscribe
-#
-conn.unsubscribe qname, {}, uuid # Second style
-#
-# And finally, disconnect.
-#
-conn.disconnect
-
-
+e = Receive11Example2.new
+e.run
diff --git a/examples/logexamp.rb b/examples/logexamp.rb
index a3d409f..f470d22 100644
--- a/examples/logexamp.rb
+++ b/examples/logexamp.rb
@@ -4,64 +4,78 @@ require 'rubygems'
require 'stomp'
require 'logger' # for the 'local' logger
#
-$:.unshift(File.dirname(__FILE__))
+if Kernel.respond_to?(:require_relative)
+ require_relative("./slogger")
+else
+ $LOAD_PATH << File.dirname(__FILE__)
+ require "slogger"
+end
#
-require 'slogger'
+# == A STOMP::Connection program which uses the callback logging facility.
#
-# A STOMP::Connection program which uses the callback logging facility.
-#
-llog = Logger::new(STDOUT)
-llog.level = Logger::DEBUG
-llog.debug "LE Starting"
+class LoggerExample
+ # Initialize.
+ def initialize
+ end
+ # Run example.
+ def run
+ llog = Logger::new(STDOUT)
+ llog.level = Logger::DEBUG
+ llog.debug "LE Starting"
-# //////////////////////////////////////////////////////////////////////////////
-mylog = Slogger::new # The client provided STOMP callback logger
+ # //////////////////////////////////////////////////////////////////////////////
+ mylog = Slogger::new # The client provided STOMP callback logger
-# //////////////////////////////////////////////////////////////////////////////
-user = ENV['STOMP_USER'] ? ENV['STOMP_USER'] : 'guest'
-password = ENV['STOMP_PASSWORD'] ? ENV['STOMP_PASSWORD'] : 'guest'
-host = ENV['STOMP_HOST'] ? ENV['STOMP_HOST'] : 'localhost'
-port = ENV['STOMP_PORT'] ? ENV['STOMP_PORT'].to_i : 61613
-# //////////////////////////////////////////////////////////////////////////////
-# A hash type connect *MUST* be used to enable callback logging.
-# //////////////////////////////////////////////////////////////////////////////
-hash = { :hosts => [
- {:login => user, :passcode => password, :host => 'noonehome', :port => 2525},
- {:login => user, :passcode => password, :host => host, :port => port},
- ],
- :logger => mylog, # This enables callback logging!
- :max_reconnect_attempts => 5,
- }
+ # //////////////////////////////////////////////////////////////////////////////
+ user = ENV['STOMP_USER'] ? ENV['STOMP_USER'] : 'guest'
+ password = ENV['STOMP_PASSWORD'] ? ENV['STOMP_PASSWORD'] : 'guest'
+ host = ENV['STOMP_HOST'] ? ENV['STOMP_HOST'] : 'localhost'
+ port = ENV['STOMP_PORT'] ? ENV['STOMP_PORT'].to_i : 61613
+ # //////////////////////////////////////////////////////////////////////////////
+ # A hash type connect *MUST* be used to enable callback logging.
+ # //////////////////////////////////////////////////////////////////////////////
+ hash = { :hosts => [
+ {:login => user, :passcode => password, :host => 'noonehome', :port => 2525},
+ {:login => user, :passcode => password, :host => host, :port => port},
+ ],
+ :logger => mylog, # This enables callback logging!
+ :max_reconnect_attempts => 5,
+ }
-# //////////////////////////////////////////////////////////////////////////////
-# For a Connection:
-llog.debug "LE Connection processing starts"
-conn = Stomp::Connection.new(hash)
-conn.disconnect
-# //////////////////////////////////////////////////////////////////////////////
-llog.debug "LE Connection processing complete"
+ # //////////////////////////////////////////////////////////////////////////////
+ # For a Connection:
+ llog.debug "LE Connection processing starts"
+ conn = Stomp::Connection.new(hash)
+ conn.disconnect
+ # //////////////////////////////////////////////////////////////////////////////
+ llog.debug "LE Connection processing complete"
-# //////////////////////////////////////////////////////////////////////////////
-# For a Client:
-llog.debug "LE Client processing starts"
-conn = Stomp::Client.new(hash)
-conn.close
-# //////////////////////////////////////////////////////////////////////////////
-llog.debug "LE Client processing complete"
+ # //////////////////////////////////////////////////////////////////////////////
+ # For a Client:
+ llog.debug "LE Client processing starts"
+ conn = Stomp::Client.new(hash)
+ conn.close
+ # //////////////////////////////////////////////////////////////////////////////
+ llog.debug "LE Client processing complete"
-# //////////////////////////////////////////////////////////////////////////////
-# For a Connection with other calls:
-llog.debug "LE Connection Enhanced processing starts"
-conn = Stomp::Connection.new(hash)
-#
-dest = "/queue/loggerq1"
-conn.publish dest, "a logger message"
-conn.subscribe dest
-msg = conn.receive
-conn.disconnect
-# //////////////////////////////////////////////////////////////////////////////
-llog.debug "LE Connection Enhanced processing complete"
+ # //////////////////////////////////////////////////////////////////////////////
+ # For a Connection with other calls:
+ llog.debug "LE Connection Enhanced processing starts"
+ conn = Stomp::Connection.new(hash)
+ #
+ dest = "/queue/loggerq1"
+ conn.publish dest, "a logger message"
+ conn.subscribe dest
+ msg = conn.receive
+ conn.disconnect
+ # //////////////////////////////////////////////////////////////////////////////
+ llog.debug "LE Connection Enhanced processing complete"
+
+ # //////////////////////////////////////////////////////////////////////////////
+ llog.debug "LE Ending"
+ end
+end
+e = LoggerExample.new
+e.run
-# //////////////////////////////////////////////////////////////////////////////
-llog.debug "LE Ending"
diff --git a/examples/logexamp_ssl.rb b/examples/logexamp_ssl.rb
index 3def39b..da81dbd 100644
--- a/examples/logexamp_ssl.rb
+++ b/examples/logexamp_ssl.rb
@@ -4,64 +4,78 @@ require 'rubygems'
require 'stomp'
require 'logger' # for the 'local' logger
#
-$:.unshift(File.dirname(__FILE__))
+if Kernel.respond_to?(:require_relative)
+ require_relative("./slogger")
+else
+ $LOAD_PATH << File.dirname(__FILE__)
+ require "slogger"
+end
#
-require 'slogger'
+# == A STOMP::Connection program which uses the callback logging facility.
#
-# A STOMP::Connection program which uses the callback logging facility.
-#
-llog = Logger::new(STDOUT)
-llog.level = Logger::DEBUG
-llog.debug "LESSL Starting"
+class SSLLoggerExample
+ # Initialize.
+ def initialize
+ end
+ # Run example.
+ def run
+ llog = Logger::new(STDOUT)
+ llog.level = Logger::DEBUG
+ llog.debug "LESSL Starting"
-# //////////////////////////////////////////////////////////////////////////////
-mylog = Slogger::new # The client provided STOMP callback logger
+ # //////////////////////////////////////////////////////////////////////////////
+ mylog = Slogger::new # The client provided STOMP callback logger
-# //////////////////////////////////////////////////////////////////////////////
-user = ENV['STOMP_USER'] ? ENV['STOMP_USER'] : 'guest'
-password = ENV['STOMP_PASSWORD'] ? ENV['STOMP_PASSWORD'] : 'guest'
-host = ENV['STOMP_HOST'] ? ENV['STOMP_HOST'] : 'localhost'
-port = ENV['STOMP_PORT'] ? ENV['STOMP_PORT'].to_i : 61612
-# //////////////////////////////////////////////////////////////////////////////
-# A hash type connect *MUST* be used to enable callback logging.
-# //////////////////////////////////////////////////////////////////////////////
-hash = { :hosts => [
- {:login => user, :passcode => password, :host => host, :port => port,
- :ssl => true}, # Or provide your insance of SSLParams instead
- ],
- :logger => mylog, # This enables callback logging!
- :max_reconnect_attempts => 2,
- }
+ # //////////////////////////////////////////////////////////////////////////////
+ user = ENV['STOMP_USER'] ? ENV['STOMP_USER'] : 'guest'
+ password = ENV['STOMP_PASSWORD'] ? ENV['STOMP_PASSWORD'] : 'guest'
+ host = ENV['STOMP_HOST'] ? ENV['STOMP_HOST'] : 'localhost'
+ port = ENV['STOMP_PORT'] ? ENV['STOMP_PORT'].to_i : 61612
+ # //////////////////////////////////////////////////////////////////////////////
+ # A hash type connect *MUST* be used to enable callback logging.
+ # //////////////////////////////////////////////////////////////////////////////
+ hash = { :hosts => [
+ {:login => user, :passcode => password, :host => host, :port => port,
+ :ssl => true}, # Or provide your insance of SSLParams instead
+ ],
+ :logger => mylog, # This enables callback logging!
+ :max_reconnect_attempts => 2,
+ }
-# //////////////////////////////////////////////////////////////////////////////
-# For a Connection:
-llog.debug "LESSL Connection processing starts"
-conn = Stomp::Connection.new(hash)
-conn.disconnect
-# //////////////////////////////////////////////////////////////////////////////
-llog.debug "LESSL Connection processing complete"
+ # //////////////////////////////////////////////////////////////////////////////
+ # For a Connection:
+ llog.debug "LESSL Connection processing starts"
+ conn = Stomp::Connection.new(hash)
+ conn.disconnect
+ # //////////////////////////////////////////////////////////////////////////////
+ llog.debug "LESSL Connection processing complete"
-# //////////////////////////////////////////////////////////////////////////////
-# For a Client:
-llog.debug "LESSL Client processing starts"
-conn = Stomp::Client.new(hash)
-conn.close
-# //////////////////////////////////////////////////////////////////////////////
-llog.debug "LESSL Client processing complete"
+ # //////////////////////////////////////////////////////////////////////////////
+ # For a Client:
+ llog.debug "LESSL Client processing starts"
+ conn = Stomp::Client.new(hash)
+ conn.close
+ # //////////////////////////////////////////////////////////////////////////////
+ llog.debug "LESSL Client processing complete"
-# //////////////////////////////////////////////////////////////////////////////
-# For a Connection with other calls:
-llog.debug "LESSL Connection Enhanced processing starts"
-conn = Stomp::Connection.new(hash)
-#
-dest = "/queue/loggerq1"
-conn.publish dest, "a logger message"
-conn.subscribe dest
-msg = conn.receive
-conn.disconnect
-# //////////////////////////////////////////////////////////////////////////////
-llog.debug "LESSL Connection Enhanced processing complete"
+ # //////////////////////////////////////////////////////////////////////////////
+ # For a Connection with other calls:
+ llog.debug "LESSL Connection Enhanced processing starts"
+ conn = Stomp::Connection.new(hash)
+ #
+ dest = "/queue/loggerq1"
+ conn.publish dest, "a logger message"
+ conn.subscribe dest
+ msg = conn.receive
+ conn.disconnect
+ # //////////////////////////////////////////////////////////////////////////////
+ llog.debug "LESSL Connection Enhanced processing complete"
-# //////////////////////////////////////////////////////////////////////////////
-llog.debug "LESSL Ending"
+ # //////////////////////////////////////////////////////////////////////////////
+ llog.debug "LESSL Ending"
+ end
+end
+#
+e = SSLLoggerExample.new
+e.run
diff --git a/examples/publisher.rb b/examples/publisher.rb
index 8e09cb3..aa7139a 100644
--- a/examples/publisher.rb
+++ b/examples/publisher.rb
@@ -2,18 +2,29 @@
require 'rubygems'
require 'stomp'
+#
+# == Example message publisher
+#
+class ExamplePublisher
+ # Initialize.
+ def initialize
+ end
+ # Run example.
+ def run
+ client = Stomp::Client.new("failover://(stomp://:@localhost:61613,stomp://:@remotehost:61613)?initialReconnectDelay=5000&randomize=false&useExponentialBackOff=false")
+ message = "ronaldo #{ARGV[0]}"
-#client = Stomp::Client.new("", "", "localhost", 61613)
-
-client = Stomp::Client.new("failover://(stomp://:@localhost:61613,stomp://:@remotehost:61613)?initialReconnectDelay=5000&randomize=false&useExponentialBackOff=false")
-message = "ronaldo #{ARGV[0]}"
-
-for i in (1..300)
- puts "Sending message"
- client.send("/queue/ronaldo", "#{i}: #{message}", {:persistent => true})
- puts "(#{Time.now})Message sent: #{i}"
- sleep 1
+ for i in (1..50)
+ puts "Sending message"
+ client.publish("/queue/ronaldo", "#{i}: #{message}", {:persistent => true})
+ puts "(#{Time.now})Message sent: #{i}"
+ sleep 0.2
+ end
+ end
end
+#
+e = ExamplePublisher.new
+e.run
diff --git a/examples/put11conn_ex1.rb b/examples/put11conn_ex1.rb
index 83b62a6..d2f7e81 100644
--- a/examples/put11conn_ex1.rb
+++ b/examples/put11conn_ex1.rb
@@ -11,35 +11,46 @@ else
require "stomp11_common"
end
include Stomp11Common
+
#
-# Stomp 1.1 Publish Example
-# =========================
+# == Stomp 1.1 Publish Example
#
# Purpose: to demonstrate sending messages using Stomp 1.1.
#
-conn = get_connection() # Use helper method to obtain a Stomp#connection
-raise "Unexpected protocol level" if conn.protocol != Stomp::SPL_11
-#
-# Publishing simple data is as it was with Stomp 1.0.
-#
-# Note: Stomp 1.1 brokers seem to prefer using '.' as delimiters in queue
-# name spaces. Hence, the queue name used here.
-#
-qname = "/queue/nodea.nodeb.nodec"
-data = "message payload"
-headers = {}
-#
-# The 'data' and 'headers' may be omitted, as with Stomp 1.0
-#
-1.upto(nmsgs()) do |i|
- msg = "#{data}: #{i}"
- conn.publish qname, msg , headers
- puts "Sent data: #{msg}"
+class Publish11Example1
+ # Initialize.
+ def initialize
+ end
+ # Run example.
+ def run
+ conn = get_connection() # Use helper method to obtain a Stomp#connection
+ raise "Unexpected protocol level" if conn.protocol != Stomp::SPL_11
+ #
+ # Publishing simple data is as it was with Stomp 1.0.
+ #
+ # Note: Stomp 1.1 brokers seem to prefer using '.' as delimiters in queue
+ # name spaces. Hence, the queue name used here.
+ #
+ qname = "/queue/nodea.nodeb.nodec"
+ data = "message payload"
+ headers = {}
+ #
+ # The 'data' and 'headers' may be omitted, as with Stomp 1.0
+ #
+ puts "Writing #{nmsgs()} messages."
+ 1.upto(nmsgs()) do |i|
+ msg = "#{data}: #{i}"
+ conn.publish qname, msg , headers
+ puts "Sent data: #{msg}"
+ end
+ #
+ # And finally, disconnect.
+ #
+ conn.disconnect
+ end
end
#
-# And finally, disconnect.
-#
-conn.disconnect
-
+e = Publish11Example1.new
+e.run
diff --git a/examples/putget11_rh1.rb b/examples/putget11_rh1.rb
index fe55650..7373946 100644
--- a/examples/putget11_rh1.rb
+++ b/examples/putget11_rh1.rb
@@ -12,72 +12,82 @@ else
end
include Stomp11Common
#
-# Stomp 1.1 Send/Receive Example - Repeated Headers
-# =================================================
+# == Stomp 1.1 Send/Receive Example - Repeated Headers
#
# Purpose: to demonstrate sending and receiving using Stomp 1.1, and an unusual
# aspect of the specification. What is demonstrated here is the use of
# 'repeated headers'. Note that brokers MAY support repeated headers as
-# demonstrated, but are not required to provide this support. This example
-# should run against the Apollo broker. It will *not* currently run against
+# demonstrated, but are not required to provide this support. This example
+# should run against the Apollo broker. It will *not* currently run against
# RabbitMQ. YMMV depending on your broker.
#
# See: http://stomp.github.com/stomp-specification-1.1.html#Repeated_Header_Entries
#
-conn = get_connection() # Use helper method to obtain a Stomp#connection
-raise "Unexpected protocol level" if conn.protocol != Stomp::SPL_11
-#
-# The gem supports repeated headers by allowing the 'value' part of a header
-# to be an Array instance.
-#
-# On 'publish', all values in the Array are placed on the wire and sent to the
-# broker in order.
-#
-# On 'receive', if repeated headers are detected, an Array instance is created
-# to hold the repeated values. This is presented the the calling client to
-# be processed per client requirements.
-#
-qname = "/queue/nodea.nodeb.nodec"
-data = "message payload: #{Time.now.to_f}"
-key2_repeats = ["key2val3", "key2val2", "key2val1" ]
-headers = {"key1" => "value1", # A normal header
- "key2" => key2_repeats, # A repeated header
- "key3" => "value3", # Another normal header
-}
-#
-# Ship it.
-#
-conn.publish qname, data , headers
-puts "Sent data: #{data}"
-#
-# Receive phase.
-#
-uuid = conn.uuid()
-conn.subscribe qname, {"id" => uuid}
-received = conn.receive
-conn.unsubscribe qname, {"id" => uuid}
-#
-# Check that we received what we sent.
-#
-raise "Unexpected payload" unless data == received.body
-raise "Missing key" unless received.headers["key2"]
-raise "Repeats not present" unless received.headers.has_value?(key2_repeats)
-raise "Unexpected repeat values" unless key2_repeats == received.headers["key2"]
-#
-# Demonstrate how to process repeated headers received by display of those
-# received headers for a visual check.
-#
-received.headers.each_pair do |k,v|
- if v.is_a?(Array)
- v.each do |e|
- puts "#{k}:#{e}"
+class RepeatedHeadersExample
+ # Initialize.
+ def initialize
+ end
+ # Run example.
+ def run
+ conn = get_connection() # Use helper method to obtain a Stomp#connection
+ raise "Unexpected protocol level" if conn.protocol != Stomp::SPL_11
+ #
+ # The gem supports repeated headers by allowing the 'value' part of a header
+ # to be an Array instance.
+ #
+ # On 'publish', all values in the Array are placed on the wire and sent to the
+ # broker in order.
+ #
+ # On 'receive', if repeated headers are detected, an Array instance is created
+ # to hold the repeated values. This is presented the the calling client to
+ # be processed per client requirements.
+ #
+ qname = "/queue/nodea.nodeb.nodec"
+ data = "message payload: #{Time.now.to_f}"
+ key2_repeats = ["key2val3", "key2val2", "key2val1" ]
+ headers = {"key1" => "value1", # A normal header
+ "key2" => key2_repeats, # A repeated header
+ "key3" => "value3", # Another normal header
+ }
+ #
+ # Ship it.
+ #
+ conn.publish qname, data , headers
+ puts "Sent data: #{data}"
+ #
+ # Receive phase.
+ #
+ uuid = conn.uuid()
+ conn.subscribe qname, {"id" => uuid}
+ received = conn.receive
+ conn.unsubscribe qname, {"id" => uuid}
+ #
+ # Check that we received what we sent.
+ #
+ raise "Unexpected payload" unless data == received.body
+ raise "Missing key" unless received.headers["key2"]
+ raise "Repeats not present" unless received.headers.has_value?(key2_repeats)
+ raise "Unexpected repeat values" unless key2_repeats == received.headers["key2"]
+ #
+ # Demonstrate how to process repeated headers received by display of those
+ # received headers for a visual check.
+ #
+ received.headers.each_pair do |k,v|
+ if v.is_a?(Array)
+ v.each do |e|
+ puts "#{k}:#{e}"
+ end
+ else
+ puts "#{k}:#{v}"
+ end
end
- else
- puts "#{k}:#{v}"
+ #
+ # And finally, disconnect.
+ #
+ conn.disconnect
end
end
#
-# And finally, disconnect.
-#
-conn.disconnect
+e = RepeatedHeadersExample.new
+e.run
diff --git a/examples/slogger.rb b/examples/slogger.rb
index 70210b5..b6e81ee 100644
--- a/examples/slogger.rb
+++ b/examples/slogger.rb
@@ -1,53 +1,51 @@
# -*- encoding: utf-8 -*-
-=begin
-
-Example STOMP call back logger class.
-
-Optional callback methods:
-
- on_connecting: connection starting
- on_connected: successful connect
- on_connectfail: unsuccessful connect (will usually be retried)
- on_disconnect: successful disconnect
-
- on_miscerr: on miscellaneous xmit/recv errors
-
- on_publish: publish called
- on_subscribe: subscribe called
- on_receive: receive called and successful
-
- on_ssl_connecting: SSL connection starting
- on_ssl_connected: successful SSL connect
- on_ssl_connectfail: unsuccessful SSL connect (will usually be retried)
-
- on_hbread_fail: unsuccessful Heartbeat read
- on_hbwrite_fail: unsuccessful Heartbeat write
-
-All methods are optional, at the user's requirements.
-
-If a method is not provided, it is not called (of course.)
-
-IMPORTANT NOTE: in general, call back logging methods *SHOULD* not raise exceptions,
-otherwise the underlying STOMP connection may fail in mysterious ways.
-
-There are two useful exceptions to this rule for:
-
- on_connectfail
- on_ssl_connectfail
-
-These two methods can raise a Stomp::Errors::LoggerConnectionError. If this
-exception is raised, it is passed up the chain to the caller.
-
-Callback parameters: are a copy of the @parameters instance variable for
-the Stomp::Connection.
-
-=end
-
require 'logger' # use the standard Ruby logger .....
+# == Example STOMP call back logger class.
+#
+# Optional callback methods:
+#
+# * on_connecting: connection starting
+# * on_connected: successful connect
+# * on_connectfail: unsuccessful connect (will usually be retried)
+# * on_disconnect: successful disconnect
+#
+# * on_miscerr: on miscellaneous xmit/recv errors
+#
+# * on_publish: publish called
+# * on_subscribe: subscribe called
+# * on_receive: receive called and successful
+#
+# * on_ssl_connecting: SSL connection starting
+# * on_ssl_connected: successful SSL connect
+# * on_ssl_connectfail: unsuccessful SSL connect (will usually be retried)
+#
+# * on_hbread_fail: unsuccessful Heartbeat read
+# * on_hbwrite_fail: unsuccessful Heartbeat write
+# * on_hbfire: on any send or receive heartbeat
+#
+# All methods are optional, at the user's requirements.
+#
+# If a method is not provided, it is not called (of course.)
+#
+# IMPORTANT NOTE: in general, call back logging methods *SHOULD* not raise exceptions,
+# otherwise the underlying STOMP connection may fail in mysterious ways.
+#
+# There are two useful exceptions to this rule for:
+#
+# * on_connectfail
+# * on_ssl_connectfail
+#
+# These two methods can raise a Stomp::Errors::LoggerConnectionError. If this
+# exception is raised, it is passed up the chain to the caller.
+#
+# Callback parameters: are a copy of the @parameters instance variable for
+# the Stomp::Connection.
+#
class Slogger
- #
+
+ # Initialize a new callback logger instance.
def initialize(init_parms = nil)
@log = Logger::new(STDOUT) # User preference
@log.level = Logger::DEBUG # User preference
@@ -105,7 +103,7 @@ class Slogger
end
end
- # Subscribe
+ # Log Subscribe
def on_subscribe(parms, headers)
begin
@log.debug "Subscribe Parms #{info(parms)}"
@@ -115,7 +113,7 @@ class Slogger
end
end
- # Publish
+ # Log Publish
def on_publish(parms, message, headers)
begin
@log.debug "Publish Parms #{info(parms)}"
@@ -126,7 +124,7 @@ class Slogger
end
end
- # Receive
+ # Log Receive
def on_receive(parms, result)
begin
@log.debug "Receive Parms #{info(parms)}"
@@ -136,7 +134,7 @@ class Slogger
end
end
- # Stomp 1.1+ - heart beat read (receive) failed
+ # Stomp 1.1+ - heart beat read (receive) failed.
def on_hbread_fail(parms, ticker_data)
begin
@log.debug "Hbreadf Parms #{info(parms)}"
@@ -146,7 +144,7 @@ class Slogger
end
end
- # Stomp 1.1+ - heart beat send (transmit) failed
+ # Stomp 1.1+ - heart beat send (transmit) failed.
def on_hbwrite_fail(parms, ticker_data)
begin
@log.debug "Hbwritef Parms #{info(parms)}"
@@ -156,6 +154,7 @@ class Slogger
end
end
+ # Log SSL connection start.
def on_ssl_connecting(parms)
begin
@log.debug "SSL Connecting Parms #{info(parms)}"
@@ -164,6 +163,7 @@ class Slogger
end
end
+ # Log a successful SSL connect.
def on_ssl_connected(parms)
begin
@log.debug "SSL Connected Parms #{info(parms)}"
@@ -172,6 +172,7 @@ class Slogger
end
end
+ # Log an unsuccessful SSL connect.
def on_ssl_connectfail(parms)
begin
@log.debug "SSL Connect Fail Parms #{info(parms)}"
@@ -186,11 +187,22 @@ class Slogger
=end
end
+ # Log heart beat fires
+ def on_hbfire(parms, srind, curt)
+ begin
+ @log.debug "HeartBeat Fire Parms #{info(parms)}"
+ @log.debug "HeartBeat Fire Send/Receive #{srind}"
+ rescue
+ @log.debug "HeartBeat Fire oops"
+ end
+ end
+
private
+ # Example information extract.
def info(parms)
#
- # Available in the Hash:
+ # Available in the parms Hash:
# parms[:cur_host]
# parms[:cur_port]
# parms[:cur_login]
@@ -199,11 +211,12 @@ class Slogger
# parms[:cur_recondelay]
# parms[:cur_parseto]
# parms[:cur_conattempts]
+ # parms[:openstat]
#
# For the on_ssl_connectfail callback these are also available:
# parms[:ssl_exception]
#
- "Host: #{parms[:cur_host]}, Port: #{parms[:cur_port]}, Login: Port: #{parms[:cur_login]}, Passcode: #{parms[:cur_passcode]}, ssl: #{parms[:cur_ssl]}"
+ "Host: #{parms[:cur_host]}, Port: #{parms[:cur_port]}, Login: #{parms[:cur_login]}, Passcode: #{parms[:cur_passcode]}, ssl: #{parms[:cur_ssl]}"
end
end # of class
diff --git a/examples/ssl_uc1.rb b/examples/ssl_uc1.rb
index 5a955c0..81f545d 100644
--- a/examples/ssl_uc1.rb
+++ b/examples/ssl_uc1.rb
@@ -6,7 +6,7 @@
require "rubygems"
require "stomp"
#
-# SSL Use Case 1 - server does *not* authenticate client, client does *not* authenticate server
+# == SSL Use Case 1 - server does *not* authenticate client, client does *not* authenticate server
#
# Subcase 1.A - Message broker configuration does *not* require client authentication
#
@@ -18,18 +18,29 @@ require "stomp"
#
# - Expect connection failure (broker must be sent a valid client certificate)
#
-ssl_opts = Stomp::SSLParams.new
-hash = { :hosts => [
- {:login => 'guest', :passcode => 'guest', :host => 'localhost', :port => 61612, :ssl => ssl_opts},
+class ExampleSSL1
+ # Initialize.
+ def initialize
+ end
+ # Run example.
+ def run
+ ssl_opts = Stomp::SSLParams.new
+ hash = { :hosts => [
+ {:login => 'guest', :passcode => 'guest', :host => 'localhost', :port => 61612, :ssl => ssl_opts},
],
- :reliable => false, # YMMV, to test this in a sane manner
+ :reliable => false, # YMMV, to test this in a sane manner
}
-#
-puts "Connect starts, SSL Use Case 1"
-c = Stomp::Connection.new(hash)
-puts "Connect completed"
-puts "SSL Verify Result: #{ssl_opts.verify_result}"
-# puts "SSL Peer Certificate:\n#{ssl_opts.peer_cert}"
-#
-c.disconnect
+ #
+ puts "Connect starts, SSL Use Case 1"
+ c = Stomp::Connection.new(hash)
+ puts "Connect completed"
+ puts "SSL Verify Result: #{ssl_opts.verify_result}"
+ # puts "SSL Peer Certificate:\n#{ssl_opts.peer_cert}"
+ #
+ c.disconnect
+ end
+end
+#
+e = ExampleSSL1.new
+e.run
diff --git a/examples/ssl_uc1_ciphers.rb b/examples/ssl_uc1_ciphers.rb
index 4019ede..dab4ded 100644
--- a/examples/ssl_uc1_ciphers.rb
+++ b/examples/ssl_uc1_ciphers.rb
@@ -6,28 +6,41 @@
require "rubygems"
require "stomp"
#
+# == SSL Use Case 1 - User Supplied Ciphers
+#
# If you need your own ciphers list, this is how.
# Stomp's default list will work in many cases. If you need to use this, you
# will know it because SSL connect will fail. In that case, determining
# _what_ should be in the list is your responsibility.
#
-ciphers_list = [["DHE-RSA-AES256-SHA", "TLSv1/SSLv3", 256, 256], ["DHE-DSS-AES256-SHA", "TLSv1/SSLv3", 256, 256], ["AES256-SHA", "TLSv1/SSLv3", 256, 256], ["EDH-RSA-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["EDH-DSS-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["DHE-RSA-AES128-SHA", "TLSv1/SSLv3", 128, 128], ["DHE-DSS-AES128-SHA", "TLSv1/SSLv3", 128, 128], ["AES128-SHA", "TLSv1/SSLv3", 128, 128], ["RC4-SHA", "TLSv1/SSLv3", 128, 128], ["RC4-MD5", "TLSv1/SSLv3", 128, 128], ["EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56],
-["DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["EXP-EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-RC2-CBC-MD5", "TLSv1/SSLv3", 40, 128], ["EXP-RC4-MD5", "TLSv1/SSLv3", 40, 128]]
+class ExampleSSL1C
+ # Initialize.
+ def initialize
+ end
+ # Run example.
+ def run
+ ciphers_list = [["DHE-RSA-AES256-SHA", "TLSv1/SSLv3", 256, 256], ["DHE-DSS-AES256-SHA", "TLSv1/SSLv3", 256, 256], ["AES256-SHA", "TLSv1/SSLv3", 256, 256], ["EDH-RSA-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["EDH-DSS-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["DHE-RSA-AES128-SHA", "TLSv1/SSLv3", 128, 128], ["DHE-DSS-AES128-SHA", "TLSv1/SSLv3", 128, 128], ["AES128-SHA", "TLSv1/SSLv3", 128, 128], ["RC4-SHA", "TLSv1/SSLv3", 128, 128], ["RC4-MD5", "TLSv1/SSLv3", 128, 128], ["EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56],
+ ["DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["EXP-EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-RC2-CBC-MD5", "TLSv1/SSLv3", 40, 128], ["EXP-RC4-MD5", "TLSv1/SSLv3", 40, 128]]
-ssl_opts = Stomp::SSLParams.new(:ciphers => ciphers_list)
+ ssl_opts = Stomp::SSLParams.new(:ciphers => ciphers_list)
-#
-# SSL Use Case 1
-#
-hash = { :hosts => [
- {:login => 'guest', :passcode => 'guest', :host => 'localhost', :port => 61612, :ssl => ssl_opts},
+ #
+ # SSL Use Case 1
+ #
+ hash = { :hosts => [
+ {:login => 'guest', :passcode => 'guest', :host => 'localhost', :port => 61612, :ssl => ssl_opts},
]
}
-#
-puts "Connect starts, SSL Use Case 1"
-c = Stomp::Connection.new(hash)
-puts "Connect completed"
-puts "SSL Verify Result: #{ssl_opts.verify_result}"
-#
-c.disconnect
+ #
+ puts "Connect starts, SSL Use Case 1"
+ c = Stomp::Connection.new(hash)
+ puts "Connect completed"
+ puts "SSL Verify Result: #{ssl_opts.verify_result}"
+ #
+ c.disconnect
+ end
+end
+#
+e = ExampleSSL1C.new
+e.run
diff --git a/examples/ssl_uc2.rb b/examples/ssl_uc2.rb
index 0036502..6e4d049 100644
--- a/examples/ssl_uc2.rb
+++ b/examples/ssl_uc2.rb
@@ -6,7 +6,7 @@
require "rubygems"
require "stomp"
#
-# SSL Use Case 2 - server does *not* authenticate client, client *does* authenticate server
+# == SSL Use Case 2 - server does *not* authenticate client, client *does* authenticate server
#
# Subcase 2.A - Message broker configuration does *not* require client authentication
#
@@ -18,21 +18,31 @@ require "stomp"
#
# - Expect connection failure (broker must be sent a valid client certificate)
#
-ts_flist = []
-ts_flist << "/home/gmallard/sslwork/twocas_tj/serverCA/ServerTJCA.crt"
-ssl_opts = Stomp::SSLParams.new(:ts_files => ts_flist.join(","))
-#
-hash = { :hosts => [
- {:login => 'guest', :passcode => 'guest', :host => 'localhost', :port => 61612, :ssl => ssl_opts},
+class ExampleSSL2
+ # Initialize.
+ def initialize
+ end
+ # Run example.
+ def run
+ ts_flist = []
+ ts_flist << "/home/gmallard/sslwork/twocas_tj/serverCA/ServerTJCA.crt"
+ ssl_opts = Stomp::SSLParams.new(:ts_files => ts_flist.join(","))
+ #
+ hash = { :hosts => [
+ {:login => 'guest', :passcode => 'guest', :host => 'localhost', :port => 61612, :ssl => ssl_opts},
],
- :reliable => false, # YMMV, to test this in a sane manner
+ :reliable => false, # YMMV, to test this in a sane manner
}
-#
-puts "Connect starts, SSL Use Case 2"
-c = Stomp::Connection.new(hash)
-puts "Connect completed"
-puts "SSL Verify Result: #{ssl_opts.verify_result}"
-# puts "SSL Peer Certificate:\n#{ssl_opts.peer_cert}"
-c.disconnect
-
+ #
+ puts "Connect starts, SSL Use Case 2"
+ c = Stomp::Connection.new(hash)
+ puts "Connect completed"
+ puts "SSL Verify Result: #{ssl_opts.verify_result}"
+ # puts "SSL Peer Certificate:\n#{ssl_opts.peer_cert}"
+ c.disconnect
+ end
+end
+#
+e = ExampleSSL2.new
+e.run
diff --git a/examples/ssl_uc2_ciphers.rb b/examples/ssl_uc2_ciphers.rb
index f718d1b..50a7a00 100644
--- a/examples/ssl_uc2_ciphers.rb
+++ b/examples/ssl_uc2_ciphers.rb
@@ -6,29 +6,42 @@
require "rubygems"
require "stomp"
#
+# == SSL Use Case 2 - User Supplied Ciphers
+#
# If you need your own ciphers list, this is how.
# Stomp's default list will work in many cases. If you need to use this, you
# will know it because SSL connect will fail. In that case, determining
# _what_ should be in the list is your responsibility.
#
-ciphers_list = [["DHE-RSA-AES256-SHA", "TLSv1/SSLv3", 256, 256], ["DHE-DSS-AES256-SHA", "TLSv1/SSLv3", 256, 256], ["AES256-SHA", "TLSv1/SSLv3", 256, 256], ["EDH-RSA-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["EDH-DSS-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["DHE-RSA-AES128-SHA", "TLSv1/SSLv3", 128, 128], ["DHE-DSS-AES128-SHA", "TLSv1/SSLv3", 128, 128], ["AES128-SHA", "TLSv1/SSLv3", 128, 128], ["RC4-SHA", "TLSv1/SSLv3", 128, 128], ["RC4-MD5", "TLSv1/SSLv3", 128, 128], ["EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56],
-["DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["EXP-EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-RC2-CBC-MD5", "TLSv1/SSLv3", 40, 128], ["EXP-RC4-MD5", "TLSv1/SSLv3", 40, 128]]
-#
-# SSL Use Case 2
-#
-ssl_opts = Stomp::SSLParams.new(:key_file => "/home/gmallard/sslwork/twocas_tj/clientCA/ClientTJ.key",
- :cert_file => "/home/gmallard/sslwork/twocas_tj/clientCA/ClientTJ.crt", :ciphers => ciphers_list)
-
-#
-hash = { :hosts => [
- {:login => 'guest', :passcode => 'guest', :host => 'localhost', :port => 61612, :ssl => ssl_opts},
+class ExampleSSL2C
+ # Initialize.
+ def initialize
+ end
+ # Run example.
+ def run
+ ciphers_list = [["DHE-RSA-AES256-SHA", "TLSv1/SSLv3", 256, 256], ["DHE-DSS-AES256-SHA", "TLSv1/SSLv3", 256, 256], ["AES256-SHA", "TLSv1/SSLv3", 256, 256], ["EDH-RSA-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["EDH-DSS-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["DHE-RSA-AES128-SHA", "TLSv1/SSLv3", 128, 128], ["DHE-DSS-AES128-SHA", "TLSv1/SSLv3", 128, 128], ["AES128-SHA", "TLSv1/SSLv3", 128, 128], ["RC4-SHA", "TLSv1/SSLv3", 128, 128], ["RC4-MD5", "TLSv1/SSLv3", 128, 128], ["EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56],
+ ["DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["EXP-EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-RC2-CBC-MD5", "TLSv1/SSLv3", 40, 128], ["EXP-RC4-MD5", "TLSv1/SSLv3", 40, 128]]
+ #
+ # SSL Use Case 2
+ #
+ ts_flist = []
+ ts_flist << "/home/gmallard/sslwork/twocas_tj/serverCA/ServerTJCA.crt"
+ ssl_opts = Stomp::SSLParams.new(:ts_files => ts_flist.join(","), :ciphers => ciphers_list)
+ #
+ hash = { :hosts => [
+ {:login => 'guest', :passcode => 'guest', :host => 'localhost', :port => 61612, :ssl => ssl_opts},
]
}
-#
-puts "Connect starts, SSL Use Case 2"
-c = Stomp::Connection.new(hash)
-puts "Connect completed"
-puts "SSL Verify Result: #{ssl_opts.verify_result}"
-# puts "SSL Peer Certificate:\n#{ssl_opts.peer_cert}"
-c.disconnect
+ #
+ puts "Connect starts, SSL Use Case 2"
+ c = Stomp::Connection.new(hash)
+ puts "Connect completed"
+ puts "SSL Verify Result: #{ssl_opts.verify_result}"
+ # puts "SSL Peer Certificate:\n#{ssl_opts.peer_cert}"
+ c.disconnect
+ end
+end
+#
+e = ExampleSSL2C.new
+e.run
diff --git a/examples/ssl_uc3.rb b/examples/ssl_uc3.rb
index 9daa04d..504107d 100644
--- a/examples/ssl_uc3.rb
+++ b/examples/ssl_uc3.rb
@@ -6,7 +6,7 @@
require "rubygems"
require "stomp"
#
-# SSL Use Case 3 - server *does* authenticate client, client does *not* authenticate server
+# == SSL Use Case 3 - server *does* authenticate client, client does *not* authenticate server
#
# Subcase 3.A - Message broker configuration does *not* require client authentication
#
@@ -20,20 +20,31 @@ require "stomp"
# - Expect a verify result of 20 because the client did not authenticate the
# server's certificate.
#
-ssl_opts = Stomp::SSLParams.new(:key_file => "/home/gmallard/sslwork/twocas_tj/clientCA/ClientTJ.key",
- :cert_file => "/home/gmallard/sslwork/twocas_tj/clientCA/ClientTJ.crt")
+class ExampleSSL3
+ # Initialize.
+ def initialize
+ end
+ # Run example.
+ def run
+ ssl_opts = Stomp::SSLParams.new(:key_file => "/home/gmallard/sslwork/twocas_tj/clientCA/ClientTJ.key",
+ :cert_file => "/home/gmallard/sslwork/twocas_tj/clientCA/ClientTJ.crt")
-#
-hash = { :hosts => [
- {:login => 'guest', :passcode => 'guest', :host => 'localhost', :port => 61612, :ssl => ssl_opts},
+ #
+ hash = { :hosts => [
+ {:login => 'guest', :passcode => 'guest', :host => 'localhost', :port => 61612, :ssl => ssl_opts},
],
- :reliable => false, # YMMV, to test this in a sane manner
+ :reliable => false, # YMMV, to test this in a sane manner
}
-#
-puts "Connect starts, SSL Use Case 3"
-c = Stomp::Connection.new(hash)
-puts "Connect completed"
-puts "SSL Verify Result: #{ssl_opts.verify_result}"
-# puts "SSL Peer Certificate:\n#{ssl_opts.peer_cert}"
-c.disconnect
+ #
+ puts "Connect starts, SSL Use Case 3"
+ c = Stomp::Connection.new(hash)
+ puts "Connect completed"
+ puts "SSL Verify Result: #{ssl_opts.verify_result}"
+ # puts "SSL Peer Certificate:\n#{ssl_opts.peer_cert}"
+ c.disconnect
+ end
+end
+#
+e = ExampleSSL3.new
+e.run
diff --git a/examples/ssl_uc3_ciphers.rb b/examples/ssl_uc3_ciphers.rb
index 7a50bfd..62d5b2d 100644
--- a/examples/ssl_uc3_ciphers.rb
+++ b/examples/ssl_uc3_ciphers.rb
@@ -6,29 +6,42 @@
require "rubygems"
require "stomp"
#
+# == SSL Use Case 3 - User Supplied Ciphers
+#
# If you need your own ciphers list, this is how.
# Stomp's default list will work in many cases. If you need to use this, you
# will know it because SSL connect will fail. In that case, determining
# _what_ should be in the list is your responsibility.
#
-ciphers_list = [["DHE-RSA-AES256-SHA", "TLSv1/SSLv3", 256, 256], ["DHE-DSS-AES256-SHA", "TLSv1/SSLv3", 256, 256], ["AES256-SHA", "TLSv1/SSLv3", 256, 256], ["EDH-RSA-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["EDH-DSS-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["DHE-RSA-AES128-SHA", "TLSv1/SSLv3", 128, 128], ["DHE-DSS-AES128-SHA", "TLSv1/SSLv3", 128, 128], ["AES128-SHA", "TLSv1/SSLv3", 128, 128], ["RC4-SHA", "TLSv1/SSLv3", 128, 128], ["RC4-MD5", "TLSv1/SSLv3", 128, 128], ["EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56],
-["DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["EXP-EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-RC2-CBC-MD5", "TLSv1/SSLv3", 40, 128], ["EXP-RC4-MD5", "TLSv1/SSLv3", 40, 128]]
-#
-# SSL Use Case 3
-#
-ts_flist = []
-ts_flist << "/home/gmallard/sslwork/twocas_tj/serverCA/ServerTJCA.crt"
-ssl_opts = Stomp::SSLParams.new(:ts_files => ts_flist.join(","), :ciphers => ciphers_list)
-#
-hash = { :hosts => [
- {:login => 'guest', :passcode => 'guest', :host => 'localhost', :port => 61612, :ssl => ssl_opts},
+class ExampleSSL3C
+ # Initialize.
+ def initialize
+ end
+ # Run example.
+ def run
+ ciphers_list = [["DHE-RSA-AES256-SHA", "TLSv1/SSLv3", 256, 256], ["DHE-DSS-AES256-SHA", "TLSv1/SSLv3", 256, 256], ["AES256-SHA", "TLSv1/SSLv3", 256, 256], ["EDH-RSA-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["EDH-DSS-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["DHE-RSA-AES128-SHA", "TLSv1/SSLv3", 128, 128], ["DHE-DSS-AES128-SHA", "TLSv1/SSLv3", 128, 128], ["AES128-SHA", "TLSv1/SSLv3", 128, 128], ["RC4-SHA", "TLSv1/SSLv3", 128, 128], ["RC4-MD5", "TLSv1/SSLv3", 128, 128], ["EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56],
+ ["DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["EXP-EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-RC2-CBC-MD5", "TLSv1/SSLv3", 40, 128], ["EXP-RC4-MD5", "TLSv1/SSLv3", 40, 128]]
+ #
+ # SSL Use Case 3
+ #
+ ssl_opts = Stomp::SSLParams.new(:key_file => "/home/gmallard/sslwork/twocas_tj/clientCA/ClientTJ.key",
+ :cert_file => "/home/gmallard/sslwork/twocas_tj/clientCA/ClientTJ.crt", :ciphers => ciphers_list)
+
+ #
+ hash = { :hosts => [
+ {:login => 'guest', :passcode => 'guest', :host => 'localhost', :port => 61612, :ssl => ssl_opts},
]
}
-#
-puts "Connect starts, SSL Use Case 3"
-c = Stomp::Connection.new(hash)
-puts "Connect completed"
-puts "SSL Verify Result: #{ssl_opts.verify_result}"
-# puts "SSL Peer Certificate:\n#{ssl_opts.peer_cert}"
-c.disconnect
+ #
+ puts "Connect starts, SSL Use Case 3"
+ c = Stomp::Connection.new(hash)
+ puts "Connect completed"
+ puts "SSL Verify Result: #{ssl_opts.verify_result}"
+ # puts "SSL Peer Certificate:\n#{ssl_opts.peer_cert}"
+ c.disconnect
+ end
+end
+#
+e = ExampleSSL3C.new
+e.run
diff --git a/examples/ssl_uc4.rb b/examples/ssl_uc4.rb
index 8668766..c861617 100644
--- a/examples/ssl_uc4.rb
+++ b/examples/ssl_uc4.rb
@@ -6,7 +6,7 @@
require "rubygems"
require "stomp"
#
-# SSL Use Case 4 - server *does* authenticate client, client *does* authenticate server
+# == SSL Use Case 4 - server *does* authenticate client, client *does* authenticate server
#
# Subcase 4.A - Message broker configuration does *not* require client authentication
#
@@ -20,20 +20,31 @@ require "stomp"
# - Expect a verify result of 0 because the client did authenticate the
# server's certificate.
#
-ssl_opts = Stomp::SSLParams.new(:key_file => "/home/gmallard/sslwork/twocas_tj/clientCA/ClientTJ.key",
- :cert_file => "/home/gmallard/sslwork/twocas_tj/clientCA/ClientTJ.crt",
- :ts_files => "/home/gmallard/sslwork/twocas_tj/serverCA/ServerTJCA.crt")
-#
-hash = { :hosts => [
- {:login => 'guest', :passcode => 'guest', :host => 'localhost', :port => 61612, :ssl => ssl_opts},
+class ExampleSSL4
+ # Initialize.
+ def initialize
+ end
+ # Run example.
+ def run
+ ssl_opts = Stomp::SSLParams.new(:key_file => "/home/gmallard/sslwork/twocas_tj/clientCA/ClientTJ.key",
+ :cert_file => "/home/gmallard/sslwork/twocas_tj/clientCA/ClientTJ.crt",
+ :ts_files => "/home/gmallard/sslwork/twocas_tj/serverCA/ServerTJCA.crt")
+ #
+ hash = { :hosts => [
+ {:login => 'guest', :passcode => 'guest', :host => 'localhost', :port => 61612, :ssl => ssl_opts},
],
- :reliable => false, # YMMV, to test this in a sane manner
+ :reliable => false, # YMMV, to test this in a sane manner
}
-#
-puts "Connect starts, SSL Use Case 4"
-c = Stomp::Connection.new(hash)
-puts "Connect completed"
-puts "SSL Verify Result: #{ssl_opts.verify_result}"
-# puts "SSL Peer Certificate:\n#{ssl_opts.peer_cert}"
-c.disconnect
+ #
+ puts "Connect starts, SSL Use Case 4"
+ c = Stomp::Connection.new(hash)
+ puts "Connect completed"
+ puts "SSL Verify Result: #{ssl_opts.verify_result}"
+ # puts "SSL Peer Certificate:\n#{ssl_opts.peer_cert}"
+ c.disconnect
+ end
+end
+#
+e = ExampleSSL4.new
+e.run
diff --git a/examples/ssl_uc4_ciphers.rb b/examples/ssl_uc4_ciphers.rb
index f5112e2..9fd91be 100644
--- a/examples/ssl_uc4_ciphers.rb
+++ b/examples/ssl_uc4_ciphers.rb
@@ -6,30 +6,43 @@
require "rubygems"
require "stomp"
#
+# == SSL Use Case 4 - User Supplied Ciphers
+#
# If you need your own ciphers list, this is how.
# Stomp's default list will work in many cases. If you need to use this, you
# will know it because SSL connect will fail. In that case, determining
# _what_ should be in the list is your responsibility.
#
-ciphers_list = [["DHE-RSA-AES256-SHA", "TLSv1/SSLv3", 256, 256], ["DHE-DSS-AES256-SHA", "TLSv1/SSLv3", 256, 256], ["AES256-SHA", "TLSv1/SSLv3", 256, 256], ["EDH-RSA-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["EDH-DSS-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["DHE-RSA-AES128-SHA", "TLSv1/SSLv3", 128, 128], ["DHE-DSS-AES128-SHA", "TLSv1/SSLv3", 128, 128], ["AES128-SHA", "TLSv1/SSLv3", 128, 128], ["RC4-SHA", "TLSv1/SSLv3", 128, 128], ["RC4-MD5", "TLSv1/SSLv3", 128, 128], ["EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56],
-["DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["EXP-EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-RC2-CBC-MD5", "TLSv1/SSLv3", 40, 128], ["EXP-RC4-MD5", "TLSv1/SSLv3", 40, 128]]
-#
-# SSL Use Case 4
-#
-ssl_opts = Stomp::SSLParams.new(:key_file => "/home/gmallard/sslwork/twocas_tj/clientCA/ClientTJ.key",
- :cert_file => "/home/gmallard/sslwork/twocas_tj/clientCA/ClientTJ.crt",
- :ts_files => "/home/gmallard/sslwork/twocas_tj/serverCA/ServerTJCA.crt",
- :ciphers => ciphers_list)
-#
-hash = { :hosts => [
- {:login => 'guest', :passcode => 'guest', :host => 'localhost', :port => 61612, :ssl => ssl_opts},
+class ExampleSSL4C
+ # Initialize.
+ def initialize
+ end
+ # Run example.
+ def run
+ ciphers_list = [["DHE-RSA-AES256-SHA", "TLSv1/SSLv3", 256, 256], ["DHE-DSS-AES256-SHA", "TLSv1/SSLv3", 256, 256], ["AES256-SHA", "TLSv1/SSLv3", 256, 256], ["EDH-RSA-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["EDH-DSS-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["DHE-RSA-AES128-SHA", "TLSv1/SSLv3", 128, 128], ["DHE-DSS-AES128-SHA", "TLSv1/SSLv3", 128, 128], ["AES128-SHA", "TLSv1/SSLv3", 128, 128], ["RC4-SHA", "TLSv1/SSLv3", 128, 128], ["RC4-MD5", "TLSv1/SSLv3", 128, 128], ["EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56],
+ ["DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["EXP-EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-RC2-CBC-MD5", "TLSv1/SSLv3", 40, 128], ["EXP-RC4-MD5", "TLSv1/SSLv3", 40, 128]]
+ #
+ # SSL Use Case 4
+ #
+ ssl_opts = Stomp::SSLParams.new(:key_file => "/home/gmallard/sslwork/twocas_tj/clientCA/ClientTJ.key",
+ :cert_file => "/home/gmallard/sslwork/twocas_tj/clientCA/ClientTJ.crt",
+ :ts_files => "/home/gmallard/sslwork/twocas_tj/serverCA/ServerTJCA.crt",
+ :ciphers => ciphers_list)
+ #
+ hash = { :hosts => [
+ {:login => 'guest', :passcode => 'guest', :host => 'localhost', :port => 61612, :ssl => ssl_opts},
]
}
-#
-puts "Connect starts, SSL Use Case 4"
-c = Stomp::Connection.new(hash)
-puts "Connect completed"
-puts "SSL Verify Result: #{ssl_opts.verify_result}"
-# puts "SSL Peer Certificate:\n#{ssl_opts.peer_cert}"
-c.disconnect
+ #
+ puts "Connect starts, SSL Use Case 4"
+ c = Stomp::Connection.new(hash)
+ puts "Connect completed"
+ puts "SSL Verify Result: #{ssl_opts.verify_result}"
+ # puts "SSL Peer Certificate:\n#{ssl_opts.peer_cert}"
+ c.disconnect
+ end
+end
+#
+e = ExampleSSL4C.new
+e.run
diff --git a/examples/ssl_ucx_default_ciphers.rb b/examples/ssl_ucx_default_ciphers.rb
index ad2c8d5..439b47e 100644
--- a/examples/ssl_ucx_default_ciphers.rb
+++ b/examples/ssl_ucx_default_ciphers.rb
@@ -6,23 +6,36 @@
require "rubygems"
require "stomp"
#
+# == Example: Use Ruby Supplied Ciphers
+#
# If you use SSLParams, and need the _default_ Ruby ciphers, this is how.
#
# NOTE: JRuby users may find that this is a *required* action. YMMV.
#
-ssl_opts = Stomp::SSLParams.new(:use_ruby_ciphers => true) # Plus other parameters as needed
-#
-# SSL Use Case: Using default Stomp ciphers
-#
-hash = { :hosts => [
- {:login => 'guest', :passcode => 'guest', :host => 'localhost',
+class ExampleRubyCiphers
+ # Initialize.
+ def initialize
+ end
+ # Run example.
+ def run
+ ssl_opts = Stomp::SSLParams.new(:use_ruby_ciphers => true) # Plus other parameters as needed
+ #
+ # SSL Use Case: Using default Stomp ciphers
+ #
+ hash = { :hosts => [
+ {:login => 'guest', :passcode => 'guest', :host => 'localhost',
:port => 61612, :ssl => ssl_opts},
]
}
-#
-puts "Connect starts, SSL , Use Default Ruby Ciphers"
-c = Stomp::Connection.new(hash)
-puts "Connect completed"
-#
-c.disconnect
+ #
+ puts "Connect starts, SSL , Use Default Ruby Ciphers"
+ c = Stomp::Connection.new(hash)
+ puts "Connect completed"
+ #
+ c.disconnect
+ end
+end
+#
+e = ExampleRubyCiphers.new
+e.run
diff --git a/examples/stomp11_common.rb b/examples/stomp11_common.rb
index 3625802..4d5e001 100644
--- a/examples/stomp11_common.rb
+++ b/examples/stomp11_common.rb
@@ -7,39 +7,40 @@ require "rubygems" if RUBY_VERSION < "1.9"
require "stomp"
#
module Stomp11Common
- #
+ # User id
def login()
ENV['STOMP_USER'] || 'guest'
end
- #
+ # Password
def passcode()
ENV['STOMP_PASSCODE'] || 'guest'
end
- #
+ # Server host
def host()
ENV['STOMP_HOST'] || "localhost" # The connect host name
end
- #
+ # Server port
def port()
(ENV['STOMP_PORT'] || 62613).to_i # !! The author runs Apollo listening here
end
- #
+ # Required vhost name
def virt_host()
- ENV['STOMP_VHOST'] || "localhost" # The 1.1 virtual host name
+ ENV['STOMP_VHOST'] || "localhost" # The 1.1 virtual host name
end
- #
+ # Create a 1.1 commection
def get_connection()
conn_hdrs = {"accept-version" => "1.1", # 1.1 only
- "host" => virt_host, # the vhost
- }
- conn_hash = { :hosts => [
- {:login => login, :passcode => passcode, :host => host, :port => port},
- ],
- :connect_headers => conn_hdrs,
- }
+ "host" => virt_host, # the vhost
+ }
+ conn_hash = { :hosts => [
+ {:login => login, :passcode => passcode, :host => host, :port => port},
+ ],
+ :connect_headers => conn_hdrs,
+ }
conn = Stomp::Connection.new(conn_hash)
end
- #
+
+ # Number of messages
def nmsgs()
(ENV['STOMP_NMSGS'] || 1).to_i # Number of messages
end
diff --git a/examples/topic_consumer.rb b/examples/topic_consumer.rb
index d4b2952..ed8b18d 100644
--- a/examples/topic_consumer.rb
+++ b/examples/topic_consumer.rb
@@ -2,18 +2,31 @@
require 'rubygems'
require 'stomp'
+#
+# == Example topic consumer.
+#
+class ExampleTopicConsumer
+ # Initialize.
+ def initialize
+ end
+ # Run example.
+ def run
+ client = Stomp::Client.new("failover://(stomp://:@localhost:61613,stomp://:@remotehost:61613)?initialReconnectDelay=5000&randomize=false&useExponentialBackOff=false")
-client = Stomp::Client.new("failover://(stomp://:@localhost:61613,stomp://:@remotehost:61613)?initialReconnectDelay=5000&randomize=false&useExponentialBackOff=false")
+ puts "Subscribing to /topic/ronaldo"
-puts "Subscribing to /topic/ronaldo"
+ client.subscribe("/topic/ronaldo") do |msg|
+ puts msg.to_s
+ puts "----------------"
+ end
-client.subscribe("/topic/ronaldo") do |msg|
- puts msg.to_s
- puts "----------------"
-end
-
-loop do
- sleep(1)
- puts "."
+ loop do
+ sleep(1)
+ puts "."
+ end
+ end
end
+#
+e = ExampleTopicConsumer.new
+e.run
diff --git a/examples/topic_publisher.rb b/examples/topic_publisher.rb
index 6e97f64..8c72e42 100644
--- a/examples/topic_publisher.rb
+++ b/examples/topic_publisher.rb
@@ -3,13 +3,27 @@
require 'rubygems'
require 'stomp'
-client = Stomp::Client.new("failover://(stomp://:@localhost:61613,stomp://:@remotehost:61613)?initialReconnectDelay=5000&randomize=false&useExponentialBackOff=false")
-message = "ronaldo #{ARGV[0]}"
-
-for i in (1..300)
- puts "Sending message"
- client.publish("/topic/ronaldo", "#{i}: #{message}")
- puts "(#{Time.now})Message sent: #{i}"
- sleep 1
+#
+# == Example topic publisher.
+#
+class ExampleTopicPublisher
+ # Initialize.
+ def initialize
+ end
+ # Run example.
+ def run
+ client = Stomp::Client.new("failover://(stomp://:@localhost:61613,stomp://:@remotehost:61613)?initialReconnectDelay=5000&randomize=false&useExponentialBackOff=false")
+ message = "ronaldo #{ARGV[0]}"
+
+ for i in (1..50)
+ puts "Sending message"
+ client.publish("/topic/ronaldo", "#{i}: #{message}")
+ puts "(#{Time.now})Message sent: #{i}"
+ sleep 0.2
+ end
+ end
end
+#
+e = ExampleTopicPublisher.new
+e.run
diff --git a/lib/client/utils.rb b/lib/client/utils.rb
new file mode 100644
index 0000000..149beda
--- /dev/null
+++ b/lib/client/utils.rb
@@ -0,0 +1,116 @@
+# -*- encoding: utf-8 -*-
+
+require 'thread'
+require 'digest/sha1'
+
+module Stomp
+
+ class Client
+
+ private
+
+ # Set a subscription id in the headers hash if one does not already exist.
+ # For simplicities sake, all subscriptions have a subscription ID.
+ # setting an id in the SUBSCRIPTION header is described in the stomp protocol docs:
+ # http://stomp.github.com/
+ def set_subscription_id_if_missing(destination, headers)
+ headers[:id] = headers[:id] ? headers[:id] : headers['id']
+ if headers[:id] == nil
+ headers[:id] = Digest::SHA1.hexdigest(destination)
+ end
+ end
+
+ # Register a receipt listener.
+ def register_receipt_listener(listener)
+ id = -1
+ @id_mutex.synchronize do
+ id = @ids.to_s
+ @ids = @ids.succ
+ end
+ @receipt_listeners[id] = listener
+ id
+ end
+
+ # url_regex defines a regex for e.g. login:passcode at host:port or host:port
+ def url_regex
+ '(([\w\.\-]*):(\w*)@)?([\w\.\-]+):(\d+)'
+ end
+
+ # Parse a stomp URL.
+ def parse_hosts(url)
+ hosts = []
+
+ host_match = /stomp(\+ssl)?:\/\/(([\w\.]*):(\w*)@)?([\w\.]+):(\d+)\)/
+ url.scan(host_match).each do |match|
+ host = {}
+ host[:ssl] = !match[0].nil?
+ host[:login] = match[2] || ""
+ host[:passcode] = match[3] || ""
+ host[:host] = match[4]
+ host[:port] = match[5].to_i
+
+ hosts << host
+ end
+
+ hosts
+ end
+
+ # A very basic check of required arguments.
+ # *NOTE* This method will be made private in the next release.
+ def check_arguments!()
+ raise ArgumentError if @host.nil? || @host.empty?
+ raise ArgumentError if @port.nil? || @port == '' || @port < 1 || @port > 65535
+ raise ArgumentError unless @reliable.is_a?(TrueClass) || @reliable.is_a?(FalseClass)
+ end
+
+ # filter_options returns a new Hash of filtered options.
+ def filter_options(options)
+ new_options = {}
+ new_options[:initial_reconnect_delay] = (options["initialReconnectDelay"] || 10).to_f / 1000 # In ms
+ new_options[:max_reconnect_delay] = (options["maxReconnectDelay"] || 30000 ).to_f / 1000 # In ms
+ new_options[:use_exponential_back_off] = !(options["useExponentialBackOff"] == "false") # Default: true
+ new_options[:back_off_multiplier] = (options["backOffMultiplier"] || 2 ).to_i
+ new_options[:max_reconnect_attempts] = (options["maxReconnectAttempts"] || 0 ).to_i
+ new_options[:randomize] = options["randomize"] == "true" # Default: false
+ new_options[:backup] = false # Not implemented yet: I'm using a master X slave solution
+ new_options[:timeout] = -1 # Not implemented yet: a "timeout(5) do ... end" would do the trick, feel free
+
+ new_options
+ end
+
+ # find_listener returns the listener for a given subscription in a given message.
+ def find_listener(message)
+ subscription_id = message.headers['subscription']
+ if subscription_id == nil
+ # For backward compatibility, some messages may already exist with no
+ # subscription id, in which case we can attempt to synthesize one.
+ set_subscription_id_if_missing(message.headers['destination'], message.headers)
+ subscription_id = message.headers[:id]
+ end
+ @listeners[subscription_id]
+ end
+
+ # Start a single listener thread. Misnamed I think.
+ def start_listeners()
+ @listeners = {}
+ @receipt_listeners = {}
+ @replay_messages_by_txn = {}
+
+ @listener_thread = Thread.start do
+ while true
+ message = @connection.receive
+ if message.command == Stomp::CMD_MESSAGE
+ if listener = find_listener(message)
+ listener.call(message)
+ end
+ elsif message.command == Stomp::CMD_RECEIPT
+ if listener = @receipt_listeners[message.headers['receipt-id']]
+ listener.call(message)
+ end
+ end
+ end
+ end
+ end
+ end
+end
+
diff --git a/lib/connection/heartbeats.rb b/lib/connection/heartbeats.rb
new file mode 100644
index 0000000..de862c2
--- /dev/null
+++ b/lib/connection/heartbeats.rb
@@ -0,0 +1,173 @@
+# -*- encoding: utf-8 -*-
+
+require 'socket'
+require 'timeout'
+require 'io/wait'
+require 'digest/sha1'
+
+module Stomp
+
+ class Connection
+
+ private
+
+ def _validate_hbheader()
+ return if @connect_headers[:"heart-beat"] == "0,0" # Caller does not want heartbeats. OK.
+ parts = @connect_headers[:"heart-beat"].split(",")
+ if (parts.size != 2) || (parts[0] != parts[0].to_i.to_s) || (parts[1] != parts[1].to_i.to_s)
+ raise Stomp::Error::InvalidHeartBeatHeaderError
+ end
+ end
+
+ def _init_heartbeats()
+ return if @connect_headers[:"heart-beat"] == "0,0" # Caller does not want heartbeats. OK.
+
+ # Init.
+
+ #
+ @cx = @cy = @sx = @sy = 0, # Variable names as in spec
+
+ #
+ @hbsend_interval = @hbrecv_interval = 0.0 # Send/Receive ticker interval.
+
+ #
+ @hbsend_count = @hbrecv_count = 0 # Send/Receive ticker counts.
+
+ #
+ @ls = @lr = -1.0 # Last send/receive time (from Time.now.to_f)
+
+ #
+ @st = @rt = nil # Send/receive ticker thread
+
+ # Handle current client / server capabilities.
+
+ #
+ cfh = @connection_frame.headers.symbolize_keys
+ return if cfh[:"heart-beat"] == "0,0" # Server does not want heartbeats
+
+ # Conect header parts.
+ parts = @connect_headers[:"heart-beat"].split(",")
+ @cx = parts[0].to_i
+ @cy = parts[1].to_i
+
+ # Connected frame header parts.
+ parts = cfh[:"heart-beat"].split(",")
+ @sx = parts[0].to_i
+ @sy = parts[1].to_i
+
+ # Catch odd situations like server has used => heart-beat:000,00000
+ return if (@cx == 0 && @cy == 0) || (@sx == 0 && @sy == 0)
+
+ # See if we are doing anything at all.
+
+ #
+ @hbs = @hbr = true # Sending/Receiving heartbeats. Assume yes at first.
+ # Check if sending is possible.
+ @hbs = false if @cx == 0 || @sy == 0
+ # Check if receiving is possible.
+ @hbr = false if @sx == 0 || @cy == 0
+ # Should not do heartbeats at all
+ return if (!@hbs && !@hbr)
+
+ # If sending
+ if @hbs
+ sm = @cx >= @sy ? @cx : @sy # ticker interval, ms
+ @hbsend_interval = 1000.0 * sm # ticker interval, μs
+ @ls = Time.now.to_f # best guess at start
+ _start_send_ticker()
+ end
+
+ # If receiving
+ if @hbr
+ rm = @sx >= @cy ? @sx : @cy # ticker interval, ms
+ @hbrecv_interval = 1000.0 * rm # ticker interval, μs
+ @lr = Time.now.to_f # best guess at start
+ _start_receive_ticker()
+ end
+
+ end
+
+ # _start_send_ticker starts a thread to send heartbeats when required.
+ def _start_send_ticker()
+ sleeptime = @hbsend_interval / 1000000.0 # Sleep time secs
+ @st = Thread.new {
+ while true do
+ sleep sleeptime
+ curt = Time.now.to_f
+ if @logger && @logger.respond_to?(:on_hbfire)
+ @logger.on_hbfire(log_params, "send_fire", curt)
+ end
+ delta = curt - @ls
+ if delta > (@hbsend_interval - (@hbsend_interval/5.0)) / 1000000.0 # Be tolerant (minus)
+ if @logger && @logger.respond_to?(:on_hbfire)
+ @logger.on_hbfire(log_params, "send_heartbeat", curt)
+ end
+ # Send a heartbeat
+ @transmit_semaphore.synchronize do
+ begin
+ @socket.puts
+ @ls = curt # Update last send
+ @hb_sent = true # Reset if necessary
+ @hbsend_count += 1
+ rescue Exception => sendex
+ @hb_sent = false # Set the warning flag
+ if @logger && @logger.respond_to?(:on_hbwrite_fail)
+ @logger.on_hbwrite_fail(log_params, {"ticker_interval" => @hbsend_interval,
+ "exception" => sendex})
+ end
+ raise # Re-raise. What else could be done here?
+ end
+ end
+ end
+ Thread.pass
+ end
+ }
+ end
+
+ # _start_receive_ticker starts a thread that receives heartbeats when required.
+ def _start_receive_ticker()
+ sleeptime = @hbrecv_interval / 1000000.0 # Sleep time secs
+ @rt = Thread.new {
+ while true do
+ sleep sleeptime
+ curt = Time.now.to_f
+ if @logger && @logger.respond_to?(:on_hbfire)
+ @logger.on_hbfire(log_params, "receive_fire", curt)
+ end
+ delta = curt - @lr
+ if delta > ((@hbrecv_interval + (@hbrecv_interval/5.0)) / 1000000.0) # Be tolerant (plus)
+ if @logger && @logger.respond_to?(:on_hbfire)
+ @logger.on_hbfire(log_params, "receive_heartbeat", curt)
+ end
+ # Client code could be off doing something else (that is, no reading of
+ # the socket has been requested by the caller). Try to handle that case.
+ lock = @read_semaphore.try_lock
+ if lock
+ last_char = @socket.getc
+ plc = parse_char(last_char)
+ if plc == "\n" # Server Heartbeat
+ @lr = Time.now.to_f
+ else
+ @socket.ungetc(last_char)
+ end
+ @read_semaphore.unlock
+ @hbrecv_count += 1
+ else
+ # Shrug. Have not received one. Just set warning flag.
+ @hb_received = false
+ if @logger && @logger.respond_to?(:on_hbread_fail)
+ @logger.on_hbread_fail(log_params, {"ticker_interval" => @hbrecv_interval})
+ end
+ end
+ else
+ @hb_received = true # Reset if necessary
+ end
+ Thread.pass
+ end
+ }
+ end
+
+ end # class
+
+end # module
+
diff --git a/lib/connection/netio.rb b/lib/connection/netio.rb
new file mode 100644
index 0000000..20761a5
--- /dev/null
+++ b/lib/connection/netio.rb
@@ -0,0 +1,322 @@
+# -*- encoding: utf-8 -*-
+
+require 'socket'
+require 'timeout'
+require 'io/wait'
+require 'digest/sha1'
+
+module Stomp
+
+ class Connection
+
+ private
+
+ # Really read from the wire.
+ def _receive(read_socket)
+ @read_semaphore.synchronize do
+ line = ''
+ if @protocol == Stomp::SPL_10 || (@protocol >= Stomp::SPL_11 && !@hbr)
+ line = read_socket.gets # The old way
+ else # We are >= 1.1 *AND* receiving heartbeats.
+ while true
+ line = read_socket.gets # Data from wire
+ break unless line == "\n"
+ line = ''
+ @lr = Time.now.to_f
+ end
+ end
+ return nil if line.nil?
+ # If the reading hangs for more than X seconds, abort the parsing process.
+ # X defaults to 5. Override allowed in connection hash parameters.
+ Timeout::timeout(@parse_timeout, Stomp::Error::PacketParsingTimeout) do
+ # Reads the beginning of the message until it runs into a empty line
+ message_header = ''
+ begin
+ message_header += line
+ line = read_socket.gets
+ raise Stomp::Error::StompServerError if line.nil?
+ end until line =~ /^\s?\n$/
+
+ # Checks if it includes content_length header
+ content_length = message_header.match /content-length\s?:\s?(\d+)\s?\n/
+ message_body = ''
+
+ # If content_length is present, read the specified amount of bytes
+ if content_length
+ message_body = read_socket.read content_length[1].to_i
+ raise Stomp::Error::InvalidMessageLength unless parse_char(read_socket.getc) == "\0"
+ # Else read the rest of the message until the first \0
+ else
+ message_body = read_socket.readline("\0")
+ message_body.chop!
+ end
+
+ # If the buffer isn't empty, reads trailing new lines.
+ #
+ # Note: experiments with JRuby seem to show that .ready? never
+ # returns true. This means that this code to drain trailing new
+ # lines never runs using JRuby.
+ #
+ # Note 2: the draining of new lines must be done _after_ a message
+ # is read. Do _not_ leave them on the wire and attempt to drain them
+ # at the start of the next read. Attempting to do that breaks the
+ # asynchronous nature of the 'poll' method.
+ while read_socket.ready?
+ last_char = read_socket.getc
+ break unless last_char
+ if parse_char(last_char) != "\n"
+ read_socket.ungetc(last_char)
+ break
+ end
+ end
+ # And so, a JRuby hack. Remove any new lines at the start of the
+ # next buffer.
+ message_header.gsub!(/^\n?/, "")
+
+ if @protocol >= Stomp::SPL_11
+ @lr = Time.now.to_f if @hbr
+ end
+ # Adds the excluded \n and \0 and tries to create a new message with it
+ msg = Message.new(message_header + "\n" + message_body + "\0", @protocol >= Stomp::SPL_11)
+ #
+ if @protocol >= Stomp::SPL_11 && msg.command != Stomp::CMD_CONNECTED
+ msg.headers = _decodeHeaders(msg.headers)
+ end
+ msg
+ end
+ end
+ end
+
+ # transmit logically puts a Message on the wire.
+ def transmit(command, headers = {}, body = '')
+ # The transmit may fail so we may need to retry.
+ while TRUE
+ begin
+ used_socket = socket
+ _transmit(used_socket, command, headers, body)
+ return
+ rescue Stomp::Error::MaxReconnectAttempts => e
+ raise
+ rescue
+ @failure = $!
+ raise unless @reliable
+ errstr = "transmit to #{@host} failed: #{$!}\n"
+ if @logger && @logger.respond_to?(:on_miscerr)
+ @logger.on_miscerr(log_params, errstr)
+ else
+ $stderr.print errstr
+ end
+ end
+ end
+ end
+
+ # _transmit is the real wire write logic.
+ def _transmit(used_socket, command, headers = {}, body = '')
+ if @protocol >= Stomp::SPL_11 && command != Stomp::CMD_CONNECT
+ headers = _encodeHeaders(headers)
+ end
+ @transmit_semaphore.synchronize do
+ # Handle nil body
+ body = '' if body.nil?
+ # The content-length should be expressed in bytes.
+ # Ruby 1.8: String#length => # of bytes; Ruby 1.9: String#length => # of characters
+ # With Unicode strings, # of bytes != # of characters. So, use String#bytesize when available.
+ body_length_bytes = body.respond_to?(:bytesize) ? body.bytesize : body.length
+
+ # ActiveMQ interprets every message as a BinaryMessage
+ # if content_length header is included.
+ # Using :suppress_content_length => true will suppress this behaviour
+ # and ActiveMQ will interpret the message as a TextMessage.
+ # For more information refer to http://juretta.com/log/2009/05/24/activemq-jms-stomp/
+ # Lets send this header in the message, so it can maintain state when using unreceive
+ headers[:'content-length'] = "#{body_length_bytes}" unless headers[:suppress_content_length]
+ headers[:'content-type'] = "text/plain; charset=UTF-8" unless headers[:'content-type']
+ used_socket.puts command
+ headers.each do |k,v|
+ if v.is_a?(Array)
+ v.each do |e|
+ used_socket.puts "#{k}:#{e}"
+ end
+ else
+ used_socket.puts "#{k}:#{v}"
+ end
+ end
+ used_socket.puts
+ used_socket.write body
+ used_socket.write "\0"
+ used_socket.flush if autoflush
+
+ if @protocol >= Stomp::SPL_11
+ @ls = Time.now.to_f if @hbs
+ end
+
+ end
+ end
+
+ # open_tcp_socket opens a TCP socket.
+ def open_tcp_socket()
+ tcp_socket = nil
+
+ if @logger && @logger.respond_to?(:on_connecting)
+ @logger.on_connecting(log_params)
+ end
+
+ Timeout::timeout(@connect_timeout, Stomp::Error::SocketOpenTimeout) do
+ tcp_socket = TCPSocket.open(@host, @port)
+ end
+
+ tcp_socket
+ end
+
+ # open_ssl_socket opens an SSL socket.
+ def open_ssl_socket()
+ require 'openssl' unless defined?(OpenSSL)
+ begin # Any raised SSL exceptions
+ ctx = OpenSSL::SSL::SSLContext.new
+ ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE # Assume for now
+ #
+ # Note: if a client uses :ssl => true this results in the gem using
+ # the _default_ Ruby ciphers list. This is _known_ to fail in later
+ # Ruby releases. The gem provides a default cipher list that may
+ # function in these cases. To use this connect with:
+ # * :ssl => Stomp::SSLParams.new
+ # * :ssl => Stomp::SSLParams.new(..., :ciphers => Stomp::DEFAULT_CIPHERS)
+ #
+ # If connecting with an SSLParams instance, and the _default_ Ruby
+ # ciphers list is required, use:
+ # * :ssl => Stomp::SSLParams.new(..., :use_ruby_ciphers => true)
+ #
+ # If a custom ciphers list is required, connect with:
+ # * :ssl => Stomp::SSLParams.new(..., :ciphers => custom_ciphers_list)
+ #
+ if @ssl != true
+ #
+ # Here @ssl is:
+ # * an instance of Stomp::SSLParams
+ # Control would not be here if @ssl == false or @ssl.nil?.
+ #
+
+ # Back reference the SSLContext
+ @ssl.ctx = ctx
+
+ # Server authentication parameters if required
+ if @ssl.ts_files
+ ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER
+ truststores = OpenSSL::X509::Store.new
+ fl = @ssl.ts_files.split(",")
+ fl.each do |fn|
+ # Add next cert file listed
+ raise Stomp::Error::SSLNoTruststoreFileError if !File::exists?(fn)
+ raise Stomp::Error::SSLUnreadableTruststoreFileError if !File::readable?(fn)
+ truststores.add_file(fn)
+ end
+ ctx.cert_store = truststores
+ end
+
+ # Client authentication parameters.
+ # Both cert file and key file must be present or not, it can not be a mix.
+ raise Stomp::Error::SSLClientParamsError if @ssl.cert_file.nil? && !@ssl.key_file.nil?
+ raise Stomp::Error::SSLClientParamsError if !@ssl.cert_file.nil? && @ssl.key_file.nil?
+ if @ssl.cert_file # Any check will do here
+ raise Stomp::Error::SSLNoCertFileError if !File::exists?(@ssl.cert_file)
+ raise Stomp::Error::SSLUnreadableCertFileError if !File::readable?(@ssl.cert_file)
+ ctx.cert = OpenSSL::X509::Certificate.new(File.read(@ssl.cert_file))
+ raise Stomp::Error::SSLNoKeyFileError if !File::exists?(@ssl.key_file)
+ raise Stomp::Error::SSLUnreadableKeyFileError if !File::readable?(@ssl.key_file)
+ ctx.key = OpenSSL::PKey::RSA.new(File.read(@ssl.key_file), @ssl.key_password)
+ end
+
+ # Cipher list
+ if !@ssl.use_ruby_ciphers # No Ruby ciphers (the default)
+ if @ssl.ciphers # User ciphers list?
+ ctx.ciphers = @ssl.ciphers # Accept user supplied ciphers
+ else
+ ctx.ciphers = Stomp::DEFAULT_CIPHERS # Just use Stomp defaults
+ end
+ end
+ end
+
+ #
+ ssl = nil
+ if @logger && @logger.respond_to?(:on_ssl_connecting)
+ @logger.on_ssl_connecting(log_params)
+ end
+
+ Timeout::timeout(@connect_timeout, Stomp::Error::SocketOpenTimeout) do
+ ssl = OpenSSL::SSL::SSLSocket.new(open_tcp_socket, ctx)
+ end
+ def ssl.ready?
+ ! @rbuffer.empty? || @io.ready?
+ end
+ ssl.connect
+ if @ssl != true
+ # Pass back results if possible
+ if RUBY_VERSION =~ /1\.8\.[56]/
+ @ssl.verify_result = "N/A for Ruby #{RUBY_VERSION}"
+ else
+ @ssl.verify_result = ssl.verify_result
+ end
+ @ssl.peer_cert = ssl.peer_cert
+ end
+ if @logger && @logger.respond_to?(:on_ssl_connected)
+ @logger.on_ssl_connected(log_params)
+ end
+ ssl
+ rescue Exception => ex
+ if @logger && @logger.respond_to?(:on_ssl_connectfail)
+ lp = log_params.clone
+ lp[:ssl_exception] = ex
+ @logger.on_ssl_connectfail(lp)
+ end
+ #
+ raise # Reraise
+ end
+ end
+
+ # close_socket closes the current open socket, and hence the connection.
+ def close_socket()
+ begin
+ # Need to set @closed = true before closing the socket
+ # within the @read_semaphore thread
+ @closed = true
+ @read_semaphore.synchronize do
+ @socket.close
+ end
+ rescue
+ #Ignoring if already closed
+ end
+ @closed
+ end
+
+ # open_socket opens a TCP or SSL soclet as required.
+ def open_socket()
+ used_socket = @ssl ? open_ssl_socket : open_tcp_socket
+ # try to close the old connection if any
+ close_socket
+
+ @closed = false
+ # Use keepalive
+ used_socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, true)
+ used_socket
+ end
+
+ # connect performs a basic STOMP CONNECT operation.
+ def connect(used_socket)
+ @connect_headers = {} unless @connect_headers # Caller said nil/false
+ headers = @connect_headers.clone
+ headers[:login] = @login
+ headers[:passcode] = @passcode
+ _pre_connect
+ _transmit(used_socket, "CONNECT", headers)
+ @connection_frame = _receive(used_socket)
+ _post_connect
+ @disconnect_receipt = nil
+ @session = @connection_frame.headers["session"] if @connection_frame
+ # replay any subscriptions.
+ @subscriptions.each { |k,v| _transmit(used_socket, Stomp::CMD_SUBSCRIBE, v) }
+ end
+
+ end # class
+
+end # module
+
diff --git a/lib/connection/utf8.rb b/lib/connection/utf8.rb
new file mode 100644
index 0000000..d304147
--- /dev/null
+++ b/lib/connection/utf8.rb
@@ -0,0 +1,294 @@
+# -*- encoding: utf-8 -*-
+
+require 'socket'
+require 'timeout'
+require 'io/wait'
+require 'digest/sha1'
+
+module Stomp
+
+ class Connection
+
+ private
+
+ # Ref:
+ # http://unicode.org/mail-arch/unicode-ml/y2003-m02/att-0467/01-The_Algorithm_to_Valide_an_UTF-8_String
+ #
+ # *CONSIDER* replacing this with a dependency on the utf8_validator gem.
+ # This code has been copied from there.
+ #
+ def _valid_utf8?(string)
+ case RUBY_VERSION
+ when /1\.8\.[56]/
+ bytes = []
+ 0.upto(string.length-1) {|i|
+ bytes << string[i]
+ }
+ else
+ bytes = string.bytes
+ end
+
+ #
+ valid = true
+ index = -1
+ nb_hex = nil
+ ni_hex = nil
+ state = "start"
+ next_byte_save = nil
+ #
+ bytes.each do |next_byte|
+ index += 1
+ next_byte_save = next_byte
+ ni_hex = sprintf "%x", index
+ nb_hex = sprintf "%x", next_byte
+ # puts "Top: #{next_byte}(0x#{nb_hex}), index: #{index}(0x#{ni_hex})" if DEBUG
+ case state
+
+ # State: 'start'
+ # The 'start' state:
+ # * handles all occurrences of valid single byte characters i.e., the ASCII character set
+ # * provides state transition logic for start bytes of valid characters with 2-4 bytes
+ # * signals a validation failure for all other single bytes
+ #
+ when "start"
+ # puts "state: start" if DEBUG
+ case next_byte
+
+ # ASCII
+ # * Input = 0x00-0x7F : change state to START
+ when (0x00..0x7f)
+ # puts "state: start 1" if DEBUG
+ state = "start"
+
+ # Start byte of two byte characters
+ # * Input = 0xC2-0xDF: change state to A
+ when (0xc2..0xdf)
+ # puts "state: start 2" if DEBUG
+ state = "a"
+
+ # Start byte of some three byte characters
+ # * Input = 0xE1-0xEC, 0xEE-0xEF: change state to B
+ when (0xe1..0xec)
+ # puts "state: start 3" if DEBUG
+ state = "b"
+ when (0xee..0xef)
+ # puts "state: start 4" if DEBUG
+ state = "b"
+
+ # Start byte of special three byte characters
+ # * Input = 0xE0: change state to C
+ when 0xe0
+ # puts "state: start 5" if DEBUG
+ state = "c"
+
+ # Start byte of the remaining three byte characters
+ # * Input = 0xED: change state to D
+ when 0xed
+ # puts "state: start 6" if DEBUG
+ state = "d"
+
+ # Start byte of some four byte characters
+ # * Input = 0xF1-0xF3:change state to E
+ when (0xf1..0xf3)
+ # puts "state: start 7" if DEBUG
+ state = "e"
+
+ # Start byte of special four byte characters
+ # * Input = 0xF0: change state to F
+ when 0xf0
+ # puts "state: start 8" if DEBUG
+ state = "f"
+
+ # Start byte of very special four byte characters
+ # * Input = 0xF4: change state to G
+ when 0xf4
+ # puts "state: start 9" if DEBUG
+ state = "g"
+
+ # All other single characters are invalid
+ # * Input = Others (0x80-0xBF,0xC0-0xC1, 0xF5-0xFF): ERROR
+ else
+ valid = false
+ break
+ end # of the inner case, the 'start' state
+
+ # The last continuation byte of a 2, 3, or 4 byte character
+ # State: 'a'
+ # o Input = 0x80-0xBF: change state to START
+ # o Others: ERROR
+ when "a"
+ # puts "state: a" if DEBUG
+ if (0x80..0xbf) === next_byte
+ state = "start"
+ else
+ valid = false
+ break
+ end
+
+ # The first continuation byte for most 3 byte characters
+ # (those with start bytes in: 0xe1-0xec or 0xee-0xef)
+ # State: 'b'
+ # o Input = 0x80-0xBF: change state to A
+ # o Others: ERROR
+ when "b"
+ # puts "state: b" if DEBUG
+ if (0x80..0xbf) === next_byte
+ state = "a"
+ else
+ valid = false
+ break
+ end
+
+ # The first continuation byte for some special 3 byte characters
+ # (those with start byte 0xe0)
+ # State: 'c'
+ # o Input = 0xA0-0xBF: change state to A
+ # o Others: ERROR
+ when "c"
+ # puts "state: c" if DEBUG
+ if (0xa0..0xbf) === next_byte
+ state = "a"
+ else
+ valid = false
+ break
+ end
+
+ # The first continuation byte for the remaining 3 byte characters
+ # (those with start byte 0xed)
+ # State: 'd'
+ # o Input = 0x80-0x9F: change state to A
+ # o Others: ERROR
+ when "d"
+ # puts "state: d" if DEBUG
+ if (0x80..0x9f) === next_byte
+ state = "a"
+ else
+ valid = false
+ break
+ end
+
+ # The first continuation byte for some 4 byte characters
+ # (those with start bytes in: 0xf1-0xf3)
+ # State: 'e'
+ # o Input = 0x80-0xBF: change state to B
+ # o Others: ERROR
+ when "e"
+ # puts "state: e" if DEBUG
+ if (0x80..0xbf) === next_byte
+ state = "b"
+ else
+ valid = false
+ break
+ end
+
+ # The first continuation byte for some special 4 byte characters
+ # (those with start byte 0xf0)
+ # State: 'f'
+ # o Input = 0x90-0xBF: change state to B
+ # o Others: ERROR
+ when "f"
+ # puts "state: f" if DEBUG
+ if (0x90..0xbf) === next_byte
+ state = "b"
+ else
+ valid = false
+ break
+ end
+
+ # The first continuation byte for the remaining 4 byte characters
+ # (those with start byte 0xf4)
+ # State: 'g'
+ # o Input = 0x80-0x8F: change state to B
+ # o Others: ERROR
+ when "g"
+ # puts "state: g" if DEBUG
+ if (0x80..0x8f) === next_byte
+ state = "b"
+ else
+ valid = false
+ break
+ end
+
+ #
+ else
+ raise RuntimeError, "state: default"
+ end
+ end
+ #
+ # puts "State at end: #{state}" if DEBUG
+ # Catch truncation at end of string
+ if valid and state != 'start'
+ # puts "Resetting valid value" if DEBUG
+ valid = false
+ end
+ #
+ valid
+ end # of _valid_utf8?
+
+ # Stomp 1.1+ header check for UTF8 validity. Raises Stomp::Error::UTF8ValidationError if header data is not valid UTF8.
+ def _headerCheck(h)
+ return if @protocol == Stomp::SPL_10 # Do nothing for this environment
+ #
+ h.each_pair do |k,v|
+ # Keys here are symbolized
+ ks = k.to_s
+ ks.force_encoding(Stomp::UTF8) if ks.respond_to?(:force_encoding)
+ raise Stomp::Error::UTF8ValidationError unless valid_utf8?(ks)
+ #
+ if v.is_a?(Array)
+ v.each do |e|
+ e.force_encoding(Stomp::UTF8) if e.respond_to?(:force_encoding)
+ raise Stomp::Error::UTF8ValidationError unless valid_utf8?(e)
+ end
+ else
+ vs = v.to_s + "" # Values are usually Strings, but could be TrueClass or Symbol
+ # The + "" above forces an 'unfreeze' if necessary
+ vs.force_encoding(Stomp::UTF8) if vs.respond_to?(:force_encoding)
+ raise Stomp::Error::UTF8ValidationError unless valid_utf8?(vs)
+ end
+ end
+ end
+
+ # encode returns a Hash of encoded headers per the Stomp 1.1 specification.
+ def _encodeHeaders(h)
+ eh = {}
+ h.each_pair do |k,v|
+ # Keys are symbolized
+ ks = k.to_s
+ if v.is_a?(Array)
+ kenc = Stomp::HeaderCodec::encode(ks)
+ eh[kenc] = []
+ v.each do |e|
+ eh[kenc] << Stomp::HeaderCodec::encode(e)
+ end
+ else
+ vs = v.to_s
+ eh[Stomp::HeaderCodec::encode(ks)] = Stomp::HeaderCodec::encode(vs)
+ end
+ end
+ eh
+ end
+
+ # decode returns a Hash of decoded headers per the Stomp 1.1 specification.
+ def _decodeHeaders(h)
+ dh = {}
+ h.each_pair do |k,v|
+ # Keys here are NOT! symbolized
+ if v.is_a?(Array)
+ kdec = Stomp::HeaderCodec::decode(k)
+ dh[kdec] = []
+ v.each do |e|
+ dh[kdec] << Stomp::HeaderCodec::decode(e)
+ end
+ else
+ vs = v.to_s
+ dh[Stomp::HeaderCodec::decode(k)] = Stomp::HeaderCodec::decode(vs)
+ end
+ end
+ dh
+ end
+
+ end # class
+
+end # module
+
diff --git a/lib/connection/utils.rb b/lib/connection/utils.rb
new file mode 100644
index 0000000..8bc211c
--- /dev/null
+++ b/lib/connection/utils.rb
@@ -0,0 +1,104 @@
+# -*- encoding: utf-8 -*-
+
+require 'socket'
+require 'timeout'
+require 'io/wait'
+require 'digest/sha1'
+
+module Stomp
+
+ class Connection
+
+ private
+
+ # Support multi-homed servers.
+ def _expand_hosts(hash)
+ new_hash = hash.clone
+ new_hash[:hosts_cloned] = hash[:hosts].clone
+ new_hash[:hosts] = []
+ #
+ hash[:hosts].each do |host_parms|
+ ai = Socket.getaddrinfo(host_parms[:host], nil, nil, Socket::SOCK_STREAM)
+ next if ai.nil? || ai.size == 0
+ info6 = ai.detect {|info| info[4] == Socket::AF_INET6}
+ info4 = ai.detect {|info| info[4] == Socket::AF_INET}
+ if info6
+ new_hostp = host_parms.clone
+ new_hostp[:host] = info6[3]
+ new_hash[:hosts] << new_hostp
+ end
+ if info4
+ new_hostp = host_parms.clone
+ new_hostp[:host] = info4[3]
+ new_hash[:hosts] << new_hostp
+ end
+ end
+ return new_hash
+ end
+
+ # Handle 1.9+ character representation.
+ def parse_char(char)
+ RUBY_VERSION > '1.9' ? char : char.chr
+ end
+
+ # Create parameters for any callback logger.
+ def log_params()
+ lparms = @parameters.clone if @parameters
+ lparms = {} unless lparms
+ lparms[:cur_host] = @host
+ lparms[:cur_port] = @port
+ lparms[:cur_login] = @login
+ lparms[:cur_passcode] = @passcode
+ lparms[:cur_ssl] = @ssl
+ lparms[:cur_recondelay] = @reconnect_delay
+ lparms[:cur_parseto] = @parse_timeout
+ lparms[:cur_conattempts] = @connection_attempts
+ lparms[:openstat] = open?
+ #
+ lparms
+ end
+
+ # _pre_connect handles low level logic just prior to a physical connect.
+ def _pre_connect()
+ @connect_headers = @connect_headers.symbolize_keys
+ raise Stomp::Error::ProtocolErrorConnect if (@connect_headers[:"accept-version"] && !@connect_headers[:host])
+ raise Stomp::Error::ProtocolErrorConnect if (!@connect_headers[:"accept-version"] && @connect_headers[:host])
+ return unless (@connect_headers[:"accept-version"] && @connect_headers[:host]) # 1.0
+ # Try 1.1 or greater
+ okvers = []
+ avers = @connect_headers[:"accept-version"].split(",")
+ avers.each do |nver|
+ if Stomp::SUPPORTED.index(nver)
+ okvers << nver
+ end
+ end
+ raise Stomp::Error::UnsupportedProtocolError if okvers == []
+ @connect_headers[:"accept-version"] = okvers.join(",") # This goes to server
+ # Heartbeats - pre connect
+ return unless @connect_headers[:"heart-beat"]
+ _validate_hbheader()
+ end
+
+ # _post_connect handles low level logic just post a physical connect.
+ def _post_connect()
+ return unless (@connect_headers[:"accept-version"] && @connect_headers[:host])
+ return if @connection_frame.command == Stomp::CMD_ERROR
+ # We are CONNECTed
+ cfh = @connection_frame.headers.symbolize_keys
+ @protocol = cfh[:version]
+ if @protocol
+ # Should not happen, but check anyway
+ raise Stomp::Error::UnsupportedProtocolError unless Stomp::SUPPORTED.index(@protocol)
+ else # CONNECTed to a 1.0 server that does not return *any* 1.1 type headers
+ @protocol = Stomp::SPL_10 # reset
+ return
+ end
+ # Heartbeats
+ return unless @connect_headers[:"heart-beat"]
+ _init_heartbeats()
+ end
+
+ end # class
+
+end # module
+
diff --git a/lib/stomp.rb b/lib/stomp.rb
index 29bc0e1..9856372 100644
--- a/lib/stomp.rb
+++ b/lib/stomp.rb
@@ -15,15 +15,24 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-require 'stomp/constants' # Constants first
-require 'stomp/ext/hash'
-require 'stomp/connection'
-require 'stomp/client'
-require 'stomp/message'
-require 'stomp/version'
-require 'stomp/errors'
-require 'stomp/codec'
-require 'stomp/sslparams'
+require 'stomp/constants' # Constants first
+require 'stomp/ext/hash' # #Hash additions
+require 'stomp/connection' # Main Stomp#Connection
+require 'stomp/client' # Main Stomp#Client
+require 'stomp/message' # Stomp#Message
+require 'stomp/version' # Stomp#Version#STRING
+require 'stomp/errors' # All Stomp# exceptions
+require 'stomp/codec' # Stomp 1.1 codec
+require 'stomp/sslparams' # Stomp SSL support
+
+# Private methods in #Client
+require 'client/utils' # private Client Utility methods
+
+# Private methods in #Connection
+require 'connection/utils' # private Connection Utility methods
+require 'connection/netio' # private Network io methods
+require 'connection/heartbeats' # private 1.1+ heartbeat related methods
+require 'connection/utf8' # private 1.1+ UTF8 related methods
module Stomp
end
diff --git a/lib/stomp/client.rb b/lib/stomp/client.rb
index e46eea7..14bd9a7 100644
--- a/lib/stomp/client.rb
+++ b/lib/stomp/client.rb
@@ -12,20 +12,59 @@ module Stomp
# in that thread if you have much message volume.
class Client
- attr_reader :login, :passcode, :host, :port, :reliable, :parameters
-
- #alias :obj_send :send
+ public
- # A new Client object can be initialized using two forms:
+ # The login ID used by the client.
+ attr_reader :login
+
+ # The login credentials used by the client.
+ attr_reader :passcode
+
+ # The Stomp host specified by the client.
+ attr_reader :host
+
+ # The Stomp host's listening port.
+ attr_reader :port
+
+ # Is this connection reliable?
+ attr_reader :reliable
+
+ # Parameters Hash, possibly nil for a non-hashed connect.
+ attr_reader :parameters
+
+ # A new Client object can be initialized using three forms:
#
- # Standard positional parameters:
+ # Hash (this is the recommended Client initialization method):
+ #
+ # hash = {
+ # :hosts => [
+ # {:login => "login1", :passcode => "passcode1", :host => "localhost", :port => 61616, :ssl => false},
+ # {:login => "login2", :passcode => "passcode2", :host => "remotehost", :port => 61617, :ssl => false}
+ # ],
+ # :reliable => true,
+ # :initial_reconnect_delay => 0.01,
+ # :max_reconnect_delay => 30.0,
+ # :use_exponential_back_off => true,
+ # :back_off_multiplier => 2,
+ # :max_reconnect_attempts => 0,
+ # :randomize => false,
+ # :backup => false,
+ # :connect_timeout => 0,
+ # :connect_headers => {},
+ # :parse_timeout => 5,
+ # :logger => nil,
+ # }
+ #
+ # e.g. c = Stomp::Client.new(hash)
+ #
+ # Positional parameters:
# login (String, default : '')
# passcode (String, default : '')
# host (String, default : 'localhost')
# port (Integer, default : 61613)
# reliable (Boolean, default : false)
#
- # e.g. c = Client.new('login', 'passcode', 'localhost', 61613, true)
+ # e.g. c = Stomp::Client.new('login', 'passcode', 'localhost', 61613, true)
#
# Stomp URL :
# A Stomp URL must begin with 'stomp://' and can be in one of the following forms:
@@ -35,19 +74,21 @@ module Stomp
# stomp://login:passcode@host:port
# stomp://login:passcode@host.domain.tld:port
#
+ # e.g. c = Stomp::Client.new(urlstring)
+ #
def initialize(login = '', passcode = '', host = 'localhost', port = 61613, reliable = false, autoflush = false)
# Parse stomp:// URL's or set params
if login.is_a?(Hash)
@parameters = login
-
+
first_host = @parameters[:hosts][0]
-
+
@login = first_host[:login]
@passcode = first_host[:passcode]
@host = first_host[:host]
@port = first_host[:port] || Connection::default_port(first_host[:ssl])
-
+
@reliable = true
elsif login =~ /^stomp:\/\/#{url_regex}/ # e.g. stomp://login:passcode@host:port or stomp://host:port
@login = $2 || ""
@@ -55,26 +96,26 @@ module Stomp
@host = $4
@port = $5.to_i
@reliable = false
- elsif login =~ /^failover:(\/\/)?\(stomp(\+ssl)?:\/\/#{url_regex}(,stomp(\+ssl)?:\/\/#{url_regex}\))+(\?(.*))?$/ # e.g. failover://(stomp://login1:passcode1@localhost:61616,stomp://login2:passcode2@remotehost:61617)?option1=param
-
+ elsif login =~ /^failover:(\/\/)?\(stomp(\+ssl)?:\/\/#{url_regex}(,stomp(\+ssl)?:\/\/#{url_regex}\))+(\?(.*))?$/
+ # e.g. failover://(stomp://login1:passcode1@localhost:61616,stomp://login2:passcode2@remotehost:61617)?option1=param
first_host = {}
first_host[:ssl] = !$2.nil?
@login = first_host[:login] = $4 || ""
@passcode = first_host[:passcode] = $5 || ""
@host = first_host[:host] = $6
@port = first_host[:port] = $7.to_i || Connection::default_port(first_host[:ssl])
-
+
options = $16 || ""
parts = options.split(/&|=/)
options = Hash[*parts]
-
+
hosts = [first_host] + parse_hosts(login)
-
+
@parameters = {}
@parameters[:hosts] = hosts
-
+
@parameters.merge! filter_options(options)
-
+
@reliable = true
else
@login = login
@@ -84,9 +125,9 @@ module Stomp
@reliable = reliable
end
- check_arguments!
+ check_arguments!()
- @id_mutex = Mutex.new
+ @id_mutex = Mutex.new()
@ids = 1
if @parameters
@@ -95,28 +136,28 @@ module Stomp
@connection = Connection.new(@login, @passcode, @host, @port, @reliable)
@connection.autoflush = autoflush
end
-
- start_listeners
+
+ start_listeners()
end
-
- # Syntactic sugar for 'Client.new' See 'initialize' for usage.
+
+ # open is syntactic sugar for 'Client.new' See 'initialize' for usage.
def self.open(login = '', passcode = '', host = 'localhost', port = 61613, reliable = false)
Client.new(login, passcode, host, port, reliable)
end
- # Join the listener thread for this client,
- # generally used to wait for a quit signal
+ # join the listener thread for this client,
+ # generally used to wait for a quit signal.
def join(limit = nil)
@listener_thread.join(limit)
end
- # Begin a transaction by name
+ # Begin starts work in a a transaction by name.
def begin(name, headers = {})
@connection.begin(name, headers)
end
- # Abort a transaction by name
+ # Abort aborts work in a transaction by name.
def abort(name, headers = {})
@connection.abort(name, headers)
@@ -131,7 +172,7 @@ module Stomp
end
end
- # Commit a transaction by name
+ # Commit commits work in a transaction by name.
def commit(name, headers = {})
txn_id = headers[:transaction]
@replay_messages_by_txn.delete(txn_id)
@@ -139,9 +180,8 @@ module Stomp
end
# Subscribe to a destination, must be passed a block
- # which will be used as a callback listener
- #
- # Accepts a transaction header ( :transaction => 'some_transaction_id' )
+ # which will be used as a callback listener.
+ # Accepts a transaction header ( :transaction => 'some_transaction_id' ).
def subscribe(destination, headers = {})
raise "No listener given" unless block_given?
# use subscription id to correlate messages to subscription. As described in
@@ -155,7 +195,7 @@ module Stomp
@connection.subscribe(destination, headers)
end
- # Unsubecribe from a channel
+ # Unsubscribe from a subscription by name.
def unsubscribe(name, headers = {})
set_subscription_id_if_missing(name, headers)
@connection.unsubscribe(name, headers)
@@ -163,9 +203,8 @@ module Stomp
end
# Acknowledge a message, used when a subscription has specified
- # client acknowledgement ( connection.subscribe "/queue/a", :ack => 'client'g
- #
- # Accepts a transaction header ( :transaction => 'some_transaction_id' )
+ # client acknowledgement ( connection.subscribe("/queue/a",{:ack => 'client'}).
+ # Accepts a transaction header ( :transaction => 'some_transaction_id' ).
def acknowledge(message, headers = {})
txn_id = headers[:transaction]
if txn_id
@@ -180,222 +219,131 @@ module Stomp
if block_given?
headers['receipt'] = register_receipt_listener lambda {|r| yield r}
end
- @connection.ack message.headers['message-id'], headers
+ @connection.ack(message.headers['message-id'], headers)
end
- # Stomp 1.1+ NACK
+ # Stomp 1.1+ NACK.
def nack(message_id, headers = {})
- @connection.nack message_id, headers
+ @connection.nack(message_id, headers)
end
- # Unreceive a message, sending it back to its queue or to the DLQ
- #
+ # Unreceive a message, sending it back to its queue or to the DLQ.
def unreceive(message, options = {})
@connection.unreceive(message, options)
end
-
- # Publishes message to destination
- #
+
+ # Publishes message to destination.
# If a block is given a receipt will be requested and passed to the
- # block on receipt
- #
- # Accepts a transaction header ( :transaction => 'some_transaction_id' )
+ # block on receipt.
+ # Accepts a transaction header ( :transaction => 'some_transaction_id' ).
def publish(destination, message, headers = {})
if block_given?
headers['receipt'] = register_receipt_listener lambda {|r| yield r}
end
@connection.publish(destination, message, headers)
end
-
+
+ # :TODO: This should not be used. Currently only referenced in the
+ # spec tests.
+ # *NOTE* This will be removed in the next release.
def obj_send(*args)
__send__(*args)
end
-
- def connection_frame
+
+ # Return the broker's CONNECTED frame to the client. Misnamed.
+ def connection_frame()
@connection.connection_frame
end
- def disconnect_receipt
+ # Return any RECEIPT frame received by DISCONNECT.
+ def disconnect_receipt()
@connection.disconnect_receipt
end
- # Is this client open?
+ # open? tests if this client connection is open.
def open?
- @connection.open?
+ @connection.open?()
end
- # Is this client closed?
- def closed?
- @connection.closed?
+ # close? tests if this client connection is closed.
+ def closed?()
+ @connection.closed?()
end
- # Close out resources in use by this client
- def close headers={}
+ # close frees resources in use by this client. The listener thread is
+ # terminated, and disconnect on the connection is called.
+ def close(headers={})
@listener_thread.exit
- @connection.disconnect headers
+ @connection.disconnect(headers)
end
- # Check if the thread was created and isn't dead
- def running
+ # running checks if the thread was created and is not dead.
+ def running()
@listener_thread && !!@listener_thread.status
end
- # Convenience method
+ # set_logger identifies a new callback logger.
def set_logger(logger)
@connection.set_logger(logger)
end
- # Convenience method
+ # protocol returns the current client's protocol level.
def protocol()
- @connection.protocol
+ @connection.protocol()
end
- # Convenience method
+ # valid_utf8? validates any given string for UTF8 compliance.
def valid_utf8?(s)
@connection.valid_utf8?(s)
end
- # Convenience method for clients
+ # sha1 returns a SHA1 sum of a given string.
def sha1(data)
@connection.sha1(data)
end
- # Convenience method for clients
+ # uuid returns a type 4 UUID.
def uuid()
@connection.uuid()
end
- # Retrieve heartbeat send interval
- def hbsend_interval
- @connection.hbsend_interval
+ # hbsend_interval returns the connection's heartbeat send interval.
+ def hbsend_interval()
+ @connection.hbsend_interval()
end
- # Retrieve heartbeat receive interval
- def hbrecv_interval
- @connection.hbrecv_interval
+ # hbrecv_interval returns the connection's heartbeat receive interval.
+ def hbrecv_interval()
+ @connection.hbrecv_interval()
end
- # Retrieve heartbeat send count
- def hbsend_count
- @connection.hbsend_count
+ # hbsend_count returns the current connection's heartbeat send count.
+ def hbsend_count()
+ @connection.hbsend_count()
end
- # Retrieve heartbeat receive count
- def hbrecv_count
- @connection.hbrecv_count
+ # hbrecv_count returns the current connection's heartbeat receive count.
+ def hbrecv_count()
+ @connection.hbrecv_count()
end
# Poll for asynchronous messages issued by broker.
# Return nil of no message available, else the message
- def poll
- @connection.poll
+ def poll()
+ @connection.poll()
end
+ # autoflush= sets the current connection's autoflush setting.
def autoflush=(af)
@connection.autoflush = af
end
- def autoflush
- @connection.autoflush
+ # autoflush returns the current connection's autoflush setting.
+ def autoflush()
+ @connection.autoflush()
end
- private
- # Set a subscription id in the headers hash if one does not already exist.
- # For simplicities sake, all subscriptions have a subscription ID.
- # setting an id in the SUBSCRIPTION header is described in the stomp protocol docs:
- # http://stomp.github.com/
- def set_subscription_id_if_missing(destination, headers)
- headers[:id] = headers[:id] ? headers[:id] : headers['id']
- if headers[:id] == nil
- headers[:id] = Digest::SHA1.hexdigest(destination)
- end
- end
-
- def register_receipt_listener(listener)
- id = -1
- @id_mutex.synchronize do
- id = @ids.to_s
- @ids = @ids.succ
- end
- @receipt_listeners[id] = listener
- id
- end
-
- # e.g. login:passcode at host:port or host:port
- def url_regex
- '(([\w\.\-]*):(\w*)@)?([\w\.\-]+):(\d+)'
- end
-
- def parse_hosts(url)
- hosts = []
-
- host_match = /stomp(\+ssl)?:\/\/(([\w\.]*):(\w*)@)?([\w\.]+):(\d+)\)/
- url.scan(host_match).each do |match|
- host = {}
- host[:ssl] = !match[0].nil?
- host[:login] = match[2] || ""
- host[:passcode] = match[3] || ""
- host[:host] = match[4]
- host[:port] = match[5].to_i
-
- hosts << host
- end
-
- hosts
- end
-
- def check_arguments!
- raise ArgumentError if @host.nil? || @host.empty?
- raise ArgumentError if @port.nil? || @port == '' || @port < 1 || @port > 65535
- raise ArgumentError unless @reliable.is_a?(TrueClass) || @reliable.is_a?(FalseClass)
- end
-
- def filter_options(options)
- new_options = {}
- new_options[:initial_reconnect_delay] = (options["initialReconnectDelay"] || 10).to_f / 1000 # In ms
- new_options[:max_reconnect_delay] = (options["maxReconnectDelay"] || 30000 ).to_f / 1000 # In ms
- new_options[:use_exponential_back_off] = !(options["useExponentialBackOff"] == "false") # Default: true
- new_options[:back_off_multiplier] = (options["backOffMultiplier"] || 2 ).to_i
- new_options[:max_reconnect_attempts] = (options["maxReconnectAttempts"] || 0 ).to_i
- new_options[:randomize] = options["randomize"] == "true" # Default: false
- new_options[:backup] = false # Not implemented yet: I'm using a master X slave solution
- new_options[:timeout] = -1 # Not implemented yet: a "timeout(5) do ... end" would do the trick, feel free
-
- new_options
- end
-
- def find_listener(message)
- subscription_id = message.headers['subscription']
- if subscription_id == nil
- # For backward compatibility, some messages may already exist with no
- # subscription id, in which case we can attempt to synthesize one.
- set_subscription_id_if_missing(message.headers['destination'], message.headers)
- subscription_id = message.headers[:id]
- end
- @listeners[subscription_id]
- end
+ end # Class
- def start_listeners
- @listeners = {}
- @receipt_listeners = {}
- @replay_messages_by_txn = {}
-
- @listener_thread = Thread.start do
- while true
- message = @connection.receive
- if message.command == Stomp::CMD_MESSAGE
- if listener = find_listener(message)
- listener.call(message)
- end
- elsif message.command == Stomp::CMD_RECEIPT
- if listener = @receipt_listeners[message.headers['receipt-id']]
- listener.call(message)
- end
- end
- end
- end
-
- end
- end
-end
+end # Module
diff --git a/lib/stomp/codec.rb b/lib/stomp/codec.rb
index 804335a..7b95f86 100644
--- a/lib/stomp/codec.rb
+++ b/lib/stomp/codec.rb
@@ -14,7 +14,9 @@ module Stomp
#
class HeaderCodec
- # Encode header data per STOMP 1.1 specification
+ public
+
+ # encode encodes header data per the STOMP 1.1 specification.
def self.encode(in_string = nil)
return in_string unless in_string
ev = Stomp::ENCODE_VALUES # avoid typing below
@@ -25,7 +27,7 @@ module Stomp
os
end
- # Decode header data per STOMP 1.1 specification
+ # decode decodes header data per the STOMP 1.1 specification.
def self.decode(in_string = nil)
return in_string unless in_string
ev = Stomp::DECODE_VALUES # avoid typing below
@@ -37,5 +39,6 @@ module Stomp
end
end # of class HeaderCodec
+
end # of module Stomp
diff --git a/lib/stomp/connection.rb b/lib/stomp/connection.rb
index 5f2f106..fe01678 100644
--- a/lib/stomp/connection.rb
+++ b/lib/stomp/connection.rb
@@ -10,31 +10,39 @@ module Stomp
# Low level connection which maps commands and supports
# synchronous receives
class Connection
+
+ public
+
+ # The CONNECTED frame from the broker.
attr_reader :connection_frame
+
+ # Any disconnect RECEIPT frame if requested.
attr_reader :disconnect_receipt
+
+ # The Stomp Protocol version.
attr_reader :protocol
+
+ # A unique session ID, assigned by the broker.
attr_reader :session
+
+ # Heartbeat receive has been on time.
attr_reader :hb_received # Heartbeat received on time
+
+ # Heartbeat send has been successful.
attr_reader :hb_sent # Heartbeat sent successfully
+
+ # Autoflush forces a flush on each transmit. This may be changed
+ # dynamically by calling code.
attr_accessor :autoflush
- #alias :obj_send :send
+ # default_port returns the default port used by the gem for TCP or SSL.
def self.default_port(ssl)
ssl ? 61612 : 61613
end
- # A new Connection object accepts the following parameters:
+ # A new Connection object can be initialized using two forms:
#
- # login (String, default : '')
- # passcode (String, default : '')
- # host (String, default : 'localhost')
- # port (Integer, default : 61613)
- # reliable (Boolean, default : false)
- # reconnect_delay (Integer, default : 5)
- #
- # e.g. c = Connection.new("username", "password", "localhost", 61613, true)
- #
- # Hash:
+ # Hash (this is the recommended Connection initialization method:
#
# hash = {
# :hosts => [
@@ -55,16 +63,18 @@ module Stomp
# :logger => nil,
# }
#
- # e.g. c = Connection.new(hash)
+ # e.g. c = Stomp::Connection.new(hash)
#
- # TODO
- # Stomp URL :
- # A Stomp URL must begin with 'stomp://' and can be in one of the following forms:
+ # Positional parameters:
+ #
+ # login (String, default : '')
+ # passcode (String, default : '')
+ # host (String, default : 'localhost')
+ # port (Integer, default : 61613)
+ # reliable (Boolean, default : false)
+ # reconnect_delay (Integer, default : 5)
#
- # stomp://host:port
- # stomp://host.domain.tld:port
- # stomp://user:pass@host:port
- # stomp://user:pass@host.domain.tld:port
+ # e.g. c = Stomp::Connection.new("username", "password", "localhost", 61613, true)
#
def initialize(login = '', passcode = '', host = 'localhost', port = 61613, reliable = false, reconnect_delay = 5, connect_headers = {})
@received_messages = []
@@ -105,6 +115,8 @@ module Stomp
socket
end
+ # hashed_initialize prepares a new connection with a Hash of initialization
+ # parameters.
def hashed_initialize(params)
@parameters = refine_params(params)
@@ -119,12 +131,14 @@ module Stomp
change_host
end
- # Syntactic sugar for 'Connection.new' See 'initialize' for usage.
+ # open is syntactic sugar for 'Connection.new' See 'initialize' for usage.
def Connection.open(login = '', passcode = '', host = 'localhost', port = 61613, reliable = false, reconnect_delay = 5, connect_headers = {})
Connection.new(login, passcode, host, port, reliable, reconnect_delay, connect_headers)
end
- def socket
+ # socket creates and returns a new socket for use by the connection.
+ # *NOTE* this method will be made private in the next realease.
+ def socket()
@socket_semaphore.synchronize do
used_socket = @socket
used_socket = nil if closed?
@@ -132,7 +146,7 @@ module Stomp
while used_socket.nil? || !@failure.nil?
@failure = nil
begin
- used_socket = open_socket
+ used_socket = open_socket()
# Open complete
connect(used_socket)
@@ -145,6 +159,7 @@ module Stomp
used_socket = nil
raise unless @reliable
raise if @failure.is_a?(Stomp::Error::LoggerConnectionError)
+ @closed = true
if @logger && @logger.respond_to?(:on_connectfail)
# on_connectfail may raise
begin
@@ -162,8 +177,8 @@ module Stomp
@connection_attempts += 1
if @parameters
- change_host
- increase_reconnect_delay
+ change_host()
+ increase_reconnect_delay()
end
end
end
@@ -171,6 +186,8 @@ module Stomp
end
end
+ # refine_params sets up defaults for a Hash initialize.
+ # *NOTE* This method will be made private in the next release.
def refine_params(params)
params = params.uncamelize_and_symbolize_keys
default_params = {
@@ -197,6 +214,8 @@ module Stomp
return res_params
end
+ # change_host selects the next host for retires.
+ # *NOTE* This method will be made private in the next release.
def change_host
@parameters[:hosts] = @parameters[:hosts].sort_by { rand } if @parameters[:randomize]
@@ -212,10 +231,16 @@ module Stomp
end
+ # max_reconnect_attempts? returns nil or the number of maximum reconnect
+ # attempts.
+ # *NOTE* This method will be made private in the next release.
def max_reconnect_attempts?
!(@parameters.nil? || @parameters[:max_reconnect_attempts].nil?) && @parameters[:max_reconnect_attempts] != 0 && @connection_attempts >= @parameters[:max_reconnect_attempts]
end
+ # increase_reconnect_delay increases the reconnect delay for the next connection
+ # attempt.
+ # *NOTE* This method will be made private in the next release.
def increase_reconnect_delay
@reconnect_delay *= @parameters[:back_off_multiplier] if @parameters[:use_exponential_back_off]
@@ -224,17 +249,17 @@ module Stomp
@reconnect_delay
end
- # Is this connection open?
+ # open? tests if this connection is open.
def open?
!@closed
end
- # Is this connection closed?
+ # closed? tests if this connection is closed.
def closed?
@closed
end
- # Begin a transaction, requires a name for the transaction
+ # Begin starts a transaction, and requires a name for the transaction
def begin(name, headers = {})
raise Stomp::Error::NoCurrentConnection if closed?
headers = headers.symbolize_keys
@@ -244,8 +269,7 @@ module Stomp
end
# Acknowledge a message, used when a subscription has specified
- # client acknowledgement ( connection.subscribe "/queue/a", :ack => 'client'g
- #
+ # client acknowledgement i.e. connection.subscribe("/queue/a", :ack => 'client').
# Accepts a transaction header ( :transaction => 'some_transaction_id' )
def ack(message_id, headers = {})
raise Stomp::Error::NoCurrentConnection if closed?
@@ -259,7 +283,7 @@ module Stomp
transmit(Stomp::CMD_ACK, headers)
end
- # STOMP 1.1+ NACK
+ # STOMP 1.1+ NACK.
def nack(message_id, headers = {})
raise Stomp::Error::NoCurrentConnection if closed?
raise Stomp::Error::UnsupportedProtocolError if @protocol == Stomp::SPL_10
@@ -271,7 +295,7 @@ module Stomp
transmit(Stomp::CMD_NACK, headers)
end
- # Commit a transaction by name
+ # Commit commits a transaction by name.
def commit(name, headers = {})
raise Stomp::Error::NoCurrentConnection if closed?
headers = headers.symbolize_keys
@@ -280,7 +304,7 @@ module Stomp
transmit(Stomp::CMD_COMMIT, headers)
end
- # Abort a transaction by name
+ # Abort aborts a transaction by name.
def abort(name, headers = {})
raise Stomp::Error::NoCurrentConnection if closed?
headers = headers.symbolize_keys
@@ -289,7 +313,8 @@ module Stomp
transmit(Stomp::CMD_ABORT, headers)
end
- # Subscribe to a destination, must specify a name
+ # Subscribe subscribes to a destination. A subscription name is required.
+ # For Stomp 1.1 a session unique subscription ID is required.
def subscribe(name, headers = {}, subId = nil)
raise Stomp::Error::NoCurrentConnection if closed?
headers = headers.symbolize_keys
@@ -313,7 +338,8 @@ module Stomp
transmit(Stomp::CMD_SUBSCRIBE, headers)
end
- # Unsubscribe from a destination, which must be specified
+ # Unsubscribe from a destination. A subscription name is required.
+ # For Stomp 1.1 a session unique subscription ID is required.
def unsubscribe(dest, headers = {}, subId = nil)
raise Stomp::Error::NoCurrentConnection if closed?
headers = headers.symbolize_keys
@@ -329,10 +355,9 @@ module Stomp
end
end
- # Publish message to destination
- #
- # To disable content length header ( :suppress_content_length => true )
- # Accepts a transaction header ( :transaction => 'some_transaction_id' )
+ # Publish message to destination.
+ # To disable content length header use header ( :suppress_content_length => true ).
+ # Accepts a transaction header ( :transaction => 'some_transaction_id' ).
def publish(destination, message, headers = {})
raise Stomp::Error::NoCurrentConnection if closed?
headers = headers.symbolize_keys
@@ -344,18 +369,19 @@ module Stomp
transmit(Stomp::CMD_SEND, headers, message)
end
+ # :TODO: Remove this method.
+ # *NOTE* This method will be removed in the next release.
def obj_send(*args)
__send__(*args)
end
- # Send a message back to the source or to the dead letter queue
- #
- # Accepts a dead letter queue option ( :dead_letter_queue => "/queue/DLQ" )
- # Accepts a limit number of redeliveries option ( :max_redeliveries => 6 )
- # Accepts a force client acknowledgement option (:force_client_ack => true)
+ # Send a message back to the source or to the dead letter queue.
+ # Accepts a dead letter queue option ( :dead_letter_queue => "/queue/DLQ" ).
+ # Accepts a limit number of redeliveries option ( :max_redeliveries => 6 ).
+ # Accepts a force client acknowledgement option (:force_client_ack => true).
def unreceive(message, options = {})
raise Stomp::Error::NoCurrentConnection if closed?
- options = { :dead_letter_queue => "/queue/DLQ", :max_redeliveries => 6 }.merge options
+ options = { :dead_letter_queue => "/queue/DLQ", :max_redeliveries => 6 }.merge(options)
# Lets make sure all keys are symbols
message.headers = message.headers.symbolize_keys
@@ -372,10 +398,14 @@ module Stomp
end
if retry_count <= options[:max_redeliveries]
- self.publish(message.headers[:destination], message.body, message.headers.merge(:transaction => transaction_id))
+ self.publish(message.headers[:destination], message.body,
+ message.headers.merge(:transaction => transaction_id))
else
# Poison ack, sending the message to the DLQ
- self.publish(options[:dead_letter_queue], message.body, message.headers.merge(:transaction => transaction_id, :original_destination => message.headers[:destination], :persistent => true))
+ self.publish(options[:dead_letter_queue], message.body,
+ message.headers.merge(:transaction => transaction_id,
+ :original_destination => message.headers[:destination],
+ :persistent => true))
end
self.commit transaction_id
rescue Exception => exception
@@ -384,12 +414,14 @@ module Stomp
end
end
+ # client_ack? determines if headers contain :ack => "client".
def client_ack?(message)
headers = @subscriptions[message.headers[:destination]]
!headers.nil? && headers[:ack] == "client"
end
- # Close this connection
+ # disconnect closes this connection. If requested, a disconnect RECEIPT
+ # is received.
def disconnect(headers = {})
raise Stomp::Error::NoCurrentConnection if closed?
headers = headers.symbolize_keys
@@ -406,18 +438,19 @@ module Stomp
close_socket
end
- # Return a pending message if one is available, otherwise
- # return nil
- def poll
+ # poll returns a pending message if one is available, otherwise
+ # returns nil.
+ def poll()
raise Stomp::Error::NoCurrentConnection if closed?
# No need for a read lock here. The receive method eventually fulfills
# that requirement.
return nil if @socket.nil? || !@socket.ready?
- receive
+ receive()
end
- # Receive a frame, block until the frame is received
- def __old_receive
+ # __old_receive receives a frame, blocks until the frame is received.
+ # *NOTE* This method will be made private in the next release.
+ def __old_receive()
# The receive may fail so we may need to retry.
while TRUE
begin
@@ -436,7 +469,8 @@ module Stomp
end
end
- def receive
+ # receive returns the next Message off of the wire.
+ def receive()
raise Stomp::Error::NoCurrentConnection if closed?
super_result = __old_receive
if super_result.nil? && @reliable && !closed?
@@ -456,855 +490,65 @@ module Stomp
return super_result
end
- # Convenience method
+ # set_logger selects a new callback logger instance.
def set_logger(logger)
@logger = logger
end
- # Convenience method
+ # valid_utf8? returns an indicator if the given string is a valid UTF8 string.
def valid_utf8?(s)
case RUBY_VERSION
- when /1\.8/
- rv = _valid_utf8?(s)
- else
- rv = s.encoding.name != Stomp::UTF8 ? false : s.valid_encoding?
+ when /1\.8/
+ rv = _valid_utf8?(s)
+ else
+ rv = s.encoding.name != Stomp::UTF8 ? false : s.valid_encoding?
end
rv
end
- # Convenience method for clients, return a SHA1 digest for arbitrary data
+ # sha1 returns a SHA1 digest for arbitrary string data.
def sha1(data)
Digest::SHA1.hexdigest(data)
end
- # Convenience method for clients, return a type 4 UUID.
+ # uuid returns a type 4 UUID.
def uuid()
b = []
0.upto(15) do |i|
b << rand(255)
end
- b[6] = (b[6] & 0x0F) | 0x40
- b[8] = (b[8] & 0xbf) | 0x80
+ b[6] = (b[6] & 0x0F) | 0x40
+ b[8] = (b[8] & 0xbf) | 0x80
# 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
- rs = sprintf("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x",
- b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15])
+ rs = sprintf("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x",
+ b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15])
rs
end
- # Retrieve heartbeat send interval
- def hbsend_interval
+ # hbsend_interval returns the connection's heartbeat send interval.
+ def hbsend_interval()
return 0 unless @hbsend_interval
@hbsend_interval / 1000.0 # ms
end
- # Retrieve heartbeat receive interval
- def hbrecv_interval
+ # hbrecv_interval returns the connection's heartbeat receive interval.
+ def hbrecv_interval()
return 0 unless @hbrecv_interval
@hbrecv_interval / 1000.0 # ms
end
- # Retrieve heartbeat send count
- def hbsend_count
+ # hbsend_count returns the current connection's heartbeat send count.
+ def hbsend_count()
return 0 unless @hbsend_count
@hbsend_count
end
- # Retrieve heartbeat receive count
- def hbrecv_count
+ # hbrecv_count returns the current connection's heartbeat receive count.
+ def hbrecv_count()
return 0 unless @hbrecv_count
@hbrecv_count
end
- private
-
- def _expand_hosts(hash)
- new_hash = hash.clone
- new_hash[:hosts_cloned] = hash[:hosts].clone
- new_hash[:hosts] = []
- #
- hash[:hosts].each do |host_parms|
- ai = Socket.getaddrinfo(host_parms[:host], nil, nil, Socket::SOCK_STREAM)
- next if ai.nil? || ai.size == 0
- info6 = ai.detect {|info| info[4] == Socket::AF_INET6}
- info4 = ai.detect {|info| info[4] == Socket::AF_INET}
- if info6
- new_hostp = host_parms.clone
- new_hostp[:host] = info6[3]
- new_hash[:hosts] << new_hostp
- end
- if info4
- new_hostp = host_parms.clone
- new_hostp[:host] = info4[3]
- new_hash[:hosts] << new_hostp
- end
- end
- return new_hash
- end
-
- def _receive( read_socket )
- @read_semaphore.synchronize do
- line = ''
- if @protocol == Stomp::SPL_10 || (@protocol >= Stomp::SPL_11 && !@hbr)
- line = read_socket.gets # The old way
- else # We are >= 1.1 and receiving heartbeats.
- while true
- line = read_socket.gets # Data from wire
- break unless line == "\n"
- line = ''
- @lr = Time.now.to_f
- end
- end
- return nil if line.nil?
- # If the reading hangs for more than X seconds, abort the parsing process.
- # X defaults to 5. Override allowed in connection hash parameters.
- Timeout::timeout(@parse_timeout, Stomp::Error::PacketParsingTimeout) do
- # Reads the beginning of the message until it runs into a empty line
- message_header = ''
- begin
- message_header += line
- line = read_socket.gets
- raise Stomp::Error::StompServerError if line.nil?
- end until line =~ /^\s?\n$/
-
- # Checks if it includes content_length header
- content_length = message_header.match /content-length\s?:\s?(\d+)\s?\n/
- message_body = ''
-
- # If content_length is present, read the specified amount of bytes
- if content_length
- message_body = read_socket.read content_length[1].to_i
- raise Stomp::Error::InvalidMessageLength unless parse_char(read_socket.getc) == "\0"
- # Else read the rest of the message until the first \0
- else
- message_body = read_socket.readline("\0")
- message_body.chop!
- end
-
- # If the buffer isn't empty, reads trailing new lines.
- #
- # Note: experiments with JRuby seem to show that .ready? never
- # returns true. This means that this code to drain trailing new
- # lines never runs using JRuby.
- #
- # Note 2: the draining of new lines mmust be done _after_ a message
- # is read. Do _not_ leave them on the wire and attempt to drain them
- # at the start of the next read. Attempting to do that breaks the
- # asynchronous nature of the 'poll' method.
- while read_socket.ready?
- last_char = read_socket.getc
- break unless last_char
- if parse_char(last_char) != "\n"
- read_socket.ungetc(last_char)
- break
- end
- end
- # And so, a JRuby hack. Remove any new lines at the start of the
- # next buffer.
- message_header.gsub!(/^\n?/, "")
-
- if @protocol >= Stomp::SPL_11
- @lr = Time.now.to_f if @hbr
- end
- # Adds the excluded \n and \0 and tries to create a new message with it
- msg = Message.new(message_header + "\n" + message_body + "\0", @protocol >= Stomp::SPL_11)
- #
- if @protocol >= Stomp::SPL_11 && msg.command != Stomp::CMD_CONNECTED
- msg.headers = _decodeHeaders(msg.headers)
- end
- msg
- end
- end
- end
-
- def parse_char(char)
- RUBY_VERSION > '1.9' ? char : char.chr
- end
-
- def transmit(command, headers = {}, body = '')
- # The transmit may fail so we may need to retry.
- while TRUE
- begin
- used_socket = socket
- _transmit(used_socket, command, headers, body)
- return
- rescue Stomp::Error::MaxReconnectAttempts => e
- raise
- rescue
- @failure = $!
- raise unless @reliable
- errstr = "transmit to #{@host} failed: #{$!}\n"
- if @logger && @logger.respond_to?(:on_miscerr)
- @logger.on_miscerr(log_params, errstr)
- else
- $stderr.print errstr
- end
- end
- end
- end
-
- def _transmit(used_socket, command, headers = {}, body = '')
- if @protocol >= Stomp::SPL_11 && command != Stomp::CMD_CONNECT
- headers = _encodeHeaders(headers)
- end
- @transmit_semaphore.synchronize do
- # Handle nil body
- body = '' if body.nil?
- # The content-length should be expressed in bytes.
- # Ruby 1.8: String#length => # of bytes; Ruby 1.9: String#length => # of characters
- # With Unicode strings, # of bytes != # of characters. So, use String#bytesize when available.
- body_length_bytes = body.respond_to?(:bytesize) ? body.bytesize : body.length
-
- # ActiveMQ interprets every message as a BinaryMessage
- # if content_length header is included.
- # Using :suppress_content_length => true will suppress this behaviour
- # and ActiveMQ will interpret the message as a TextMessage.
- # For more information refer to http://juretta.com/log/2009/05/24/activemq-jms-stomp/
- # Lets send this header in the message, so it can maintain state when using unreceive
- headers[:'content-length'] = "#{body_length_bytes}" unless headers[:suppress_content_length]
- headers[:'content-type'] = "text/plain; charset=UTF-8" unless headers[:'content-type']
- used_socket.puts command
- headers.each do |k,v|
- if v.is_a?(Array)
- v.each do |e|
- used_socket.puts "#{k}:#{e}"
- end
- else
- used_socket.puts "#{k}:#{v}"
- end
- end
- used_socket.puts
- used_socket.write body
- used_socket.write "\0"
- used_socket.flush if autoflush
-
- if @protocol >= Stomp::SPL_11
- @ls = Time.now.to_f if @hbs
- end
-
- end
- end
-
- def open_tcp_socket
- tcp_socket = nil
-
- if @logger && @logger.respond_to?(:on_connecting)
- @logger.on_connecting(log_params)
- end
-
- Timeout::timeout(@connect_timeout, Stomp::Error::SocketOpenTimeout) do
- tcp_socket = TCPSocket.open @host, @port
- end
-
- tcp_socket
- end
-
- def open_ssl_socket
- require 'openssl' unless defined?(OpenSSL)
- begin # Any raised SSL exceptions
- ctx = OpenSSL::SSL::SSLContext.new
- ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE # Assume for now
- #
- # Note: if a client uses :ssl => true this results in the gem using
- # the _default_ Ruby ciphers list. This is _known_ to fail in later
- # Ruby releases. The gem provides a default cipher list that may
- # function in these cases. To use this connect with:
- # * :ssl => Stomp::SSLParams.new
- # * :ssl => Stomp::SSLParams.new(..., :ciphers => Stomp::DEFAULT_CIPHERS)
- #
- # If connecting with an SSLParams instance, and the _default_ Ruby
- # ciphers list is required, use:
- # * :ssl => Stomp::SSLParams.new(..., :use_ruby_ciphers => true)
- #
- # If a custom ciphers list is required, connect with:
- # * :ssl => Stomp::SSLParams.new(..., :ciphers => custom_ciphers_list)
- #
- if @ssl != true
- #
- # Here @ssl is:
- # * an instance of Stomp::SSLParams
- # Control would not be here if @ssl == false or @ssl.nil?.
- #
-
- # Back reference the SSLContext
- @ssl.ctx = ctx
-
- # Server authentication parameters if required
- if @ssl.ts_files
- ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER
- truststores = OpenSSL::X509::Store.new
- fl = @ssl.ts_files.split(",")
- fl.each do |fn|
- # Add next cert file listed
- raise Stomp::Error::SSLNoTruststoreFileError if !File::exists?(fn)
- raise Stomp::Error::SSLUnreadableTruststoreFileError if !File::readable?(fn)
- truststores.add_file(fn)
- end
- ctx.cert_store = truststores
- end
-
- # Client authentication parameters
- # Both cert file and key file must be present or not, it can not be a mix
- raise Stomp::Error::SSLClientParamsError if @ssl.cert_file.nil? && !@ssl.key_file.nil?
- raise Stomp::Error::SSLClientParamsError if !@ssl.cert_file.nil? && @ssl.key_file.nil?
- if @ssl.cert_file # Any check will do here
- raise Stomp::Error::SSLNoCertFileError if !File::exists?(@ssl.cert_file)
- raise Stomp::Error::SSLUnreadableCertFileError if !File::readable?(@ssl.cert_file)
- ctx.cert = OpenSSL::X509::Certificate.new(File.read(@ssl.cert_file))
- raise Stomp::Error::SSLNoKeyFileError if !File::exists?(@ssl.key_file)
- raise Stomp::Error::SSLUnreadableKeyFileError if !File::readable?(@ssl.key_file)
- ctx.key = OpenSSL::PKey::RSA.new(File.read(@ssl.key_file), @ssl.key_password)
- end
-
- # Cipher list
- if !@ssl.use_ruby_ciphers # No Ruby ciphers (the default)
- if @ssl.ciphers # User ciphers list?
- ctx.ciphers = @ssl.ciphers # Accept user supplied ciphers
- else
- ctx.ciphers = Stomp::DEFAULT_CIPHERS # Just use Stomp defaults
- end
- end
- end
-
- #
- ssl = nil
- if @logger && @logger.respond_to?(:on_ssl_connecting)
- @logger.on_ssl_connecting(log_params)
- end
-
- Timeout::timeout(@connect_timeout, Stomp::Error::SocketOpenTimeout) do
- ssl = OpenSSL::SSL::SSLSocket.new(open_tcp_socket, ctx)
- end
- def ssl.ready?
- ! @rbuffer.empty? || @io.ready?
- end
- ssl.connect
- if @ssl != true
- # Pass back results if possible
- if RUBY_VERSION =~ /1\.8\.[56]/
- @ssl.verify_result = "N/A for Ruby #{RUBY_VERSION}"
- else
- @ssl.verify_result = ssl.verify_result
- end
- @ssl.peer_cert = ssl.peer_cert
- end
- if @logger && @logger.respond_to?(:on_ssl_connected)
- @logger.on_ssl_connected(log_params)
- end
- ssl
- rescue Exception => ex
- if @logger && @logger.respond_to?(:on_ssl_connectfail)
- lp = log_params.clone
- lp[:ssl_exception] = ex
- @logger.on_ssl_connectfail(lp)
- end
- #
- raise # Reraise
- end
- end
-
- def close_socket
- begin
- # Need to set @closed = true before closing the socket
- # within the @read_semaphore thread
- @closed = true
- @read_semaphore.synchronize do
- @socket.close
- end
- rescue
- #Ignoring if already closed
- end
- @closed
- end
-
- def open_socket
- used_socket = @ssl ? open_ssl_socket : open_tcp_socket
- # try to close the old connection if any
- close_socket
-
- @closed = false
- # Use keepalive
- used_socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, true)
- used_socket
- end
-
- def connect(used_socket)
- @connect_headers = {} unless @connect_headers # Caller said nil/false
- headers = @connect_headers.clone
- headers[:login] = @login
- headers[:passcode] = @passcode
- _pre_connect
- _transmit(used_socket, "CONNECT", headers)
- @connection_frame = _receive(used_socket)
- _post_connect
- @disconnect_receipt = nil
- @session = @connection_frame.headers["session"] if @connection_frame
- # replay any subscriptions.
- @subscriptions.each { |k,v| _transmit(used_socket, Stomp::CMD_SUBSCRIBE, v) }
- end
-
- def log_params
- lparms = @parameters.clone if @parameters
- lparms = {} unless lparms
- lparms[:cur_host] = @host
- lparms[:cur_port] = @port
- lparms[:cur_login] = @login
- lparms[:cur_passcode] = @passcode
- lparms[:cur_ssl] = @ssl
- lparms[:cur_recondelay] = @reconnect_delay
- lparms[:cur_parseto] = @parse_timeout
- lparms[:cur_conattempts] = @connection_attempts
- #
- lparms
- end
-
- def _pre_connect
- @connect_headers = @connect_headers.symbolize_keys
- raise Stomp::Error::ProtocolErrorConnect if (@connect_headers[:"accept-version"] && !@connect_headers[:host])
- raise Stomp::Error::ProtocolErrorConnect if (!@connect_headers[:"accept-version"] && @connect_headers[:host])
- return unless (@connect_headers[:"accept-version"] && @connect_headers[:host]) # 1.0
- # Try 1.1 or greater
- okvers = []
- avers = @connect_headers[:"accept-version"].split(",")
- avers.each do |nver|
- if Stomp::SUPPORTED.index(nver)
- okvers << nver
- end
- end
- raise Stomp::Error::UnsupportedProtocolError if okvers == []
- @connect_headers[:"accept-version"] = okvers.join(",") # This goes to server
- # Heartbeats - pre connect
- return unless @connect_headers[:"heart-beat"]
- _validate_hbheader()
- end
-
- def _post_connect
- return unless (@connect_headers[:"accept-version"] && @connect_headers[:host])
- return if @connection_frame.command == Stomp::CMD_ERROR
- # We are CONNECTed
- cfh = @connection_frame.headers.symbolize_keys
- @protocol = cfh[:version]
- if @protocol
- # Should not happen, but check anyway
- raise Stomp::Error::UnsupportedProtocolError unless Stomp::SUPPORTED.index(@protocol)
- else # CONNECTed to a 1.0 server that does not return *any* 1.1 type headers
- @protocol = Stomp::SPL_10 # reset
- return
- end
- # Heartbeats
- return unless @connect_headers[:"heart-beat"]
- _init_heartbeats()
- end
-
- def _validate_hbheader()
- return if @connect_headers[:"heart-beat"] == "0,0" # Caller does not want heartbeats. OK.
- parts = @connect_headers[:"heart-beat"].split(",")
- if (parts.size != 2) || (parts[0] != parts[0].to_i.to_s) || (parts[1] != parts[1].to_i.to_s)
- raise Stomp::Error::InvalidHeartBeatHeaderError
- end
- end
-
- def _init_heartbeats()
- return if @connect_headers[:"heart-beat"] == "0,0" # Caller does not want heartbeats. OK.
- #
- @cx = @cy = @sx = @sy = 0, # Variable names as in spec
- #
- @hbsend_interval = @hbrecv_interval = 0.0 # Send/Receive ticker interval.
- #
- @hbsend_count = @hbrecv_count = 0 # Send/Receive ticker counts.
- #
- @ls = @lr = -1.0 # Last send/receive time (from Time.now.to_f)
- #
- @st = @rt = nil # Send/receive ticker thread
- #
- cfh = @connection_frame.headers.symbolize_keys
- return if cfh[:"heart-beat"] == "0,0" # Server does not want heartbeats
- #
- parts = @connect_headers[:"heart-beat"].split(",")
- @cx = parts[0].to_i
- @cy = parts[1].to_i
- #
- parts = cfh[:"heart-beat"].split(",")
- @sx = parts[0].to_i
- @sy = parts[1].to_i
- # Catch odd situations like someone has used => heart-beat:000,00000
- return if (@cx == 0 && @cy == 0) || (@sx == 0 && @sy == 0)
- #
- @hbs = @hbr = true # Sending/Receiving heartbeats. Assume yes at first.
- # Check for sending
- @hbs = false if @cx == 0 || @sy == 0
- # Check for receiving
- @hbr = false if @sx == 0 || @cy == 0
- # Should not do heartbeats at all
- return if (!@hbs && !@hbr)
- # If sending
- if @hbs
- sm = @cx >= @sy ? @cx : @sy # ticker interval, ms
- @hbsend_interval = 1000.0 * sm # ticker interval, μs
- @ls = Time.now.to_f # best guess at start
- _start_send_ticker
- end
-
- # If receiving
- if @hbr
- rm = @sx >= @cy ? @sx : @cy # ticker interval, ms
- @hbrecv_interval = 1000.0 * rm # ticker interval, μs
- @lr = Time.now.to_f # best guess at start
- _start_receive_ticker
- end
-
- end
-
- def _start_send_ticker
- sleeptime = @hbsend_interval / 1000000.0 # Sleep time secs
- @st = Thread.new {
- while true do
- sleep sleeptime
- curt = Time.now.to_f
- if @logger && @logger.respond_to?(:on_hbfire)
- @logger.on_hbfire(log_params, "send_fire", curt)
- end
- delta = curt - @ls
- if delta > (@hbsend_interval - (@hbsend_interval/5.0)) / 1000000.0 # Be tolerant (minus)
- if @logger && @logger.respond_to?(:on_hbfire)
- @logger.on_hbfire(log_params, "send_heartbeat", curt)
- end
- # Send a heartbeat
- @transmit_semaphore.synchronize do
- begin
- @socket.puts
- @ls = curt # Update last send
- @hb_sent = true # Reset if necessary
- @hbsend_count += 1
- rescue Exception => sendex
- @hb_sent = false # Set the warning flag
- if @logger && @logger.respond_to?(:on_hbwrite_fail)
- @logger.on_hbwrite_fail(log_params, {"ticker_interval" => @hbsend_interval,
- "exception" => sendex})
- end
- raise # Re-raise. What else could be done here?
- end
- end
- end
- Thread.pass
- end
- }
- end
-
- def _start_receive_ticker
- sleeptime = @hbrecv_interval / 1000000.0 # Sleep time secs
- @rt = Thread.new {
- while true do
- sleep sleeptime
- curt = Time.now.to_f
- if @logger && @logger.respond_to?(:on_hbfire)
- @logger.on_hbfire(log_params, "receive_fire", curt)
- end
- delta = curt - @lr
- if delta > ((@hbrecv_interval + (@hbrecv_interval/5.0)) / 1000000.0) # Be tolerant (plus)
- if @logger && @logger.respond_to?(:on_hbfire)
- @logger.on_hbfire(log_params, "receive_heartbeat", curt)
- end
- # Client code could be off doing something else (that is, no reading of
- # the socket has been requested by the caller). Try to handle that case.
- lock = @read_semaphore.try_lock
- if lock
- last_char = @socket.getc
- plc = parse_char(last_char)
- if plc == "\n" # Server Heartbeat
- @lr = Time.now.to_f
- else
- @socket.ungetc(last_char)
- end
- @read_semaphore.unlock
- @hbrecv_count += 1
- else
- # Shrug. Have not received one. Just set warning flag.
- @hb_received = false
- if @logger && @logger.respond_to?(:on_hbread_fail)
- @logger.on_hbread_fail(log_params, {"ticker_interval" => @hbrecv_interval})
- end
- end
- else
- @hb_received = true # Reset if necessary
- end
- Thread.pass
- end
- }
- end
-
- # Ref:
- # http://unicode.org/mail-arch/unicode-ml/y2003-m02/att-0467/01-The_Algorithm_to_Valide_an_UTF-8_String
- #
- def _valid_utf8?(string)
- case RUBY_VERSION
- when /1\.8\.[56]/
- bytes = []
- 0.upto(string.length-1) {|i|
- bytes << string[i]
- }
- else
- bytes = string.bytes
- end
-
- #
- valid = true
- index = -1
- nb_hex = nil
- ni_hex = nil
- state = "start"
- next_byte_save = nil
- #
- bytes.each do |next_byte|
- index += 1
- next_byte_save = next_byte
- ni_hex = sprintf "%x", index
- nb_hex = sprintf "%x", next_byte
- # puts "Top: #{next_byte}(0x#{nb_hex}), index: #{index}(0x#{ni_hex})" if DEBUG
- case state
-
- # State: 'start'
- # The 'start' state:
- # * handles all occurrences of valid single byte characters i.e., the ASCII character set
- # * provides state transition logic for start bytes of valid characters with 2-4 bytes
- # * signals a validation failure for all other single bytes
- #
- when "start"
- # puts "state: start" if DEBUG
- case next_byte
-
- # ASCII
- # * Input = 0x00-0x7F : change state to START
- when (0x00..0x7f)
- # puts "state: start 1" if DEBUG
- state = "start"
-
- # Start byte of two byte characters
- # * Input = 0xC2-0xDF: change state to A
- when (0xc2..0xdf)
- # puts "state: start 2" if DEBUG
- state = "a"
-
- # Start byte of some three byte characters
- # * Input = 0xE1-0xEC, 0xEE-0xEF: change state to B
- when (0xe1..0xec)
- # puts "state: start 3" if DEBUG
- state = "b"
- when (0xee..0xef)
- # puts "state: start 4" if DEBUG
- state = "b"
-
- # Start byte of special three byte characters
- # * Input = 0xE0: change state to C
- when 0xe0
- # puts "state: start 5" if DEBUG
- state = "c"
-
- # Start byte of the remaining three byte characters
- # * Input = 0xED: change state to D
- when 0xed
- # puts "state: start 6" if DEBUG
- state = "d"
-
- # Start byte of some four byte characters
- # * Input = 0xF1-0xF3:change state to E
- when (0xf1..0xf3)
- # puts "state: start 7" if DEBUG
- state = "e"
-
- # Start byte of special four byte characters
- # * Input = 0xF0: change state to F
- when 0xf0
- # puts "state: start 8" if DEBUG
- state = "f"
-
- # Start byte of very special four byte characters
- # * Input = 0xF4: change state to G
- when 0xf4
- # puts "state: start 9" if DEBUG
- state = "g"
-
- # All other single characters are invalid
- # * Input = Others (0x80-0xBF,0xC0-0xC1, 0xF5-0xFF): ERROR
- else
- valid = false
- break
- end # of the inner case, the 'start' state
-
- # The last continuation byte of a 2, 3, or 4 byte character
- # State: 'a'
- # o Input = 0x80-0xBF: change state to START
- # o Others: ERROR
- when "a"
- # puts "state: a" if DEBUG
- if (0x80..0xbf) === next_byte
- state = "start"
- else
- valid = false
- break
- end
-
- # The first continuation byte for most 3 byte characters
- # (those with start bytes in: 0xe1-0xec or 0xee-0xef)
- # State: 'b'
- # o Input = 0x80-0xBF: change state to A
- # o Others: ERROR
- when "b"
- # puts "state: b" if DEBUG
- if (0x80..0xbf) === next_byte
- state = "a"
- else
- valid = false
- break
- end
-
- # The first continuation byte for some special 3 byte characters
- # (those with start byte 0xe0)
- # State: 'c'
- # o Input = 0xA0-0xBF: change state to A
- # o Others: ERROR
- when "c"
- # puts "state: c" if DEBUG
- if (0xa0..0xbf) === next_byte
- state = "a"
- else
- valid = false
- break
- end
-
- # The first continuation byte for the remaining 3 byte characters
- # (those with start byte 0xed)
- # State: 'd'
- # o Input = 0x80-0x9F: change state to A
- # o Others: ERROR
- when "d"
- # puts "state: d" if DEBUG
- if (0x80..0x9f) === next_byte
- state = "a"
- else
- valid = false
- break
- end
-
- # The first continuation byte for some 4 byte characters
- # (those with start bytes in: 0xf1-0xf3)
- # State: 'e'
- # o Input = 0x80-0xBF: change state to B
- # o Others: ERROR
- when "e"
- # puts "state: e" if DEBUG
- if (0x80..0xbf) === next_byte
- state = "b"
- else
- valid = false
- break
- end
-
- # The first continuation byte for some special 4 byte characters
- # (those with start byte 0xf0)
- # State: 'f'
- # o Input = 0x90-0xBF: change state to B
- # o Others: ERROR
- when "f"
- # puts "state: f" if DEBUG
- if (0x90..0xbf) === next_byte
- state = "b"
- else
- valid = false
- break
- end
-
- # The first continuation byte for the remaining 4 byte characters
- # (those with start byte 0xf4)
- # State: 'g'
- # o Input = 0x80-0x8F: change state to B
- # o Others: ERROR
- when "g"
- # puts "state: g" if DEBUG
- if (0x80..0x8f) === next_byte
- state = "b"
- else
- valid = false
- break
- end
-
- #
- else
- raise RuntimeError, "state: default"
- end
- end
- #
- # puts "State at end: #{state}" if DEBUG
- # Catch truncation at end of string
- if valid and state != 'start'
- # puts "Resetting valid value" if DEBUG
- valid = false
- end
- #
- valid
- end # of _valid_utf8?
-
- def _headerCheck(h)
- return if @protocol == Stomp::SPL_10 # Do nothing for this environment
- #
- h.each_pair do |k,v|
- # Keys here are symbolized
- ks = k.to_s
- ks.force_encoding(Stomp::UTF8) if ks.respond_to?(:force_encoding)
- raise Stomp::Error::UTF8ValidationError unless valid_utf8?(ks)
- #
- if v.is_a?(Array)
- v.each do |e|
- e.force_encoding(Stomp::UTF8) if e.respond_to?(:force_encoding)
- raise Stomp::Error::UTF8ValidationError unless valid_utf8?(e)
- end
- else
- vs = v.to_s + "" # Values are usually Strings, but could be TrueClass or Symbol
- # The + "" forces an 'unfreeze' if necessary
- vs.force_encoding(Stomp::UTF8) if vs.respond_to?(:force_encoding)
- raise Stomp::Error::UTF8ValidationError unless valid_utf8?(vs)
- end
- end
- end
-
- #
- def _encodeHeaders(h)
- eh = {}
- h.each_pair do |k,v|
- # Keys are symbolized
- ks = k.to_s
- if v.is_a?(Array)
- kenc = Stomp::HeaderCodec::encode(ks)
- eh[kenc] = []
- v.each do |e|
- eh[kenc] << Stomp::HeaderCodec::encode(e)
- end
- else
- vs = v.to_s
- eh[Stomp::HeaderCodec::encode(ks)] = Stomp::HeaderCodec::encode(vs)
- end
- end
- eh
- end
-
- #
- def _decodeHeaders(h)
- dh = {}
- h.each_pair do |k,v|
- # Keys here are NOT! symbolized
- if v.is_a?(Array)
- kdec = Stomp::HeaderCodec::decode(k)
- dh[kdec] = []
- v.each do |e|
- dh[kdec] << Stomp::HeaderCodec::decode(e)
- end
- else
- vs = v.to_s
- dh[Stomp::HeaderCodec::decode(k)] = Stomp::HeaderCodec::decode(vs)
- end
- end
- dh
- end
-
end # class
end # module
diff --git a/lib/stomp/constants.rb b/lib/stomp/constants.rb
index 5183565..04dbbf6 100644
--- a/lib/stomp/constants.rb
+++ b/lib/stomp/constants.rb
@@ -2,28 +2,28 @@
module Stomp
- # Client side
- CMD_CONNECT = "CONNECT"
- CMD_STOMP = "STOMP"
- CMD_DISCONNECT = "DISCONNECT"
- CMD_SEND = "SEND"
- CMD_SUBSCRIBE = "SUBSCRIBE"
- CMD_UNSUBSCRIBE = "UNSUBSCRIBE"
- CMD_ACK = "ACK"
- CMD_NACK = "NACK"
- CMD_BEGIN = "BEGIN"
- CMD_COMMIT = "COMMIT"
- CMD_ABORT = "ABORT"
+ # Client side
+ CMD_CONNECT = "CONNECT"
+ CMD_STOMP = "STOMP"
+ CMD_DISCONNECT = "DISCONNECT"
+ CMD_SEND = "SEND"
+ CMD_SUBSCRIBE = "SUBSCRIBE"
+ CMD_UNSUBSCRIBE = "UNSUBSCRIBE"
+ CMD_ACK = "ACK"
+ CMD_NACK = "NACK"
+ CMD_BEGIN = "BEGIN"
+ CMD_COMMIT = "COMMIT"
+ CMD_ABORT = "ABORT"
- # Server side
- CMD_CONNECTED = "CONNECTED"
- CMD_MESSAGE = "MESSAGE"
- CMD_RECEIPT = "RECEIPT"
- CMD_ERROR = "ERROR"
+ # Server side
+ CMD_CONNECTED = "CONNECTED"
+ CMD_MESSAGE = "MESSAGE"
+ CMD_RECEIPT = "RECEIPT"
+ CMD_ERROR = "ERROR"
- # Protocols
- SPL_10 = "1.0"
- SPL_11 = "1.1"
+ # Protocols
+ SPL_10 = "1.0"
+ SPL_11 = "1.1"
# Stomp 1.0 and 1.1
SUPPORTED = [SPL_10, SPL_11]
@@ -38,44 +38,63 @@ module Stomp
# New line
#
NL = "\n"
- NL_ASCII = 0x0a
+ NL_ASCII = 0x0a
#
# Back Slash
#
BACK_SLASH = "\\"
- BACK_SLASH_ASCII = 0x5c
+ BACK_SLASH_ASCII = 0x5c
#
# Literal colon
#
LITERAL_COLON = ":"
- COLON_ASCII = 0x3a
+ COLON_ASCII = 0x3a
#
# Literal letter c
#
LITERAL_C = "c"
- C_ASCII = 0x63
+ C_ASCII = 0x63
#
# Literal letter n
#
LITERAL_N = "n"
- N_ASCII = 0x6e
+ N_ASCII = 0x6e
#
# Codec from/to values.
#
ENCODE_VALUES = [
- "\\\\", "\\", # encoded, decoded
- "\\" + "n", "\n",
- "\\c", ":",
+ "\\\\", "\\", # encoded, decoded
+ "\\" + "n", "\n",
+ "\\c", ":",
]
#
DECODE_VALUES = [
- "\\\\\\\\", "\\", # encoded, decoded
- "\\" + "n", "\n",
- "\\c", ":",
+ "\\\\\\\\", "\\", # encoded, decoded
+ "\\" + "n", "\n",
+ "\\c", ":",
]
- DEFAULT_CIPHERS = [["DHE-RSA-AES256-SHA", "TLSv1/SSLv3", 256, 256], ["DHE-DSS-AES256-SHA", "TLSv1/SSLv3", 256, 256], ["AES256-SHA", "TLSv1/SSLv3", 256, 256], ["EDH-RSA-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["EDH-DSS-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168], ["DHE-RSA-AES128-SHA", "TLSv1/SSLv3", 128, 128], ["DHE-DSS-AES128-SHA", "TLSv1/SSLv3", 128, 128], ["AES128-SHA", "TLSv1/SSLv3", 128, 128], ["RC4-SHA", "TLSv1/SSLv3", 128, 128], ["RC4-MD5", "TLSv1/SSLv3", 128, 128], ["EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56],
-["DES-CBC-SHA", "TLSv1/SSLv3", 56, 56], ["EXP-EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56], ["EXP-RC2-CBC-MD5", "TLSv1/SSLv3", 40, 128], ["EXP-RC4-MD5", "TLSv1/SSLv3", 40, 128]]
+ DEFAULT_CIPHERS = [
+ ["DHE-RSA-AES256-SHA", "TLSv1/SSLv3", 256, 256],
+ ["DHE-DSS-AES256-SHA", "TLSv1/SSLv3", 256, 256],
+ ["AES256-SHA", "TLSv1/SSLv3", 256, 256],
+ ["EDH-RSA-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168],
+ ["EDH-DSS-DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168],
+ ["DES-CBC3-SHA", "TLSv1/SSLv3", 168, 168],
+ ["DHE-RSA-AES128-SHA", "TLSv1/SSLv3", 128, 128],
+ ["DHE-DSS-AES128-SHA", "TLSv1/SSLv3", 128, 128],
+ ["AES128-SHA", "TLSv1/SSLv3", 128, 128],
+ ["RC4-SHA", "TLSv1/SSLv3", 128, 128],
+ ["RC4-MD5", "TLSv1/SSLv3", 128, 128],
+ ["EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56],
+ ["EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 56, 56],
+ ["DES-CBC-SHA", "TLSv1/SSLv3", 56, 56],
+ ["EXP-EDH-RSA-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56],
+ ["EXP-EDH-DSS-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56],
+ ["EXP-DES-CBC-SHA", "TLSv1/SSLv3", 40, 56],
+ ["EXP-RC2-CBC-MD5", "TLSv1/SSLv3", 40, 128],
+ ["EXP-RC4-MD5", "TLSv1/SSLv3", 40, 128],
+ ]
end
diff --git a/lib/stomp/errors.rb b/lib/stomp/errors.rb
index e9157f5..9430b08 100644
--- a/lib/stomp/errors.rb
+++ b/lib/stomp/errors.rb
@@ -1,139 +1,190 @@
# -*- encoding: utf-8 -*-
module Stomp
+
+ # Module level container for Stomp gem error classes.
module Error
+
+ # InvalidFormat is raised if:
+ # * During frame parsing if a malformed frame is detected.
class InvalidFormat < RuntimeError
def message
"Invalid message - invalid format"
end
end
+ # InvalidServerCommand is raised if:
+ # * An invalid STOMP COMMAND is received from the server.
class InvalidServerCommand < RuntimeError
def message
"Invalid command from server"
end
end
+ # InvalidMessageLength is raised if:
+ # * An invalid message length is detected during a frame read.
class InvalidMessageLength < RuntimeError
def message
"Invalid content length received"
end
end
+ # PacketParsingTimeout is raised if:
+ # * A frame read has started, but does not complete in 5 seconds.
+ # * Use :parse_timeout connect parameter to override the timeout.
class PacketParsingTimeout < RuntimeError
def message
"Packet parsing timeout"
end
end
+ # SocketOpenTimeout is raised if:
+ # * A timeout occurs during a socket open.
class SocketOpenTimeout < RuntimeError
def message
"Socket open timeout"
end
end
+ # NoCurrentConnection is raised if:
+ # * Any method is called when a current connection does not exist.
class NoCurrentConnection < RuntimeError
def message
"no current connection exists"
end
end
-
+
+ # MaxReconnectAttempts is raised if:
+ # * The maximum number of retries has been reached for a reliable connection.
class MaxReconnectAttempts < RuntimeError
def message
"Maximum number of reconnection attempts reached"
end
end
-
+
+ # DuplicateSubscription is raised if:
+ # * A duplicate subscription ID is detected in the current session.
class DuplicateSubscription < RuntimeError
def message
"duplicate subscriptions are disallowed"
end
end
-
+
+ # ProtocolErrorConnect is raised if:
+ # * Incomplete Stomp 1.1 headers are detectd during a connect.
class ProtocolErrorConnect < RuntimeError
def message
"protocol error on CONNECT"
end
end
-
+
+ # UnsupportedProtocolError is raised if:
+ # * No supported Stomp protocol levels are detected during a connect.
class UnsupportedProtocolError < RuntimeError
def message
"unsupported protocol level(s)"
end
end
-
+
+ # InvalidHeartBeatHeaderError is raised if:
+ # * A "heart-beat" header is present, but the values are malformed.
class InvalidHeartBeatHeaderError < RuntimeError
def message
"heart-beat header value is malformed"
end
end
+ # SubscriptionRequiredError is raised if:
+ # * No subscription id is specified for a Stomp 1.1 subscribe.
class SubscriptionRequiredError < RuntimeError
def message
"a valid subscription id header is required"
end
end
+ # UTF8ValidationError is raised if:
+ # * Stomp 1.1 headers are not valid UTF8.
class UTF8ValidationError < RuntimeError
def message
"header is invalid UTF8"
end
end
+ # MessageIDRequiredError is raised if:
+ # * No messageid parameter is specified for ACK or NACK.
class MessageIDRequiredError < RuntimeError
def message
"a valid message id is required for ACK/NACK"
end
end
+ # SSLClientParamsError is raised if:
+ # * Incomplete SSLParams are specified for an SSL connect.
class SSLClientParamsError < RuntimeError
def message
"certificate and key files are both required"
end
end
+ # StompServerError is raised if:
+ # * Invalid (nil) data is received from the Stomp server.
class StompServerError < RuntimeError
def message
"Connected, header read is nil, is this really a Stomp Server?"
end
end
+ # SSLNoKeyFileError is raised if:
+ # * A supplied key file does not exist.
class SSLNoKeyFileError < RuntimeError
def message
"client key file does not exist"
end
end
+ # SSLUnreadableKeyFileError is raised if:
+ # * A supplied key file is not readable.
class SSLUnreadableKeyFileError < RuntimeError
def message
"client key file can not be read"
end
end
+ # SSLNoCertFileError is raised if:
+ # * A supplied SSL cert file does not exist.
class SSLNoCertFileError < RuntimeError
def message
"client cert file does not exist"
end
end
+ # SSLUnreadableCertFileError is raised if:
+ # * A supplied SSL cert file is not readable.
class SSLUnreadableCertFileError < RuntimeError
def message
"client cert file can not be read"
end
end
+ # SSLNoTruststoreFileError is raised if:
+ # * A supplied SSL trust store file does not exist.
class SSLNoTruststoreFileError < RuntimeError
def message
"a client truststore file does not exist"
end
end
+ # SSLUnreadableTruststoreFileError is raised if:
+ # * A supplied SSL trust store file is not readable.
class SSLUnreadableTruststoreFileError < RuntimeError
def message
"a client truststore file can not be read"
end
end
+ # LoggerConnectionError is not raised by the gem. It may be
+ # raised by client logic in callback logger methods to signal
+ # that a connection should not proceed.
class LoggerConnectionError < RuntimeError
end
diff --git a/lib/stomp/ext/hash.rb b/lib/stomp/ext/hash.rb
index c6526c0..9c1c171 100644
--- a/lib/stomp/ext/hash.rb
+++ b/lib/stomp/ext/hash.rb
@@ -1,10 +1,13 @@
# -*- encoding: utf-8 -*-
class ::Hash
+
+ # Returns self with keys uncamelized and converted to symbols.
def uncamelize_and_symbolize_keys
self.uncamelize_and_stringify_keys.symbolize_keys
end
+ # Returns self with keys uncamelized and converted to strings.
def uncamelize_and_stringify_keys
uncamelized = {}
self.each_pair do |key, value|
@@ -15,6 +18,7 @@ class ::Hash
uncamelized
end
+ # Returns self with all keys symbolized.
def symbolize_keys
symbolized = {}
self.each_pair do |key, value|
diff --git a/lib/stomp/message.rb b/lib/stomp/message.rb
index 8cbf112..f9f27eb 100644
--- a/lib/stomp/message.rb
+++ b/lib/stomp/message.rb
@@ -2,39 +2,54 @@
module Stomp
- # Container class for frames, misnamed technically
+ # Message is a container class for frames. Misnamed technically.
class Message
- attr_accessor :command, :headers, :body, :original
- @@allowed_commands = [ Stomp::CMD_CONNECTED, Stomp::CMD_MESSAGE, Stomp::CMD_RECEIPT, Stomp::CMD_ERROR ]
+ public
+ # The COMMAND value.
+ attr_accessor :command
+
+ # The Headers Hash.
+ attr_accessor :headers
+
+ # The message Body.
+ attr_accessor :body
+
+ # The original input(s).
+ attr_accessor :original
+
+ # Commands that are allowed from the wire per the specifications.
+ @@allowed_commands = [ Stomp::CMD_CONNECTED, Stomp::CMD_MESSAGE, Stomp::CMD_RECEIPT, Stomp::CMD_ERROR ]
+
+ # initialize returns a Message from a raw physical frame.
def initialize(frame, protocol11p = false)
- # p [ "00", frame, frame.encoding ]
+ # p [ "00", frame, frame.encoding ]
# Set default empty values
self.command = ''
self.headers = {}
self.body = ''
self.original = frame
return self if is_blank?(frame)
- # Figure out where individual parts of the frame begin and end.
- command_index = frame.index("\n")
- raise Stomp::Error::InvalidFormat, 'command index' unless command_index
- #
- headers_index = frame.index("\n\n", command_index+1)
- raise Stomp::Error::InvalidFormat, 'headers index' unless headers_index
- #
- lastnull_index = frame.rindex("\0")
- raise Stomp::Error::InvalidFormat, 'lastnull index' unless lastnull_index
-
- # Extract working copies of each frame part
- work_command = frame[0..command_index-1]
- raise Stomp::Error::InvalidServerCommand, "invalid command: #{work_command.inspect}" unless @@allowed_commands.include?(work_command)
- #
- work_headers = frame[command_index+1..headers_index-1]
- raise Stomp::Error::InvalidFormat, 'nil headers' unless work_headers
- #
- work_body = frame[headers_index+2..lastnull_index-1]
- raise Stomp::Error::InvalidFormat, 'nil body' unless work_body
+ # Figure out where individual parts of the frame begin and end.
+ command_index = frame.index("\n")
+ raise Stomp::Error::InvalidFormat, 'command index' unless command_index
+ #
+ headers_index = frame.index("\n\n", command_index+1)
+ raise Stomp::Error::InvalidFormat, 'headers index' unless headers_index
+ #
+ lastnull_index = frame.rindex("\0")
+ raise Stomp::Error::InvalidFormat, 'lastnull index' unless lastnull_index
+
+ # Extract working copies of each frame part
+ work_command = frame[0..command_index-1]
+ raise Stomp::Error::InvalidServerCommand, "invalid command: #{work_command.inspect}" unless @@allowed_commands.include?(work_command)
+ #
+ work_headers = frame[command_index+1..headers_index-1]
+ raise Stomp::Error::InvalidFormat, 'nil headers' unless work_headers
+ #
+ work_body = frame[headers_index+2..lastnull_index-1]
+ raise Stomp::Error::InvalidFormat, 'nil body' unless work_body
# Set the frame values
if protocol11p
work_command.force_encoding(Stomp::UTF8) if work_command.respond_to?(:force_encoding)
@@ -42,7 +57,7 @@ module Stomp
self.command = work_command
work_headers.split("\n").map do |value|
parsed_value = value.match /^([\r|\w|-]*):(.*)$/
- raise Stomp::Error::InvalidFormat, 'parsed header value' unless parsed_value
+ raise Stomp::Error::InvalidFormat, 'parsed header value' unless parsed_value
#
pk = parsed_value[1]
pv = parsed_value[2]
@@ -71,7 +86,7 @@ module Stomp
end
body_length = -1
-
+
if self.headers['content-length']
body_length = self.headers['content-length'].to_i
raise Stomp::Error::InvalidMessageLength if work_body.length != body_length
@@ -79,18 +94,23 @@ module Stomp
self.body = work_body[0..body_length]
end
+ # to_s returns a string prepresentation of this Message
def to_s
"<Stomp::Message headers=#{headers.inspect} body='#{body}' command='#{command}' >"
end
+ private
+
+ # is_blank? tests if a data value is nil or empty.
+ def is_blank?(value)
+ value.nil? || (value.respond_to?(:empty?) && value.empty?)
+ end
+
+ # empty? tests if a Message has any blank parts.
def empty?
is_blank?(command) && is_blank?(headers) && is_blank?(body)
end
- private
- def is_blank?(value)
- value.nil? || (value.respond_to?(:empty?) && value.empty?)
- end
end
end
diff --git a/lib/stomp/sslparams.rb b/lib/stomp/sslparams.rb
index 93600e1..98d3f99 100644
--- a/lib/stomp/sslparams.rb
+++ b/lib/stomp/sslparams.rb
@@ -1,72 +1,84 @@
-# -*- encoding: utf-8 -*-
-
-module Stomp
- #
- # == Purpose
- #
- # Parameters for STOMP ssl connections.
- #
- class SSLParams
- # The trust store files. Normally the certificate of the CA that signed
- # the server's certificate. One file name, or a CSV list of file names.
- attr_accessor :ts_files
- # The client certificate file.
- attr_accessor :cert_file
- # The client private key file.
- attr_accessor :key_file
- # The client private key password.
- attr_accessor :key_password
- # SSL Connect Verify Result. The result of the handshake.
- attr_accessor :verify_result
- # The certificate of the connection peer (the server), received during
- # the handshake.
- attr_accessor :peer_cert
- # Optional list of SSL ciphers to be used. In the format documented for
- # Ruby's OpenSSL.
- attr_accessor :ciphers
- # Abcolute command to use Ruby default ciphers
- attr_reader :use_ruby_ciphers
- # Back reference to the OpenSSL::SSL::SSLContext instance, gem sets before connect
- attr_accessor :ctx # Set by the gem during connect, before the callbacks
- # Client wants file existance check now. true/value or false/nil
- attr_reader :fsck #
- #
- def initialize(opts={})
-
- # Server authentication parameters
- @ts_files = opts[:ts_files] # A trust store file, normally a CA's cert
- # or a CSV list of cert file names
-
- # Client authentication parameters
- @cert_file = opts[:cert_file] # Client cert
- @key_file = opts[:key_file] # Client key
- @key_password = opts[:key_password] # Client key password
- #
- raise Stomp::Error::SSLClientParamsError if @cert_file.nil? && !@key_file.nil?
- raise Stomp::Error::SSLClientParamsError if !@cert_file.nil? && @key_file.nil?
- #
- @ciphers = opts[:ciphers]
- @use_ruby_ciphers = opts[:use_ruby_ciphers] ? opts[:use_ruby_ciphers] : false
- #
- if opts[:fsck]
- if @cert_file
- raise Stomp::Error::SSLNoCertFileError if !File::exists?(@cert_file)
- raise Stomp::Error::SSLUnreadableCertFileError if !File::readable?(@cert_file)
- end
- if @key_file
- raise Stomp::Error::SSLNoKeyFileError if !File::exists?(@key_file)
- raise Stomp::Error::SSLUnreadableKeyFileError if !File::readable?(@key_file)
- end
- if @ts_files
- tsa = @ts_files.split(",")
- tsa.each do |fn|
- raise Stomp::Error::SSLNoTruststoreFileError if !File::exists?(fn)
- raise Stomp::Error::SSLUnreadableTruststoreFileError if !File::readable?(fn)
- end
- end
- end
- end
- end # of class SSLParams
-
-end # of module Stomp
+# -*- encoding: utf-8 -*-
+
+module Stomp
+ #
+ # == Purpose
+ #
+ # Parameters for STOMP ssl connections.
+ #
+ class SSLParams
+
+ # The trust store files. Normally the certificate of the CA that signed
+ # the server's certificate. One file name, or a CSV list of file names.
+ attr_accessor :ts_files
+
+ # The client certificate file.
+ attr_accessor :cert_file
+
+ # The client private key file.
+ attr_accessor :key_file
+
+ # The client private key password.
+ attr_accessor :key_password
+
+ # SSL Connect Verify Result. The result of the handshake.
+ attr_accessor :verify_result
+
+ # The certificate of the connection peer (the server), received during
+ # the handshake.
+ attr_accessor :peer_cert
+
+ # Optional list of SSL ciphers to be used. In the format documented for
+ # Ruby's OpenSSL.
+ attr_accessor :ciphers
+
+ # Absolute command to use Ruby default ciphers.
+ attr_reader :use_ruby_ciphers
+
+ # Back reference to the OpenSSL::SSL::SSLContext instance, gem sets before connect.
+ attr_accessor :ctx # Set by the gem during connect, before the callbacks
+
+ # Client wants file existance check on initialize. true/value or false/nil.
+ attr_reader :fsck #
+
+ # initialize returns a valid set of SSLParams or raises an error.
+ def initialize(opts={})
+
+ # Server authentication parameters
+ @ts_files = opts[:ts_files] # A trust store file, normally a CA's cert
+ # or a CSV list of cert file names
+
+ # Client authentication parameters
+ @cert_file = opts[:cert_file] # Client cert
+ @key_file = opts[:key_file] # Client key
+ @key_password = opts[:key_password] # Client key password
+ #
+ raise Stomp::Error::SSLClientParamsError if @cert_file.nil? && !@key_file.nil?
+ raise Stomp::Error::SSLClientParamsError if !@cert_file.nil? && @key_file.nil?
+ #
+ @ciphers = opts[:ciphers]
+ @use_ruby_ciphers = opts[:use_ruby_ciphers] ? opts[:use_ruby_ciphers] : false
+ #
+ if opts[:fsck]
+ if @cert_file
+ raise Stomp::Error::SSLNoCertFileError if !File::exists?(@cert_file)
+ raise Stomp::Error::SSLUnreadableCertFileError if !File::readable?(@cert_file)
+ end
+ if @key_file
+ raise Stomp::Error::SSLNoKeyFileError if !File::exists?(@key_file)
+ raise Stomp::Error::SSLUnreadableKeyFileError if !File::readable?(@key_file)
+ end
+ if @ts_files
+ tsa = @ts_files.split(",")
+ tsa.each do |fn|
+ raise Stomp::Error::SSLNoTruststoreFileError if !File::exists?(fn)
+ raise Stomp::Error::SSLUnreadableTruststoreFileError if !File::readable?(fn)
+ end
+ end
+ end
+ end
+
+ end # of class SSLParams
+
+end # of module Stomp
diff --git a/lib/stomp/version.rb b/lib/stomp/version.rb
index 7d11951..f7ac410 100644
--- a/lib/stomp/version.rb
+++ b/lib/stomp/version.rb
@@ -1,10 +1,12 @@
# -*- encoding: utf-8 -*-
module Stomp
+
+ # Define the gem version.
module Version #:nodoc: all
MAJOR = 1
MINOR = 2
- PATCH = 4
+ PATCH = 5
STRING = "#{MAJOR}.#{MINOR}.#{PATCH}"
end
end
diff --git a/metadata.yml b/metadata.yml
index c10b6a0..70d98a1 100644
--- a/metadata.yml
+++ b/metadata.yml
@@ -1,13 +1,13 @@
--- !ruby/object:Gem::Specification
name: stomp
version: !ruby/object:Gem::Version
- hash: 23
+ hash: 21
prerelease: false
segments:
- 1
- 2
- - 4
- version: 1.2.4
+ - 5
+ version: 1.2.5
platform: ruby
authors:
- Brian McCallister
@@ -18,7 +18,7 @@ autorequire:
bindir: bin
cert_chain: []
-date: 2012-06-25 00:00:00 -04:00
+date: 2012-08-04 00:00:00 -04:00
default_executable:
dependencies:
- !ruby/object:Gem::Dependency
@@ -48,8 +48,58 @@ executables:
extensions: []
extra_rdoc_files:
+- CHANGELOG.rdoc
- LICENSE
- README.rdoc
+- examples/client11_ex1.rb
+- examples/client11_putget1.rb
+- examples/conn11_ex1.rb
+- examples/conn11_ex2.rb
+- examples/conn11_hb1.rb
+- examples/consumer.rb
+- examples/get11conn_ex1.rb
+- examples/get11conn_ex2.rb
+- examples/logexamp.rb
+- examples/logexamp_ssl.rb
+- examples/publisher.rb
+- examples/put11conn_ex1.rb
+- examples/putget11_rh1.rb
+- examples/slogger.rb
+- examples/ssl_uc1.rb
+- examples/ssl_uc1_ciphers.rb
+- examples/ssl_uc2.rb
+- examples/ssl_uc2_ciphers.rb
+- examples/ssl_uc3.rb
+- examples/ssl_uc3_ciphers.rb
+- examples/ssl_uc4.rb
+- examples/ssl_uc4_ciphers.rb
+- examples/ssl_ucx_default_ciphers.rb
+- examples/stomp11_common.rb
+- examples/topic_consumer.rb
+- examples/topic_publisher.rb
+- lib/client/utils.rb
+- lib/connection/heartbeats.rb
+- lib/connection/netio.rb
+- lib/connection/utf8.rb
+- lib/connection/utils.rb
+- lib/stomp.rb
+- lib/stomp/client.rb
+- lib/stomp/codec.rb
+- lib/stomp/connection.rb
+- lib/stomp/constants.rb
+- lib/stomp/errors.rb
+- lib/stomp/ext/hash.rb
+- lib/stomp/message.rb
+- lib/stomp/sslparams.rb
+- lib/stomp/version.rb
+- test/test_client.rb
+- test/test_codec.rb
+- test/test_connection.rb
+- test/test_connection1p.rb
+- test/test_helper.rb
+- test/test_message.rb
+- test/test_ssl.rb
+- test/tlogger.rb
files:
- CHANGELOG.rdoc
- LICENSE
@@ -83,6 +133,11 @@ files:
- examples/stomp11_common.rb
- examples/topic_consumer.rb
- examples/topic_publisher.rb
+- lib/client/utils.rb
+- lib/connection/heartbeats.rb
+- lib/connection/netio.rb
+- lib/connection/utf8.rb
+- lib/connection/utils.rb
- lib/stomp.rb
- lib/stomp/client.rb
- lib/stomp/codec.rb
diff --git a/stomp.gemspec b/stomp.gemspec
index cf77594..56b8fb8 100644
--- a/stomp.gemspec
+++ b/stomp.gemspec
@@ -5,17 +5,67 @@
Gem::Specification.new do |s|
s.name = %q{stomp}
- s.version = "1.2.4"
+ s.version = "1.2.5"
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Brian McCallister", "Marius Mathiesen", "Thiago Morello", "Guy M. Allard"]
- s.date = %q{2012-06-25}
+ s.date = %q{2012-08-04}
s.description = %q{Ruby client for the Stomp messaging protocol. Note that this gem is no longer supported on rubyforge.}
s.email = ["brianm at apache.org", "marius at stones.com", "morellon at gmail.com", "allard.guy.m at gmail.com"]
s.executables = ["catstomp", "stompcat"]
s.extra_rdoc_files = [
+ "CHANGELOG.rdoc",
"LICENSE",
- "README.rdoc"
+ "README.rdoc",
+ "examples/client11_ex1.rb",
+ "examples/client11_putget1.rb",
+ "examples/conn11_ex1.rb",
+ "examples/conn11_ex2.rb",
+ "examples/conn11_hb1.rb",
+ "examples/consumer.rb",
+ "examples/get11conn_ex1.rb",
+ "examples/get11conn_ex2.rb",
+ "examples/logexamp.rb",
+ "examples/logexamp_ssl.rb",
+ "examples/publisher.rb",
+ "examples/put11conn_ex1.rb",
+ "examples/putget11_rh1.rb",
+ "examples/slogger.rb",
+ "examples/ssl_uc1.rb",
+ "examples/ssl_uc1_ciphers.rb",
+ "examples/ssl_uc2.rb",
+ "examples/ssl_uc2_ciphers.rb",
+ "examples/ssl_uc3.rb",
+ "examples/ssl_uc3_ciphers.rb",
+ "examples/ssl_uc4.rb",
+ "examples/ssl_uc4_ciphers.rb",
+ "examples/ssl_ucx_default_ciphers.rb",
+ "examples/stomp11_common.rb",
+ "examples/topic_consumer.rb",
+ "examples/topic_publisher.rb",
+ "lib/client/utils.rb",
+ "lib/connection/heartbeats.rb",
+ "lib/connection/netio.rb",
+ "lib/connection/utf8.rb",
+ "lib/connection/utils.rb",
+ "lib/stomp.rb",
+ "lib/stomp/client.rb",
+ "lib/stomp/codec.rb",
+ "lib/stomp/connection.rb",
+ "lib/stomp/constants.rb",
+ "lib/stomp/errors.rb",
+ "lib/stomp/ext/hash.rb",
+ "lib/stomp/message.rb",
+ "lib/stomp/sslparams.rb",
+ "lib/stomp/version.rb",
+ "test/test_client.rb",
+ "test/test_codec.rb",
+ "test/test_connection.rb",
+ "test/test_connection1p.rb",
+ "test/test_helper.rb",
+ "test/test_message.rb",
+ "test/test_ssl.rb",
+ "test/tlogger.rb"
]
s.files = [
"CHANGELOG.rdoc",
@@ -50,6 +100,11 @@ Gem::Specification.new do |s|
"examples/stomp11_common.rb",
"examples/topic_consumer.rb",
"examples/topic_publisher.rb",
+ "lib/client/utils.rb",
+ "lib/connection/heartbeats.rb",
+ "lib/connection/netio.rb",
+ "lib/connection/utf8.rb",
+ "lib/connection/utils.rb",
"lib/stomp.rb",
"lib/stomp/client.rb",
"lib/stomp/codec.rb",
diff --git a/test/test_client.rb b/test/test_client.rb
index 71cbbbb..3eb1096 100644
--- a/test/test_client.rb
+++ b/test/test_client.rb
@@ -4,6 +4,11 @@ $:.unshift(File.dirname(__FILE__))
require 'test_helper'
+=begin
+
+ Main class for testing Stomp::Client instances.
+
+=end
class TestClient < Test::Unit::TestCase
include TestBase
@@ -18,12 +23,14 @@ class TestClient < Test::Unit::TestCase
@client.close if @client.open? # allow tests to close
end
+ # Test poll works.
def test_poll_async
# If the test 'hangs' here, Connection#poll is broken.
m = @client.poll
assert m.nil?
end
+ # Test ACKs.
def test_ack_api_works
@client.publish make_destination, message_text, {:suppress_content_length => true}
@@ -41,6 +48,7 @@ class TestClient < Test::Unit::TestCase
assert_not_nil receipt.headers['receipt-id']
end unless ENV['STOMP_RABBIT']
+ # Test Client subscribe
def test_asynch_subscribe
received = false
@client.subscribe(make_destination) {|msg| received = msg}
@@ -50,6 +58,7 @@ class TestClient < Test::Unit::TestCase
assert_equal message_text, received.body
end
+ # Test not ACKing messages.
def test_noack
@client.publish make_destination, message_text
@@ -71,17 +80,19 @@ class TestClient < Test::Unit::TestCase
assert_equal received.headers['message-id'], received2.headers['message-id'] unless ENV['STOMP_RABBIT']
end unless RUBY_ENGINE =~ /jruby/
+ # Test obtaining a RECEIPT via a listener.
def test_receipts
receipt = false
@client.publish(make_destination, message_text) {|r| receipt = r}
sleep 0.1 until receipt
-
+ assert_equal receipt.command, Stomp::CMD_RECEIPT
message = nil
@client.subscribe(make_destination) {|m| message = m}
sleep 0.1 until message
assert_equal message_text, message.body
end
+ # Test requesting a receipt on disconnect.
def test_disconnect_receipt
@client.close :receipt => "xyz789"
assert_nothing_raised {
@@ -91,6 +102,7 @@ class TestClient < Test::Unit::TestCase
}
end
+ # Test publish and immediate subscribe.
def test_publish_then_sub
@client.publish make_destination, message_text
message = nil
@@ -100,12 +112,14 @@ class TestClient < Test::Unit::TestCase
assert_equal message_text, message.body
end
+ # Test that Client subscribe requires a block.
def test_subscribe_requires_block
assert_raise(RuntimeError) do
@client.subscribe make_destination
end
end unless RUBY_ENGINE =~ /jruby/
+ # Test transaction publish.
def test_transactional_publish
@client.begin 'tx1'
@client.publish make_destination, message_text, :transaction => 'tx1'
@@ -118,6 +132,7 @@ class TestClient < Test::Unit::TestCase
assert_equal message_text, message.body
end
+ # Test transaction publish and abort.
def test_transaction_publish_then_rollback
@client.begin 'tx1'
@client.publish make_destination, "first_message", :transaction => 'tx1'
@@ -133,6 +148,7 @@ class TestClient < Test::Unit::TestCase
assert_equal "second_message", message.body
end unless RUBY_ENGINE =~ /jruby/
+ # Test transaction publish and abort, receive with new client.
def test_transaction_ack_rollback_with_new_client
@client.publish make_destination, message_text
@@ -185,6 +201,7 @@ class TestClient < Test::Unit::TestCase
}
end
+ # Test that subscription destinations must be unique for a Client.
def test_raise_on_multiple_subscriptions_to_same_make_destination
subscribe_dest = make_destination
@client.subscribe(subscribe_dest) {|m| nil }
@@ -193,6 +210,7 @@ class TestClient < Test::Unit::TestCase
end
end
+ # Test that subscription IDs must be unique for a Client.
def test_raise_on_multiple_subscriptions_to_same_id
subscribe_dest = make_destination
@client.subscribe(subscribe_dest, {'id' => 'myid'}) {|m| nil }
@@ -201,6 +219,7 @@ class TestClient < Test::Unit::TestCase
end
end
+ # Test that subscription IDs must be unique for a Client, mixed id specification.
def test_raise_on_multiple_subscriptions_to_same_id_mixed
subscribe_dest = make_destination
@client.subscribe(subscribe_dest, {'id' => 'myid'}) {|m| nil }
@@ -209,6 +228,7 @@ class TestClient < Test::Unit::TestCase
end
end
+ # Test wildcard subscribe. Primarily for AMQ.
def test_asterisk_wildcard_subscribe
queue_base_name = make_destination
queue1 = queue_base_name + ".a"
@@ -239,6 +259,7 @@ class TestClient < Test::Unit::TestCase
end unless ENV['STOMP_NOWILD']
+ # Test wildcard subscribe with >. Primarily for AMQ.
def test_greater_than_wildcard_subscribe
queue_base_name = make_destination + "."
queue1 = queue_base_name + "foo.a"
@@ -272,6 +293,7 @@ class TestClient < Test::Unit::TestCase
assert results.all?{|a| a == true }
end unless ENV['STOMP_NOWILD'] || ENV['STOMP_DOTQUEUE']
+ # Test transaction with client side redilivery.
def test_transaction_with_client_side_redelivery
@client.publish make_destination, message_text
@@ -310,10 +332,12 @@ class TestClient < Test::Unit::TestCase
@client.commit 'tx2'
end
+ # Test that a connection frame is received.
def test_connection_frame
assert_not_nil @client.connection_frame
end unless RUBY_ENGINE =~ /jruby/
+ # Test basic unsubscribe.
def test_unsubscribe
message = nil
dest = make_destination
@@ -353,6 +377,7 @@ class TestClient < Test::Unit::TestCase
assert_equal message.headers['message-id'], message_copy.headers['message-id'], "header check" unless ENV['STOMP_RABBIT']
end
+ # Test subscribe from a worker thread.
def test_thread_one_subscribe
msg = nil
dest = make_destination
@@ -374,6 +399,7 @@ class TestClient < Test::Unit::TestCase
assert_not_nil msg
end unless RUBY_ENGINE =~ /jruby/
+ # Test subscribe from multiple worker threads.
def test_thread_multi_subscribe
#
lock = Mutex.new
@@ -424,6 +450,7 @@ class TestClient < Test::Unit::TestCase
assert_equal @max_msgs, msg_ctr
end
+ # Test that methods detect no client connection is present.
def test_closed_checks_client
@client.close
#
diff --git a/test/test_codec.rb b/test/test_codec.rb
index 5124639..79ffa46 100644
--- a/test/test_codec.rb
+++ b/test/test_codec.rb
@@ -4,6 +4,11 @@ $:.unshift(File.dirname(__FILE__))
require 'test_helper'
+=begin
+
+ Main class for testing Stomp::HeadreCodec methods.
+
+=end
class TestCodec < Test::Unit::TestCase
include TestBase
@@ -18,6 +23,7 @@ class TestCodec < Test::Unit::TestCase
@conn.disconnect if @conn.open? # allow tests to disconnect
end
+ # Test that the codec does nothing to strings that do not need encoding.
def test_1000_check_notneeded
test_data = [
"a",
@@ -39,7 +45,7 @@ class TestCodec < Test::Unit::TestCase
end
end
- #
+ # Test the basic encoding / decoding requirements.
def test_1010_basic_encode_decode
test_data = [
[ "\\\\", "\\" ],
@@ -62,7 +68,7 @@ class TestCodec < Test::Unit::TestCase
end
end
- #
+ # Test more complex strings with the codec.
def test_1020_fancier
test_data = [
[ "a\\\\b", "a\\b" ],
diff --git a/test/test_connection.rb b/test/test_connection.rb
index 554ab0a..e10cb01 100644
--- a/test/test_connection.rb
+++ b/test/test_connection.rb
@@ -4,6 +4,11 @@ $:.unshift(File.dirname(__FILE__))
require 'test_helper'
+=begin
+
+ Main class for testing Stomp::Connection instances.
+
+=end
class TestConnection < Test::Unit::TestCase
include TestBase
@@ -18,10 +23,12 @@ class TestConnection < Test::Unit::TestCase
@conn.disconnect if @conn.open? # allow tests to disconnect
end
+ # Test basic connection creation.
def test_connection_exists
assert_not_nil @conn
end
+ # Test asynchronous polling.
def test_poll_async
@conn.subscribe("/queue/do.not.put.messages.on.this.queue", :id => "a.no.messages.queue")
# If the test 'hangs' here, Connection#poll is broken.
@@ -29,6 +36,7 @@ class TestConnection < Test::Unit::TestCase
assert m.nil?
end
+ # Test suppression of content length header.
def test_no_length
conn_subscribe make_destination
#
@@ -47,6 +55,7 @@ class TestConnection < Test::Unit::TestCase
end
end unless ENV['STOMP_RABBIT']
+ # Test direct / explicit receive.
def test_explicit_receive
conn_subscribe make_destination
@conn.publish make_destination, "test_stomp#test_explicit_receive"
@@ -54,12 +63,14 @@ class TestConnection < Test::Unit::TestCase
assert_equal "test_stomp#test_explicit_receive", msg.body
end
+ # Test asking for a receipt.
def test_receipt
conn_subscribe make_destination, :receipt => "abc"
msg = @conn.receive
assert_equal "abc", msg.headers['receipt-id']
end
+ # Test asking for a receipt on disconnect.
def test_disconnect_receipt
@conn.disconnect :receipt => "abc123"
assert_nothing_raised {
@@ -69,6 +80,7 @@ class TestConnection < Test::Unit::TestCase
}
end
+ # Test ACKs using symbols for header keys.
def test_client_ack_with_symbol
if @conn.protocol == Stomp::SPL_10
@conn.subscribe make_destination, :ack => :client
@@ -87,6 +99,7 @@ class TestConnection < Test::Unit::TestCase
}
end
+ # Test a message with 0x00 embedded in the body.
def test_embedded_null
conn_subscribe make_destination
@conn.publish make_destination, "a\0"
@@ -94,18 +107,21 @@ class TestConnection < Test::Unit::TestCase
assert_equal "a\0" , msg.body
end
+ # Test connection open checking.
def test_connection_open?
assert_equal true , @conn.open?
@conn.disconnect
assert_equal false, @conn.open?
end
+ # Test connection closed checking.
def test_connection_closed?
assert_equal false, @conn.closed?
@conn.disconnect
assert_equal true, @conn.closed?
end
+ # Test that methods detect a closed connection.
def test_closed_checks_conn
@conn.disconnect
#
@@ -154,6 +170,7 @@ class TestConnection < Test::Unit::TestCase
end
end
+ # Test that we receive a Stomp::Message.
def test_response_is_instance_of_message_class
conn_subscribe make_destination
@conn.publish make_destination, "a\0"
@@ -161,6 +178,7 @@ class TestConnection < Test::Unit::TestCase
assert_instance_of Stomp::Message , msg
end
+ # Test converting a Message to a string.
def test_message_to_s
conn_subscribe make_destination
@conn.publish make_destination, "a\0"
@@ -168,10 +186,12 @@ class TestConnection < Test::Unit::TestCase
assert_match /^<Stomp::Message headers=/ , msg.to_s
end
+ # Test that a connection frame is present.
def test_connection_frame
assert_not_nil @conn.connection_frame
end
+ # Test messages with multiple line ends.
def test_messages_with_multipleLine_ends
conn_subscribe make_destination
@conn.publish make_destination, "a\n\n"
@@ -184,6 +204,7 @@ class TestConnection < Test::Unit::TestCase
assert_equal "b\n\na\n\n", msg_b.body
end
+ # Test publishing multiple messages.
def test_publish_two_messages
conn_subscribe make_destination
@conn.publish make_destination, "a\0"
@@ -211,6 +232,7 @@ class TestConnection < Test::Unit::TestCase
assert_equal message, received.body
end
+ # Test polling with a single thread.
def test_thread_poll_one
received = nil
max_sleep = (RUBY_VERSION =~ /1\.8/) ? 10 : 1
@@ -231,6 +253,7 @@ class TestConnection < Test::Unit::TestCase
assert_equal message, received.body
end
+ # Test receiving with multiple threads.
def test_multi_thread_receive
lock = Mutex.new
msg_ctr = 0
@@ -268,6 +291,7 @@ class TestConnection < Test::Unit::TestCase
assert_equal @max_msgs, msg_ctr
end unless RUBY_ENGINE =~ /jruby/
+ # Test polling with multiple threads.
def test_multi_thread_poll
#
lock = Mutex.new
@@ -311,6 +335,7 @@ class TestConnection < Test::Unit::TestCase
assert_equal @max_msgs, msg_ctr
end unless RUBY_ENGINE =~ /jruby/
+ # Test using a nil body.
def test_nil_body
dest = make_destination
assert_nothing_raised {
@@ -321,6 +346,7 @@ class TestConnection < Test::Unit::TestCase
assert_equal "", msg.body
end
+ # Test transaction message sequencing.
def test_transaction
conn_subscribe make_destination
@@ -337,6 +363,7 @@ class TestConnection < Test::Unit::TestCase
assert_equal "txn message", msg.body
end
+ # Test duplicate subscriptions.
def test_duplicate_subscription
@conn.disconnect # not reliable
@conn = Stomp::Connection.open(user, passcode, host, port, true) # reliable
@@ -348,6 +375,7 @@ class TestConnection < Test::Unit::TestCase
end
end
+ # Test nil 1.1 connection parameters.
def test_nil_connparms
@conn.disconnect
#
@@ -356,6 +384,7 @@ class TestConnection < Test::Unit::TestCase
end
end
+ # Basic NAK test.
def test_nack11p_0010
if @conn.protocol == Stomp::SPL_10
assert_raise Stomp::Error::UnsupportedProtocolError do
diff --git a/test/test_connection1p.rb b/test/test_connection1p.rb
index edf371e..d0c4287 100644
--- a/test/test_connection1p.rb
+++ b/test/test_connection1p.rb
@@ -4,6 +4,11 @@ $:.unshift(File.dirname(__FILE__))
require 'test_helper'
+=begin
+
+ Main class for testing Stomp::Connection instances, protocol level 1.1+.
+
+=end
class TestConnection1P < Test::Unit::TestCase
include TestBase
@@ -14,11 +19,13 @@ class TestConnection1P < Test::Unit::TestCase
def teardown
@conn.disconnect if @conn.open? # allow tests to disconnect
end
- #
+
+ # Test basic connection open.
def test_conn_1p_0000
assert @conn.open?
end
- #
+
+ # Test missing connect headers.
def test_conn_1p_0010
#
cha = {:host => "localhost"}
@@ -31,7 +38,8 @@ class TestConnection1P < Test::Unit::TestCase
conn = Stomp::Connection.open(user, passcode, host, port, false, 5, chb)
end
end
- #
+
+ # Test requesting only a 1.0 connection.
def test_conn_1p_0020
#
cha = {:host => "localhost", "accept-version" => "1.0"}
@@ -43,7 +51,8 @@ class TestConnection1P < Test::Unit::TestCase
end
assert_equal conn.protocol, Stomp::SPL_10
end
- #
+
+ # Test requesting only a 1.1 connection.
def test_conn_1p_0030
#
cha = {:host => "localhost", "accept-version" => "1.1"}
@@ -55,7 +64,8 @@ class TestConnection1P < Test::Unit::TestCase
end
assert_equal conn.protocol, Stomp::SPL_11
end
- #
+
+ # Test basic request for no heartbeats.
def test_conn_1p_0040
#
cha = {:host => "localhost", "accept-version" => "1.1"}
@@ -68,8 +78,8 @@ class TestConnection1P < Test::Unit::TestCase
end
assert_equal conn.protocol, Stomp::SPL_11
end
- #
+ # Test malformed heartbeat header.
def test_conn_1p_0050
#
cha = {:host => "localhost", "accept-version" => "1.1"}
@@ -80,7 +90,8 @@ class TestConnection1P < Test::Unit::TestCase
conn = Stomp::Connection.open(user, passcode, host, port, false, 5, cha)
end
end
- #
+
+ # Test malformed heartbeat header.
def test_conn_11h_0060
#
cha = {:host => "localhost", "accept-version" => "1.1"}
@@ -91,7 +102,8 @@ class TestConnection1P < Test::Unit::TestCase
conn = Stomp::Connection.open(user, passcode, host, port, false, 5, cha)
end
end
- #
+
+ # Test a valid heartbeat header.
def test_conn_1p_0070
#
cha = {:host => "localhost", "accept-version" => "1.1"}
@@ -106,7 +118,7 @@ class TestConnection1P < Test::Unit::TestCase
assert conn.hbrecv_interval > 0
end
- #
+ # Test only sending heartbeats.
def test_conn_1p_0080
#
cha = {:host => "localhost", "accept-version" => "1.1"}
@@ -124,7 +136,7 @@ class TestConnection1P < Test::Unit::TestCase
hb_asserts_send(conn)
end if ENV['STOMP_HB11LONG']
- #
+ # Test only receiving heartbeats.
def test_conn_1p_0090
#
cha = {:host => "localhost", "accept-version" => "1.1"}
@@ -143,7 +155,7 @@ class TestConnection1P < Test::Unit::TestCase
hb_asserts_recv(conn)
end if ENV['STOMP_HB11LONG']
- #
+ # Test sending and receiving heartbeats.
def test_conn_1p_0100
#
cha = {:host => "localhost", "accept-version" => "1.1"}
@@ -162,7 +174,7 @@ class TestConnection1P < Test::Unit::TestCase
hb_asserts_both(conn)
end if ENV['STOMP_HB11LONG']
- #
+ # Test valid UTF8 data.
def test_conn_1p_0110
#
cha = {:host => "localhost", "accept-version" => "1.1"}
@@ -193,7 +205,7 @@ class TestConnection1P < Test::Unit::TestCase
conn.disconnect
end
- #
+ # Test invalid UTF8 data.
def test_conn_1p_0120
#
cha = {:host => "localhost", "accept-version" => "1.1"}
@@ -230,6 +242,8 @@ class TestConnection1P < Test::Unit::TestCase
# Repeated headers test. Currently:
# - Apollo emits repeated headers for a 1.1 connection only
# - RabbitMQ does not emit repeated headers under any circumstances
+ # - AMQ 5.6 does not emit repeated headers under any circumstances
+ # Pure luck that this runs against AMQ at present.
def test_conn_1p_0120
dest = make_destination
msg = "payload: #{Time.now.to_f}"
@@ -253,6 +267,7 @@ class TestConnection1P < Test::Unit::TestCase
@conn.unsubscribe dest, :id => sid
end
+ # Test frozen headers.
def test_conn_1p_0120
dest = make_destination
sid = @conn.uuid()
@@ -262,7 +277,7 @@ class TestConnection1P < Test::Unit::TestCase
}
end
- #
+ # Test heartbeats with send and receive.
def test_conn_1p_0130
#
cha = {:host => "localhost", "accept-version" => "1.1"}
@@ -281,7 +296,7 @@ class TestConnection1P < Test::Unit::TestCase
hb_asserts_both(conn)
end if ENV['STOMP_HB11LONG']
- #
+ # Test heartbeats with send and receive.
def test_conn_1p_0130
#
cha = {:host => "localhost", "accept-version" => "1.1"}
@@ -300,7 +315,7 @@ class TestConnection1P < Test::Unit::TestCase
hb_asserts_both(conn)
end if ENV['STOMP_HB11LONG']
- #
+ # Test heartbeats with send and receive.
def test_conn_1p_0140
#
cha = {:host => "localhost", "accept-version" => "1.1"}
diff --git a/test/test_helper.rb b/test/test_helper.rb
index 407f66a..987fbb7 100644
--- a/test/test_helper.rb
+++ b/test/test_helper.rb
@@ -13,30 +13,43 @@ rescue NameError => ne
RUBY_ENGINE = "unknown"
end
-# Helper routines
+=begin
+
+ Test helper methods.
+
+=end
module TestBase
+
+ # Get user
def user
ENV['STOMP_USER'] || "guest"
end
+
+ # Gete passcode
def passcode
ENV['STOMP_PASSCODE'] || "guest"
end
+
# Get host
def host
ENV['STOMP_HOST'] || "localhost"
end
+
# Get port
def port
(ENV['STOMP_PORT'] || 61613).to_i
end
+
# Get SSL port
def ssl_port
(ENV['STOMP_SSLPORT'] || 61612).to_i
end
+
# Helper for minitest on 1.9
def caller_method_name
parse_caller(caller(2).first).last
end
+
# Helper for minitest on 1.9
def parse_caller(at)
if /^(.+?):(\d+)(?::in `(.*)')?/ =~ at
@@ -48,12 +61,14 @@ module TestBase
end
end
+ # Get a Stomp Connection.
def get_connection()
ch = get_conn_headers()
conn = Stomp::Connection.open(user, passcode, host, port, false, 5, ch)
conn
end
+ # Get a Stomp SSL Connection.
def get_ssl_connection()
ch = get_conn_headers()
ssl_params = Stomp::SSLParams.new # S/B safe for all Ruby versions tested
@@ -66,6 +81,7 @@ module TestBase
conn
end
+ # Get a Stomp Client.
def get_client()
hash = { :hosts => [
{:login => user, :passcode => passcode, :host => host, :port => port},
@@ -77,6 +93,7 @@ module TestBase
client
end
+ # Get a connection headers hash.
def get_conn_headers()
ch = {}
if ENV['STOMP_TEST11']
@@ -92,6 +109,7 @@ module TestBase
ch
end
+ # Subscribe to a destination.
def conn_subscribe(dest, headers = {})
if @conn.protocol >= Stomp::SPL_11
headers[:id] = @conn.uuid() unless headers[:id]
@@ -99,8 +117,7 @@ module TestBase
@conn.subscribe dest, headers
end
- # Test helper methods
-
+ # Get a dynamic destination name.
def make_destination
name = caller_method_name unless name
qname = ENV['STOMP_DOTQUEUE'] ? "/queue/test.ruby.stomp." + name : "/queue/test/ruby/stomp/" + name
diff --git a/test/test_message.rb b/test/test_message.rb
index a26a8b5..6eeb6f8 100644
--- a/test/test_message.rb
+++ b/test/test_message.rb
@@ -11,7 +11,12 @@ $:.unshift(File.dirname(__FILE__))
# Test Ruby 1.8 with $KCODE='U'
#
require 'test_helper'
-#
+
+=begin
+
+ Main class for testing Stomp::Message.
+
+=end
class TestMessage < Test::Unit::TestCase
include TestBase
#
@@ -87,7 +92,7 @@ class TestMessage < Test::Unit::TestCase
end
end
- #
+ # Test various valid and invalid frames.
def test_0040_msg_create
#
assert_raise(Stomp::Error::InvalidFormat) {
@@ -132,7 +137,7 @@ class TestMessage < Test::Unit::TestCase
end
- # Multiple headers with the same key
+ # Test multiple headers with the same key
def test_0050_mh_msg_create
aframe = bframe = nil
assert_nothing_raised {
diff --git a/test/test_ssl.rb b/test/test_ssl.rb
index 6992f52..c541a59 100644
--- a/test/test_ssl.rb
+++ b/test/test_ssl.rb
@@ -4,6 +4,11 @@ $:.unshift(File.dirname(__FILE__))
require 'test_helper'
+=begin
+
+ Main class for testing Stomp::SSLParams.
+
+=end
class TestSSL < Test::Unit::TestCase
include TestBase
@@ -19,7 +24,7 @@ class TestSSL < Test::Unit::TestCase
assert @conn.open?
end
- #
+ # Test SSLParams basic.
def test_ssl_0010_parms
ssl_params = Stomp::SSLParams.new
assert ssl_params.ts_files.nil?
@@ -28,7 +33,7 @@ class TestSSL < Test::Unit::TestCase
assert ssl_params.fsck.nil?
end
- #
+ # Test using correct parameters.
def test_ssl_0020_noraise
assert_nothing_raised {
ssl_parms = Stomp::SSLParams.new(:cert_file => "dummy1", :key_file => "dummy2")
@@ -41,7 +46,8 @@ class TestSSL < Test::Unit::TestCase
:cert_file => "dummy1", :key_file => "dummy2")
}
end
- #
+
+ # Test using incorrect / incomplete parameters.
def test_ssl_0030_raise
assert_raise(Stomp::Error::SSLClientParamsError) {
ssl_parms = Stomp::SSLParams.new(:cert_file => "dummy1")
@@ -51,7 +57,7 @@ class TestSSL < Test::Unit::TestCase
}
end
- #
+ # Test that :fsck works.
def test_ssl_0040_fsck
assert_raise(Stomp::Error::SSLNoCertFileError) {
ssl_parms = Stomp::SSLParams.new(:cert_file => "dummy1",
diff --git a/test/tlogger.rb b/test/tlogger.rb
index c44a8d1..99295fc 100644
--- a/test/tlogger.rb
+++ b/test/tlogger.rb
@@ -1,22 +1,22 @@
# -*- encoding: utf-8 -*-
+require 'logger' # use the standard Ruby logger .....
+
=begin
-Callback logger for tests.
+Callback logger for Stomp 1.1 heartbeat tests.
=end
-
-require 'logger' # use the standard Ruby logger .....
-
class Tlogger
- #
+
+ # Initialize a callback logger class.
def initialize(init_parms = nil)
@log = Logger::new(STDOUT) # User preference
@log.level = Logger::DEBUG # User preference
@log.info("Logger initialization complete.")
end
- # Log connecting events
+ # Log connecting events.
def on_connecting(parms)
begin
@log.debug "Connecting: #{info(parms)}"
@@ -25,7 +25,7 @@ class Tlogger
end
end
- # Log connected events
+ # Log connected events.
def on_connected(parms)
begin
@log.debug "Connected: #{info(parms)}"
@@ -34,7 +34,7 @@ class Tlogger
end
end
- # Log connectfail events
+ # Log connectfail events.
def on_connectfail(parms)
begin
@log.debug "Connect Fail #{info(parms)}"
@@ -43,7 +43,7 @@ class Tlogger
end
end
- # Log disconnect events
+ # Log disconnect events.
def on_disconnect(parms)
begin
@log.debug "Disconnected #{info(parms)}"
@@ -52,7 +52,7 @@ class Tlogger
end
end
- # Log miscellaneous errors
+ # Log miscellaneous errors.
def on_miscerr(parms, errstr)
begin
@log.debug "Miscellaneous Error #{info(parms)}"
@@ -62,7 +62,7 @@ class Tlogger
end
end
- # Subscribe
+ # Log subscribes.
def on_subscribe(parms, headers)
begin
@log.debug "Subscribe Parms #{info(parms)}"
@@ -72,7 +72,7 @@ class Tlogger
end
end
- # Publish
+ # Log publishes.
def on_publish(parms, message, headers)
begin
@log.debug "Publish Parms #{info(parms)}"
@@ -83,7 +83,7 @@ class Tlogger
end
end
- # Receive
+ # Log receives.
def on_receive(parms, result)
begin
@log.debug "Receive Parms #{info(parms)}"
@@ -139,7 +139,7 @@ class Tlogger
def info(parms)
#
- # Available in the Hash:
+ # Available in the parms Hash:
# parms[:cur_host]
# parms[:cur_port]
# parms[:cur_login]
@@ -148,8 +148,9 @@ class Tlogger
# parms[:cur_recondelay]
# parms[:cur_parseto]
# parms[:cur_conattempts]
+ # parms[:openstat]
#
- "Host: #{parms[:cur_host]}, Port: #{parms[:cur_port]}, Login: Port: #{parms[:cur_login]}, Passcode: #{parms[:cur_passcode]}"
+ "Host: #{parms[:cur_host]}, Port: #{parms[:cur_port]}, Login: #{parms[:cur_login]}, Passcode: #{parms[:cur_passcode]}"
end
end # of class
--
ruby-stomp.git
More information about the Pkg-ruby-extras-commits
mailing list