[DRE-commits] [ruby-stomp] 01/04: Imported Upstream version 1.2.14

Jonas Genannt jonas at brachium-system.net
Tue Aug 27 12:12:00 UTC 2013


This is an automated email from the git hooks/post-receive script.

hggh-guest pushed a commit to branch master
in repository ruby-stomp.

commit 3e6d963dd249cb7efb40722d25d18e6b11e78dd4
Author: Jonas Genannt <jonas at brachium-system.net>
Date:   Tue Aug 27 14:07:10 2013 +0200

    Imported Upstream version 1.2.14
---
 CHANGELOG.rdoc               |   34 +++++++
 README.rdoc                  |   29 ++++--
 examples/slogger.rb          |   80 ++++++++++++++--
 examples/ssl_uc1_ciphers.rb  |    6 +-
 examples/ssl_uc2.rb          |    9 +-
 examples/ssl_uc2_ciphers.rb  |   16 +++-
 examples/ssl_uc3.rb          |   10 +-
 examples/ssl_uc3_ciphers.rb  |   18 ++--
 examples/ssl_uc4.rb          |   13 ++-
 examples/ssl_uc4_ciphers.rb  |   21 ++--
 lib/client/utils.rb          |   98 +++++++++----------
 lib/connection/heartbeats.rb |  169 +++++++++++++++++++++++++-------
 lib/connection/netio.rb      |   42 +++++---
 lib/connection/utils.rb      |   26 ++++-
 lib/stomp/client.rb          |    8 ++
 lib/stomp/connection.rb      |   65 +++++++++++--
 lib/stomp/constants.rb       |    7 ++
 lib/stomp/errors.rb          |   34 ++++++-
 lib/stomp/version.rb         |    2 +-
 metadata.yml                 |   97 ++++++++-----------
 notes/heartbeat_readme.txt   |  169 ++++++++++++++++++++++++++++++++
 spec/client_spec.rb          |    6 +-
 spec/connection_spec.rb      |   43 ++++++---
 stomp.gemspec                |    7 +-
 test/test_client.rb          |  217 ++++++++++++++++++++++++++++++++----------
 test/test_connection.rb      |   16 +++-
 test/test_connection1p.rb    |   29 +++++-
 test/test_helper.rb          |    7 +-
 test/test_urlogin.rb         |   86 +++++++++++++++++
 test/tlogger.rb              |   10 +-
 30 files changed, 1090 insertions(+), 284 deletions(-)

diff --git a/CHANGELOG.rdoc b/CHANGELOG.rdoc
index 6f61f13..b445b97 100644
--- a/CHANGELOG.rdoc
+++ b/CHANGELOG.rdoc
@@ -1,3 +1,37 @@
+== 1.2.14 20130819
+
+* Version bump (1.2.13 release had Stomp::Version of 1.1.12.)
+* Prevent dup subscription header on re-receive
+
+== 1.2.13 20130817
+
+* Issue #68, Stomp::Client#unreceive max_redeliveries off-by-one error
+
+== 1.2.12 20130811
+
+* Fix infinite loop when max reconn attempts is reached
+* Enhance JRuby support in tests
+* Issue #63, nil message on rapid AMQ restarts
+* Issue #63, fast spurious failovers with JRuby and AMQ
+* Issue #67, SSL SNI support (thanks Hiram)
+* Proper cleanup when not reliable adn EOF from broker
+* Remove extraneous privte declarations
+* Issue #65, allow non-word characters in login and passcode using stomp://
+* Issue #66, allow a single broker in a failover URL
+
+== 1.2.11 20130728
+
+* Issue #60, timeout/hang under JRuby
+* More generally support JRuby use and testing
+* Issue #58, nil message in Client on AMQ shutdown
+* More robust RabbitMQ tests
+
+== 1.2.10 20130708
+
+* Issue #57, reconnect delays not honored if erroneous headers
+* Support fail overs when heartbeat send/receive fails
+* Update callback logger example
+
 == 1.2.9 20130328
 
 * Refactoring and documentation updates (glennr)
diff --git a/README.rdoc b/README.rdoc
index cfb946e..4270a60 100644
--- a/README.rdoc
+++ b/README.rdoc
@@ -10,18 +10,23 @@ An implementation of the Stomp protocol for Ruby. See:
 
 ===New
 
-* Gem version 1.2.9. Miscellaneous fixes and changes. See _CHANGELOG.rdoc_ for details.
-* Gem version 1.2.8. Stomp 1.1+ header codec inversion fix, test refactoring. See _CHANGELOG.rdoc_ for details.
-* Gem version 1.2.7. Stomp 1.2 support and miscellaneous fixes. See _CHANGELOG.rdoc_ for details.
-* Gem version 1.2.6. Miscellaneous fixes and changes. See _CHANGELOG.rdoc_ for details.
-* Gem version 1.2.5. Restructure. Forks with modifcations will be affected. See _CHANGELOG.rdoc_ for details.
+See _CHANGELOG.rdoc_ for details.
+
+* Gem version 1.2.14. Cleanup.
+* Gem version 1.2.13. Stomp::Client#unreceive max_redeliveries fix.
+* Gem version 1.2.12. Miscellaneous issue fixes and cleanup.
+* Gem version 1.2.11. JRuby and AMQ support fixes.
+* Gem version 1.2.10. Support failover from heartbeat threads.
+* Gem version 1.2.9. Miscellaneous fixes and changes.
+* Gem version 1.2.8. Stomp 1.1+ header codec inversion fix, test refactoring.
+* Gem version 1.2.7. Stomp 1.2 support and miscellaneous fixes.
+* Gem version 1.2.6. Miscellaneous fixes and changes.
+* Gem version 1.2.5. Restructure. Forks with modifcations will be affected.
 * 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 _CHANGELOG.rdoc_ for details.
+* Gem version 1.2.1. Full support of SSL certificates.
+* Gem version 1.2.0. Support of Stomp protocol level 1.1.
 
 ===Hash Login Example Usage (this is the recommended login technique)
 
@@ -50,6 +55,11 @@ See _CHANGELOG.rdoc_ for details.
       :hbser => false,                    # raise on heartbeat send exception
       :stompconn => false,                # Use STOMP instead of CONNECT
       :usecrlf => false,                  # Use CRLF command and header line ends (1.2+)
+      :max_hbread_fails => 0,             # Max HB read fails before retry.  0 => never retry
+      :max_hbrlck_fails => 0,             # Max HB read lock obtain fails before retry.  0 => never retry
+      :fast_hbs_adjust => 0.0,            # Fast heartbeat senders sleep adjustment, seconds, needed ...
+                                          # For fast heartbeat senders.  'fast' == YMMV.  If not
+                                          # correct for your environment, expect unnecessary fail overs
     }
 
     # for client
@@ -132,4 +142,5 @@ The following people have contributed to Stomp:
 * Jeremy Gailor
 * JP Hastings-Spital
 * Glenn Roberts
+* Ian Smith
 
diff --git a/examples/slogger.rb b/examples/slogger.rb
index b6e81ee..278a1e5 100644
--- a/examples/slogger.rb
+++ b/examples/slogger.rb
@@ -15,6 +15,14 @@ require 'logger'	# use the standard Ruby logger .....
 #
 # *    on_publish: publish called
 # *    on_subscribe: subscribe called
+# *    on_unsubscribe: unsubscribe called
+#
+# *    on_begin: begin called
+# *    on_ack: ack called
+# *    on_nack: nack called
+# *    on_commit: commit called
+# *    on_abort: abort called
+#
 # *    on_receive: receive called and successful
 #
 # *    on_ssl_connecting: SSL connection starting
@@ -80,7 +88,7 @@ class Slogger
 =begin
     # An example LoggerConnectionError raise
     @log.debug "Connect Fail, will raise"
-    raise Stomp::Error::LoggerConnectionError.new("quit from connect")
+    raise Stomp::Error::LoggerConnectionError.new("quit from connect fail")
 =end
   end
 
@@ -113,6 +121,16 @@ class Slogger
     end
   end
 
+  # Log UnSubscribe
+  def on_unsubscribe(parms, headers)
+    begin
+      @log.debug "UnSubscribe Parms #{info(parms)}"
+      @log.debug "UnSubscribe Headers #{headers}"
+    rescue
+      @log.debug "UnSubscribe oops"
+    end
+  end
+
   # Log Publish
   def on_publish(parms, message, headers)
     begin
@@ -134,21 +152,71 @@ class Slogger
     end
   end
 
+  # Log Begin
+  def on_begin(parms, headers)
+    begin
+      @log.debug "Begin Parms #{info(parms)}"
+      @log.debug "Begin Result #{headers}"
+    rescue
+      @log.debug "Begin oops"
+    end
+  end
+
+  # Log Ack
+  def on_ack(parms, headers)
+    begin
+      @log.debug "Ack Parms #{info(parms)}"
+      @log.debug "Ack Result #{headers}"
+    rescue
+      @log.debug "Ack oops"
+    end
+  end
+
+  # Log NAck
+  def on_nack(parms, headers)
+    begin
+      @log.debug "NAck Parms #{info(parms)}"
+      @log.debug "NAck Result #{headers}"
+    rescue
+      @log.debug "NAck oops"
+    end
+  end
+
+  # Log Commit
+  def on_commit(parms, headers)
+    begin
+      @log.debug "Commit Parms #{info(parms)}"
+      @log.debug "Commit Result #{headers}"
+    rescue
+      @log.debug "Commit oops"
+    end
+  end
+
+  # Log Abort
+  def on_abort(parms, headers)
+    begin
+      @log.debug "Abort Parms #{info(parms)}"
+      @log.debug "Abort Result #{headers}"
+    rescue
+      @log.debug "Abort oops"
+    end
+  end
+
   # Stomp 1.1+ - heart beat read (receive) failed.
-  def on_hbread_fail(parms, ticker_data)
+  def on_hbread_fail(parms, ticker_data = {})
     begin
       @log.debug "Hbreadf Parms #{info(parms)}"
-      @log.debug "Hbreadf Result #{ticker_data}"
+      @log.debug "Hbreadf Result #{ticker_data.inspect}"
     rescue
       @log.debug "Hbreadf oops"
     end
   end
 
   # Stomp 1.1+ - heart beat send (transmit) failed.
-  def on_hbwrite_fail(parms, ticker_data)
+  def on_hbwrite_fail(parms, ticker_data = {})
     begin
       @log.debug "Hbwritef Parms #{info(parms)}"
-      @log.debug "Hbwritef Result #{ticker_data}"
+      @log.debug "Hbwritef Result #{ticker_data.inspect}"
     rescue
       @log.debug "Hbwritef oops"
     end
@@ -188,7 +256,7 @@ class Slogger
   end
 
   # Log heart beat fires
-  def on_hbfire(parms, srind, curt)
+  def on_hbfire(parms, srind, firedata = {})
     begin
       @log.debug "HeartBeat Fire Parms #{info(parms)}"
       @log.debug "HeartBeat Fire Send/Receive #{srind}"
diff --git a/examples/ssl_uc1_ciphers.rb b/examples/ssl_uc1_ciphers.rb
index dab4ded..3b0fdf3 100644
--- a/examples/ssl_uc1_ciphers.rb
+++ b/examples/ssl_uc1_ciphers.rb
@@ -19,8 +19,7 @@ class ExampleSSL1C
   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", [...]
-    ["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]]
+    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", [...]
 
     ssl_opts = Stomp::SSLParams.new(:ciphers => ciphers_list)
 
@@ -29,7 +28,8 @@ class ExampleSSL1C
     #
     hash = { :hosts => [
         {:login => 'guest', :passcode => 'guest', :host => 'localhost', :port => 61612, :ssl => ssl_opts},
-      ]
+      ],
+      :reliable => false, # YMMV, to test this in a sane manner
     }
     #
     puts "Connect starts, SSL Use Case 1"
diff --git a/examples/ssl_uc2.rb b/examples/ssl_uc2.rb
index 6e4d049..23b0213 100644
--- a/examples/ssl_uc2.rb
+++ b/examples/ssl_uc2.rb
@@ -25,8 +25,13 @@ class ExampleSSL2
   # 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(","))
+
+    # Change the following to the location of the server's CA signed certificate.
+    ts_flist << "/home/gmallard/sslwork/2013/TestCA.crt"
+
+    ssl_opts = Stomp::SSLParams.new(:ts_files => ts_flist.join(","), 
+      :fsck => true,
+    )
     #
     hash = { :hosts => [
         {:login => 'guest', :passcode => 'guest', :host => 'localhost', :port => 61612, :ssl => ssl_opts},
diff --git a/examples/ssl_uc2_ciphers.rb b/examples/ssl_uc2_ciphers.rb
index 50a7a00..ec0e695 100644
--- a/examples/ssl_uc2_ciphers.rb
+++ b/examples/ssl_uc2_ciphers.rb
@@ -19,18 +19,24 @@ class ExampleSSL2C
   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", [...]
-    ["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]]
+    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", [...]
     #
     # 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)
+
+    # Change the following to the location of your CA's signed certificate.
+    ts_flist << "/home/gmallard/sslwork/2013/TestCA.crt"
+
+    ssl_opts = Stomp::SSLParams.new(:ts_files => ts_flist.join(","), 
+      :ciphers => ciphers_list,
+      :fsck => true
+    )
     #
     hash = { :hosts => [
         {:login => 'guest', :passcode => 'guest', :host => 'localhost', :port => 61612, :ssl => ssl_opts},
-      ]
+      ],
+      :reliable => false, # YMMV, to test this in a sane manner
     }
     #
     puts "Connect starts, SSL Use Case 2"
diff --git a/examples/ssl_uc3.rb b/examples/ssl_uc3.rb
index 504107d..3f5a767 100644
--- a/examples/ssl_uc3.rb
+++ b/examples/ssl_uc3.rb
@@ -26,8 +26,14 @@ class ExampleSSL3
   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")
+    # Change the following:
+    # * location of the client's signed certificate
+    # * location of the client's private key.
+    ssl_opts = Stomp::SSLParams.new(
+      :key_file => "/home/gmallard/sslwork/2013/client.key", # the client's private key
+      :cert_file => "/home/gmallard/sslwork/2013/client.crt", # the client's signed certificate
+      :fsck => true # Check that the files exist first
+    )
 
     #
     hash = { :hosts => [
diff --git a/examples/ssl_uc3_ciphers.rb b/examples/ssl_uc3_ciphers.rb
index 62d5b2d..9e25fd1 100644
--- a/examples/ssl_uc3_ciphers.rb
+++ b/examples/ssl_uc3_ciphers.rb
@@ -19,18 +19,24 @@ class ExampleSSL3C
   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", [...]
-    ["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]]
+    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", [...]
     #
     # 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)
-
+    # Change the following:
+    # * location of your client's signed certificate
+    # * location of tour client's private key.
+    ssl_opts = Stomp::SSLParams.new(
+      :key_file => "/home/gmallard/sslwork/2013/client.key", # the client's private key
+      :cert_file => "/home/gmallard/sslwork/2013/client.crt", # the client's signed certificate
+      :fsck => true, # Check that the files exist first
+      :ciphers => ciphers_list
+    )
     #
     hash = { :hosts => [
         {:login => 'guest', :passcode => 'guest', :host => 'localhost', :port => 61612, :ssl => ssl_opts},
-      ]
+      ],
+      :reliable => false, # YMMV, to test this in a sane manner
     }
     #
     puts "Connect starts, SSL Use Case 3"
diff --git a/examples/ssl_uc4.rb b/examples/ssl_uc4.rb
index c861617..bc8deec 100644
--- a/examples/ssl_uc4.rb
+++ b/examples/ssl_uc4.rb
@@ -26,9 +26,16 @@ class ExampleSSL4
   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")
+    # Change the following:
+    # * location of the client's private key
+    # * location of the client's signed certificate
+    # * location of the server's CA signed certificate
+    ssl_opts = Stomp::SSLParams.new(
+      :key_file => "/home/gmallard/sslwork/2013/client.key", # The client's private key
+      :cert_file => "/home/gmallard/sslwork/2013/client.crt", # The client's signed certificate
+      :ts_files => "/home/gmallard/sslwork/2013/TestCA.crt", # The CA's signed sertificate
+      :fsck => true # Check that files exist first
+    )
     #
     hash = { :hosts => [
         {:login => 'guest', :passcode => 'guest', :host => 'localhost', :port => 61612, :ssl => ssl_opts},
diff --git a/examples/ssl_uc4_ciphers.rb b/examples/ssl_uc4_ciphers.rb
index 9fd91be..015eab2 100644
--- a/examples/ssl_uc4_ciphers.rb
+++ b/examples/ssl_uc4_ciphers.rb
@@ -19,19 +19,26 @@ class ExampleSSL4C
   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", [...]
-    ["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]]
+    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", [...]
     #
     # 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)
+    # Change the following:
+    # * location of the client's private key
+    # * location of the client's signed certificate
+    # * location of the server's CA signed certificate
+    ssl_opts = Stomp::SSLParams.new(
+      :key_file => "/home/gmallard/sslwork/2013/client.key", # The client's private key
+      :cert_file => "/home/gmallard/sslwork/2013/client.crt", # The client's signed certificate
+      :ts_files => "/home/gmallard/sslwork/2013/TestCA.crt", # The CA's signed sertificate
+      :fsck => true, # Check that files exist first
+      :ciphers => ciphers_list
+    )
     #
     hash = { :hosts => [
         {:login => 'guest', :passcode => 'guest', :host => 'localhost', :port => 61612, :ssl => ssl_opts},
-      ]
+      ],
+      :reliable => false, # YMMV, to test this in a sane manner
     }
     #
     puts "Connect starts, SSL Use Case 4"
diff --git a/lib/client/utils.rb b/lib/client/utils.rb
index 162f74b..9170344 100644
--- a/lib/client/utils.rb
+++ b/lib/client/utils.rb
@@ -21,43 +21,43 @@ module Stomp
       @reliable = true
       true
     end
-    private :parse_hash_params
 
     def parse_stomp_url(login)
-      regexp = /^stomp:\/\/#{url_regex}/ # e.g. stomp://login:passcode@host:port or stomp://host:port
+      regexp = /^stomp:\/\/#{URL_REPAT}/
       return false unless login =~ regexp
 
-      @login = $2 || ""
-      @passcode = $3 || ""
-      @host = $4
-      @port = $5.to_i
+      @login = $3 || ""
+      @passcode = $4 || ""
+      @host = $5
+      @port = $6.to_i
+
       @reliable = false
       true
     end
-    private :parse_stomp_url
 
     # e.g. failover://(stomp://login1:passcode1@localhost:61616,stomp://login2:passcode2@remotehost:61617)?option1=param
     def parse_failover_url(login)
-      regexp = /^failover:(\/\/)?\(stomp(\+ssl)?:\/\/#{url_regex}(,stomp(\+ssl)?:\/\/#{url_regex}\))+(\?(.*))?$/
-      return false unless login =~ regexp
-
-      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
-      true
+      rval = nil
+      if md = FAILOVER_REGEX.match(login)
+        finhosts = parse_hosts(login)
+        #
+        @login = finhosts[0][:login] || ""
+        @passcode = finhosts[0][:passcode] || ""
+        @host = finhosts[0][:host] || ""
+        @port = finhosts[0][:port] || ""
+        #
+        options = {}
+        if md_last = md[md.size-1]
+          parts = md_last.split(/&|=/)
+          raise Stomp::Error::MalformedFailoverOptionsError unless (parts.size % 2 ) == 0
+          options = Hash[*parts]
+        end
+        @parameters = {:hosts => finhosts}.merge! filter_options(options)
+        @reliable = true
+        rval = true
+      end
+      rval
     end
-    private :parse_failover_url
 
     def parse_positional_params(login, passcode, host, port, reliable)
       @login = login
@@ -67,7 +67,6 @@ module Stomp
       @reliable = reliable
       true
     end
-    private :parse_positional_params
 
     # Set a subscription id in the headers hash if one does not already exist.
     # For simplicities sake, all subscriptions have a subscription ID.
@@ -91,29 +90,21 @@ module Stomp
       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
+# Parse a stomp URL.
+def parse_hosts(url)
+  hosts = []
+  host_match = /stomp(\+ssl)?:\/\/#{URL_REPAT}/
+  url.scan(host_match).each do |match|
+    host = {}
+    host[:ssl] = match[0] == "+ssl" ? true : false
+    host[:login] =  match[3] || ""
+    host[:passcode] = match[4] || ""
+    host[:host] = match[5]
+    host[:port] = match[6].to_i
+    hosts << host
+  end
+  hosts
+end
 
     # A very basic check of required arguments.
     def check_arguments!()
@@ -157,7 +148,12 @@ module Stomp
       @listener_thread = Thread.start do
         while true
           message = @connection.receive
-          if message # AMQ specific?, nil message on multiple reconnects
+          # AMQ specific behavior
+          if message.nil? && (!@reliable)
+            raise Stomp::Error::NilMessageError
+          end
+          if message # message can be nil on rapid AMQ stop / start sequences
+          # OK, we have some real data
             if message.command == Stomp::CMD_MESSAGE
               if listener = find_listener(message)
                 listener.call(message)
diff --git a/lib/connection/heartbeats.rb b/lib/connection/heartbeats.rb
index dbd2c86..624cb98 100644
--- a/lib/connection/heartbeats.rb
+++ b/lib/connection/heartbeats.rb
@@ -90,37 +90,62 @@ module Stomp
     # _start_send_ticker starts a thread to send heartbeats when required.
     def _start_send_ticker()
       sleeptime = @hbsend_interval / 1000000.0 # Sleep time secs
+      reconn = false
+      adjust = 0.0
       @st = Thread.new {
+        first_time = true
         while true do
-          sleep sleeptime
+          #
+          slt = sleeptime - adjust - @fast_hbs_adjust
+          sleep(slt)
+          next unless @socket # nil under some circumstances ??
           curt = Time.now.to_f
           if @logger && @logger.respond_to?(:on_hbfire)
-            @logger.on_hbfire(log_params, "send_fire", curt)
+            @logger.on_hbfire(log_params, "send_fire", :curt => curt, :last_sleep => slt)
           end
           delta = curt - @ls
-          if delta > (@hbsend_interval - (@hbsend_interval/5.0)) / 1000000.0 # Be tolerant (minus)
+          # Be tolerant (minus), and always do this the first time through.
+          # Reintroduce logic removed in d922fa.
+          compval = (@hbsend_interval - (@hbsend_interval/5.0)) / 1000000.0
+          if delta > compval || first_time
+            first_time = false
             if @logger && @logger.respond_to?(:on_hbfire)
-              @logger.on_hbfire(log_params, "send_heartbeat", curt)
+              @logger.on_hbfire(log_params, "send_heartbeat", :last_sleep => slt,
+                :curt => curt, :last_send => @ls, :delta => delta,
+                :compval => compval)
             end
             # Send a heartbeat
             @transmit_semaphore.synchronize do
               begin
                 @socket.puts
-                @ls = curt      # Update last send
-                @hb_sent = true # Reset if necessary
+                @socket.flush       # Do not buffer heartbeats
+                @ls = Time.now.to_f # 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,
+                  @logger.on_hbwrite_fail(log_params, {"ticker_interval" => sleeptime,
                   "exception" => sendex})
                 end
                 if @hbser
                   raise # Re-raise if user requested this, otherwise ignore
                 end
+                if @reliable
+                  reconn = true
+                  break # exit the synchronize do
+                end
               end
+            end # of the synchronize
+            if reconn
+              # Attempt a fail over reconnect.  This is 'safe' here because
+              # this thread no longer holds the @transmit_semaphore lock.
+              @rt.kill if @rt   # Kill the receiver thread if one exists
+              _reconn_prep_hb() # Drive reconnection logic
+              Thread.exit       # This sender thread is done
             end
           end
+          adjust = Time.now.to_f - curt
           Thread.pass
         end
       }
@@ -129,44 +154,118 @@ module Stomp
     # _start_receive_ticker starts a thread that receives heartbeats when required.
     def _start_receive_ticker()
       sleeptime = @hbrecv_interval / 1000000.0 # Sleep time secs
+      read_fail_count = 0
+      lock_fail_count = 0
+      fail_hard = false
       @rt = Thread.new {
+
+        #
         while true do
           sleep sleeptime
+          next unless @socket # nil under some circumstances ??
+          rdrdy = _is_ready?(@socket)
           curt = Time.now.to_f
           if @logger && @logger.respond_to?(:on_hbfire)
-            @logger.on_hbfire(log_params, "receive_fire", curt)
+            @logger.on_hbfire(log_params, "receive_fire", :curt => 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)
+          #
+          begin
+            delta = curt - @lr
+            if delta > sleeptime
+              if @logger && @logger.respond_to?(:on_hbfire)
+                @logger.on_hbfire(log_params, "receive_heartbeat", {})
               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})
+              # 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
+                lock_fail_count = 0 # clear
+                rdrdy = _is_ready?(@socket)
+                if rdrdy
+                  read_fail_count = 0 # clear
+                  last_char = @socket.getc
+                  if last_char.nil? # EOF from broker?
+                    fail_hard = true
+                  else
+                    @lr = Time.now.to_f
+                    plc = parse_char(last_char)
+                    if plc == "\n" # Server Heartbeat
+                      @hbrecv_count += 1
+                      @hb_received = true # Reset if necessary
+                    else
+                      @socket.ungetc(last_char)
+                    end
+                  end
+                  @read_semaphore.unlock # Release read lock
+                else # Socket is not ready
+                  @read_semaphore.unlock # Release read lock
+                  @hb_received = false
+                  read_fail_count += 1
+                  if @logger && @logger.respond_to?(:on_hbread_fail)
+                    @logger.on_hbread_fail(log_params, {"ticker_interval" => sleeptime,
+                      "read_fail_count" => read_fail_count, "lock_fail" => false,
+                      "lock_fail_count" => lock_fail_count})
+                  end
+                end
+              else  # try_lock failed
+                # Shrug.  Could not get lock.  Client must be actually be reading.
+                @hb_received = false
+                # But notify caller if possible
+                lock_fail_count += 1
+                if @logger && @logger.respond_to?(:on_hbread_fail)
+                  @logger.on_hbread_fail(log_params, {"ticker_interval" => sleeptime,
+                    "read_fail_count" => read_fail_count, "lock_fail" => true,
+                    "lock_fail_count" => lock_fail_count})
+                end
+              end # of the try_lock
+
+            else # delta <= sleeptime
+              @hb_received = true # Reset if necessary
+              read_fail_count = 0 # reset
+              lock_fail_count = 0 # reset
+            end # of the if delta > sleeptime
+          rescue Exception => recvex
+            if @logger && @logger.respond_to?(:on_hbread_fail)
+              @logger.on_hbread_fail(log_params, {"ticker_interval" => sleeptime,
+                "exception" => recvex, "read_fail_count" => read_fail_count,
+                "lock_fail_count" => lock_fail_count})
+            end
+            fail_hard = true
+          end
+          # Do we want to attempt a retry?
+          if @reliable
+            # Retry on hard fail or max read fails
+            if fail_hard ||
+              (@max_hbread_fails > 0 && read_fail_count >= @max_hbread_fails)
+              # This is an attempt at a connection retry.
+              @st.kill if @st   # Kill the sender thread if one exists
+              _reconn_prep_hb() # Drive reconnection logic
+              Thread.exit       # This receiver thread is done            
+            end
+            # Retry on max lock fails.  Different logic in order to avoid a deadlock.
+            if (@max_hbrlck_fails > 0 && lock_fail_count >= @max_hbrlck_fails)
+              # This is an attempt at a connection retry.
+              begin
+                @socket.close # Attempt a forced close
+              rescue
               end
+              @st.kill if @st   # Kill the sender thread if one exists
+              Thread.exit       # This receiver thread is done            
             end
-          else
-            @hb_received = true # Reset if necessary
           end
-          Thread.pass
-        end
-      }
+          Thread.pass         # Prior to next receive loop
+        #
+        end # of the "while true"
+      } # end of the Thread.new
+    end
+
+    # _reconn_prep_hb prepares for a reconnect retry
+    def _reconn_prep_hb()
+      if @parameters
+        change_host()
+      end
+      @socket = nil
+      used_socket = socket()
     end
 
   end # class Connection
diff --git a/lib/connection/netio.rb b/lib/connection/netio.rb
index 320c610..dd08213 100644
--- a/lib/connection/netio.rb
+++ b/lib/connection/netio.rb
@@ -16,7 +16,16 @@ module Stomp
       @read_semaphore.synchronize do
         line = ''
         if @protocol == Stomp::SPL_10 || (@protocol >= Stomp::SPL_11 && !@hbr)
-          line = read_socket.gets # The old way
+          if @jruby
+            # Handle JRuby specific behavior.
+            while true
+              line = read_socket.gets # Data from wire
+              break unless line == "\n"
+              line = ''
+            end
+          else
+            line = read_socket.gets # The old way
+          end
         else # We are >= 1.1 *AND* receiving heartbeats.
           while true
             line = read_socket.gets # Data from wire
@@ -28,7 +37,6 @@ module Stomp
         return nil if line.nil?
         # p [ "wiredatain_01", line ]
         line = _normalize_line_end(line) if @protocol >= Stomp::SPL_12
-
         # 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
@@ -58,15 +66,16 @@ module Stomp
 
           # 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: experiments with JRuby seem to show that socket.ready? never
+          # returns true.  It appears that in cases where Ruby returns true
+          # that JRuby returns a Fixnum.  We attempt to adjust for this
+          # in the _is_ready? method.
           #
           # 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?
+          while _is_ready?(read_socket)
             last_char = read_socket.getc
             break unless last_char
             if parse_char(last_char) != "\n"
@@ -74,9 +83,6 @@ module Stomp
               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
@@ -92,6 +98,15 @@ module Stomp
       end
     end
 
+    # Check if the socket is ready, i.e. there is data to read.
+    def _is_ready?(s)
+      rdy = s.ready?
+      if @jruby
+        rdy = rdy.class == Fixnum ? true : false
+      end
+      rdy
+    end
+
     # Normalize line ends because 1.2+ brokers can send 'mixed mode' headers, i.e.:
     # - Some headers end with '\n'
     # - Other headers end with '\r\n'
@@ -124,6 +139,8 @@ module Stomp
           else
             $stderr.print errstr
           end
+          # !!! This loop initiates a re-connect !!!
+          _reconn_prep()
         end
       end
     end
@@ -262,7 +279,6 @@ module Stomp
             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
@@ -275,6 +291,8 @@ module Stomp
 
         Timeout::timeout(@connect_timeout, Stomp::Error::SocketOpenTimeout) do
           ssl = OpenSSL::SSL::SSLSocket.new(open_tcp_socket, ctx)
+          ssl.hostname = @host if ssl.respond_to? :hostname=
+          ssl.sync_close = true # Sync ssl close with underlying TCP socket
           ssl.connect
         end
         def ssl.ready?
@@ -351,7 +369,9 @@ module Stomp
       @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) }
+      @subscriptions.each {|k,v| 
+        _transmit(used_socket, Stomp::CMD_SUBSCRIBE, v)
+      }
     end
 
   end # class Connection
diff --git a/lib/connection/utils.rb b/lib/connection/utils.rb
index 64fd8eb..548bf0b 100644
--- a/lib/connection/utils.rb
+++ b/lib/connection/utils.rb
@@ -53,6 +53,7 @@ module Stomp
       lparms[:cur_recondelay] = @reconnect_delay
       lparms[:cur_parseto] = @parse_timeout
       lparms[:cur_conattempts] = @connection_attempts
+      lparms[:cur_failure] = @failure # To assist in debugging
       lparms[:openstat] = open?
       #
       lparms
@@ -122,9 +123,15 @@ module Stomp
           rescue
             @failure = $!
             used_socket = nil
+            @closed = true
+
             raise unless @reliable
             raise if @failure.is_a?(Stomp::Error::LoggerConnectionError)
-            @closed = true
+            # Catch errors which are:
+            # a) emitted from corrupted 1.1+ 'connect' (caller programming error)
+            # b) should never be retried
+            raise if @failure.is_a?(Stomp::Error::ProtocolError11p)
+
             if @logger && @logger.respond_to?(:on_connectfail)
               # on_connectfail may raise
               begin
@@ -172,6 +179,9 @@ module Stomp
         :closed_check => true,
         :hbser => false,
         :stompconn => false,
+        :max_hbread_fails => 0,
+        :max_hbrlck_fails => 0,
+        :fast_hbs_adjust => 0.0,
       }
 
       res_params = default_params.merge(params)
@@ -220,6 +230,8 @@ module Stomp
         begin
           used_socket = socket()
           return _receive(used_socket)
+        rescue Stomp::Error::MaxReconnectAttempts
+          raise
         rescue
           @failure = $!
           raise unless @reliable
@@ -229,10 +241,22 @@ module Stomp
           else
             $stderr.print errstr
           end
+          # !!! This initiates a re-connect !!!
+          _reconn_prep()
         end
       end
     end
 
+    # _reconn_prep prepares for a reconnect retry
+    def _reconn_prep()
+      if @parameters
+        change_host()
+      end
+      @st.kill if @st # Kill ticker thread if any
+      @rt.kill if @rt # Kill ticker thread if any
+      @socket = nil
+    end
+
   end # class Connection
 
 end # module Stomp
diff --git a/lib/stomp/client.rb b/lib/stomp/client.rb
index 90ca069..28625c2 100644
--- a/lib/stomp/client.rb
+++ b/lib/stomp/client.rb
@@ -55,6 +55,9 @@ module Stomp
     #     :hbser => false,
     #     :stompconn => false,
     #     :usecrlf => false,
+    #     :max_hbread_fails => 0,
+    #     :max_hbrlck_fails => 0,
+    #     :fast_hbs_adjust => 0.0,
     #   }
     #
     #   e.g. c = Stomp::Client.new(hash)
@@ -231,6 +234,11 @@ module Stomp
       @connection.closed?()
     end
 
+    # jruby? tests if the connection has detcted a JRuby environment
+    def jruby?()
+      @connection.jruby
+    end
+
     # close frees resources in use by this client.  The listener thread is
     # terminated, and disconnect on the connection is called.
     def close(headers={})
diff --git a/lib/stomp/connection.rb b/lib/stomp/connection.rb
index 52d5cfd..e20344f 100644
--- a/lib/stomp/connection.rb
+++ b/lib/stomp/connection.rb
@@ -31,6 +31,9 @@ module Stomp
     # Heartbeat send has been successful.
     attr_reader   :hb_sent # Heartbeat sent successfully
 
+    # JRuby detected
+    attr_reader   :jruby
+
     # Autoflush forces a flush on each transmit.  This may be changed
     # dynamically by calling code.
     attr_accessor :autoflush
@@ -65,6 +68,9 @@ module Stomp
     #     :hbser => false,
     #     :stompconn => false,
     #     :usecrlf => false,
+    #     :max_hbread_fails => 0,
+    #     :max_hbrlck_fails => 0,
+    #     :fast_hbs_adjust => 0.0,
     #   }
     #
     #   e.g. c = Stomp::Connection.new(hash)
@@ -85,7 +91,10 @@ module Stomp
       @hb_received = true       # Assumed at first
       @hb_sent = true           # Assumed at first
       @hbs = @hbr = false       # Sending/Receiving heartbeats. Assume no for now.
-
+      @jruby = false            # Assumed at first
+      if defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /jruby/
+        @jruby = true
+      end
       if login.is_a?(Hash)
         hashed_initialize(login)
       else
@@ -106,6 +115,9 @@ module Stomp
         @hbser = false        # Raise if heartbeat send exception
         @stompconn = false    # If true, use STOMP rather than CONNECT
         @usecrlf = false      # If true, use \r\n as line ends (1.2 only)
+        @max_hbread_fails = 0 # 0 means never retry for HB read failures
+        @max_hbrlck_fails = 0 # 0 means never retry for HB read lock failures
+        @fast_hbs_adjust = 0.0 # Fast heartbeat senders sleep adjustment 
         warn "login looks like a URL, do you have the correct parameters?" if @login =~ /:\/\//
       end
 
@@ -138,6 +150,9 @@ module Stomp
       @hbser = @parameters[:hbser]
       @stompconn = @parameters[:stompconn]
       @usecrlf = @parameters[:usecrlf]
+      @max_hbread_fails = @parameters[:max_hbread_fails]
+      @max_hbrlck_fails = @parameters[:max_hbrlck_fails]
+      @fast_hbs_adjust = @parameters[:fast_hbs_adjust]
       #sets the first host to connect
       change_host
     end
@@ -163,6 +178,9 @@ module Stomp
       headers = headers.symbolize_keys
       headers[:transaction] = name
       _headerCheck(headers)
+      if @logger && @logger.respond_to?(:on_begin)
+        @logger.on_begin(log_params, headers)
+      end
       transmit(Stomp::CMD_BEGIN, headers)
     end
 
@@ -193,6 +211,9 @@ module Stomp
           headers[:'message-id'] = message_id
       end
       _headerCheck(headers)
+      if @logger && @logger.respond_to?(:on_ack)
+        @logger.on_ack(log_params, headers)
+      end
       transmit(Stomp::CMD_ACK, headers)
     end
 
@@ -216,6 +237,9 @@ module Stomp
           raise Stomp::Error::SubscriptionRequiredError unless headers[:subscription]
       end
       _headerCheck(headers)
+      if @logger && @logger.respond_to?(:on_nack)
+        @logger.on_nack(log_params, headers)
+      end
       transmit(Stomp::CMD_NACK, headers)
     end
 
@@ -225,6 +249,9 @@ module Stomp
       headers = headers.symbolize_keys
       headers[:transaction] = name
       _headerCheck(headers)
+      if @logger && @logger.respond_to?(:on_commit)
+        @logger.on_commit(log_params, headers)
+      end
       transmit(Stomp::CMD_COMMIT, headers)
     end
 
@@ -234,6 +261,9 @@ module Stomp
       headers = headers.symbolize_keys
       headers[:transaction] = name
       _headerCheck(headers)
+      if @logger && @logger.respond_to?(:on_abort)
+        @logger.on_abort(log_params, headers)
+      end
       transmit(Stomp::CMD_ABORT, headers)
     end
 
@@ -270,8 +300,12 @@ module Stomp
       headers[:destination] = dest
       if @protocol >= Stomp::SPL_11
         raise Stomp::Error::SubscriptionRequiredError if (headers[:id].nil? && subId.nil?)
+        headers[:id] = subId unless headers[:id]
       end
       _headerCheck(headers)
+      if @logger && @logger.respond_to?(:on_unsubscribe)
+        @logger.on_unsubscribe(log_params, headers)
+      end
       transmit(Stomp::CMD_UNSUBSCRIBE, headers)
       if @reliable
         subId = dest if subId.nil?
@@ -302,12 +336,14 @@ module Stomp
       options = { :dead_letter_queue => "/queue/DLQ", :max_redeliveries => 6 }.merge(options)
       # Lets make sure all keys are symbols
       message.headers = message.headers.symbolize_keys
-
       retry_count = message.headers[:retry_count].to_i || 0
       message.headers[:retry_count] = retry_count + 1
       transaction_id = "transaction-#{message.headers[:'message-id']}-#{retry_count}"
       message_id = message.headers.delete(:'message-id')
 
+      # Prevent duplicate 'subscription' headers on subsequent receives
+      message.headers.delete(:subscription) if message.headers[:subscription]
+
       begin
         self.begin transaction_id
 
@@ -315,7 +351,7 @@ module Stomp
           self.ack(message_id, :transaction => transaction_id)
         end
 
-        if retry_count <= options[:max_redeliveries]
+        if message.headers[:retry_count] <= options[:max_redeliveries]
           self.publish(message.headers[:destination], message.body, 
             message.headers.merge(:transaction => transaction_id))
         else
@@ -366,10 +402,13 @@ module Stomp
       receive()
     end
 
-    # receive returns the next Message off of the wire.
+    # receive returns the next Message off of the wire.  this can return nil
+    # in cases where:
+    # * the broker has closed the connection
+    # * the connection is not reliable
     def receive()
       raise Stomp::Error::NoCurrentConnection if @closed_check && closed?
-      super_result = __old_receive
+      super_result = __old_receive()
       if super_result.nil? && @reliable && !closed?
         errstr = "connection.receive returning EOF as nil - resetting connection.\n"
         if @logger && @logger.respond_to?(:on_miscerr)
@@ -377,10 +416,22 @@ module Stomp
         else
           $stderr.print errstr
         end
-        @socket = nil
-        super_result = __old_receive
+        # !!! This initiates a re-connect !!!
+        # The call to __old_receive() will in turn call socket().  Before
+        # that we should change the target host, otherwise the host that
+        # just failed may be attempted first.
+        _reconn_prep()
+        #
+        super_result = __old_receive()
       end
       #
+      if super_result.nil? && !@reliable
+        @st.kill if @st # Kill ticker thread if any
+        @rt.kill if @rt # Kill ticker thread if any
+        close_socket()
+        @closed = true
+        warn 'warning: broker sent EOF, and connection not reliable' unless defined?(Test)
+      end
       if @logger && @logger.respond_to?(:on_receive)
         @logger.on_receive(log_params, super_result)
       end
diff --git a/lib/stomp/constants.rb b/lib/stomp/constants.rb
index b43e3fb..e6efe55 100644
--- a/lib/stomp/constants.rb
+++ b/lib/stomp/constants.rb
@@ -111,4 +111,11 @@ module Stomp
     ["EXP-RC4-MD5", "TLSv1/SSLv3", 40, 128],
   ]
 
+  # stomp URL regex pattern, for e.g. login:passcode at host:port or host:port
+  URL_REPAT = '((([\w~!@#$%^&*()\-+=.?:<>,.]*\w):([\w~!@#$%^&*()\-+=.?:<>,.]*))?@)?([\w\.\-]+):(\d+)'
+
+  # Failover URL regex, for e.g.
+  #failover:(stomp+ssl://login1:passcode1@remotehost1:61612,stomp://login2:passcode2@remotehost2:61613)
+  FAILOVER_REGEX = /^failover:(\/\/)?\(stomp(\+ssl)?:\/\/#{URL_REPAT}(,stomp(\+ssl)?:\/\/#{URL_REPAT})*\)(\?(.*))?$/
+
 end # Module Stomp
diff --git a/lib/stomp/errors.rb b/lib/stomp/errors.rb
index a6f09af..4ed7bb2 100644
--- a/lib/stomp/errors.rb
+++ b/lib/stomp/errors.rb
@@ -71,17 +71,24 @@ module Stomp
       end
     end
 
+    # ProtocolError11p - base class of 1.1 CONNECT errors
+    class ProtocolError11p < RuntimeError
+      def message
+        "STOMP 1.1+ CONNECT error"
+      end
+    end
+
     # ProtocolErrorConnect is raised if:
-    # * Incomplete Stomp 1.1 headers are detectd during a connect.
-    class ProtocolErrorConnect < RuntimeError
+    # * Incomplete Stomp 1.1 headers are detected during a connect.
+    class ProtocolErrorConnect < ProtocolError11p
       def message
-        "protocol error on CONNECT"
+        "STOMP 1.1+ CONNECT error, missing/incorrect CONNECT headers"
       end
     end
 
     # UnsupportedProtocolError is raised if:
     # * No supported Stomp protocol levels are detected during a connect.
-    class UnsupportedProtocolError < RuntimeError
+    class UnsupportedProtocolError < ProtocolError11p
       def message
         "unsupported protocol level(s)"
       end
@@ -89,7 +96,7 @@ module Stomp
 
     # InvalidHeartBeatHeaderError is raised if:
     # * A "heart-beat" header is present, but the values are malformed.
-    class InvalidHeartBeatHeaderError < RuntimeError
+    class InvalidHeartBeatHeaderError < ProtocolError11p
       def message
         "heart-beat header value is malformed"
       end
@@ -189,6 +196,23 @@ module Stomp
     class LoggerConnectionError < RuntimeError
     end
 
+    # NilMessageError is raised if:
+    # * Invalid (nil) data is received from the Stomp server in a client's
+    # listener thread, and the connection is not reliable.
+    class NilMessageError < RuntimeError
+      def message
+        "Received message is nil, and connection not reliable"
+      end
+    end
+
+    # MalformedFailoverOptionsError is raised if failover URL
+    # options can not be parsed
+    class MalformedFailoverOptionsError < RuntimeError
+      def message
+        "failover options are malformed"
+      end
+    end
+
   end # module Error
 
 end # module Stomp
diff --git a/lib/stomp/version.rb b/lib/stomp/version.rb
index 57facdb..11b5a77 100644
--- a/lib/stomp/version.rb
+++ b/lib/stomp/version.rb
@@ -6,7 +6,7 @@ module Stomp
   module Version  #:nodoc: all
     MAJOR = 1
     MINOR = 2
-    PATCH = 9
+    PATCH = 14
     STRING = "#{MAJOR}.#{MINOR}.#{PATCH}"
   end
 end
diff --git a/metadata.yml b/metadata.yml
index d9c2144..1a50f48 100644
--- a/metadata.yml
+++ b/metadata.yml
@@ -1,15 +1,10 @@
---- !ruby/object:Gem::Specification 
+--- !ruby/object:Gem::Specification
 name: stomp
-version: !ruby/object:Gem::Version 
-  hash: 13
-  prerelease: false
-  segments: 
-  - 1
-  - 2
-  - 9
-  version: 1.2.9
+version: !ruby/object:Gem::Version
+  version: 1.2.14
+  prerelease: 
 platform: ruby
-authors: 
+authors:
 - Brian McCallister
 - Marius Mathiesen
 - Thiago Morello
@@ -17,37 +12,36 @@ authors:
 autorequire: 
 bindir: bin
 cert_chain: []
-
-date: 2013-03-28 00:00:00 -04:00
-default_executable: 
-dependencies: 
-- !ruby/object:Gem::Dependency 
+date: 2013-08-19 00:00:00.000000000 Z
+dependencies:
+- !ruby/object:Gem::Dependency
   name: rspec
-  prerelease: false
-  requirement: &id001 !ruby/object:Gem::Requirement 
+  requirement: !ruby/object:Gem::Requirement
     none: false
-    requirements: 
-    - - ">="
-      - !ruby/object:Gem::Version 
-        hash: 5
-        segments: 
-        - 2
-        - 3
-        version: "2.3"
+    requirements:
+    - - ! '>='
+      - !ruby/object:Gem::Version
+        version: '2.3'
   type: :development
-  version_requirements: *id001
-description: Ruby client for the Stomp messaging protocol.  Note that this gem is no longer supported on rubyforge.
-email: 
+  prerelease: false
+  version_requirements: !ruby/object:Gem::Requirement
+    none: false
+    requirements:
+    - - ! '>='
+      - !ruby/object:Gem::Version
+        version: '2.3'
+description: Ruby client for the Stomp messaging protocol.  Note that this gem is
+  no longer supported on rubyforge.
+email:
 - brianm at apache.org
 - marius at stones.com
 - morellon at gmail.com
 - allard.guy.m at gmail.com
-executables: 
+executables:
 - catstomp
 - stompcat
 extensions: []
-
-extra_rdoc_files: 
+extra_rdoc_files:
 - CHANGELOG.rdoc
 - LICENSE
 - README.rdoc
@@ -99,8 +93,9 @@ extra_rdoc_files:
 - test/test_helper.rb
 - test/test_message.rb
 - test/test_ssl.rb
+- test/test_urlogin.rb
 - test/tlogger.rb
-files: 
+files:
 - CHANGELOG.rdoc
 - LICENSE
 - README.rdoc
@@ -148,6 +143,7 @@ files:
 - lib/stomp/message.rb
 - lib/stomp/sslparams.rb
 - lib/stomp/version.rb
+- notes/heartbeat_readme.txt
 - spec/client_shared_examples.rb
 - spec/client_spec.rb
 - spec/connection_spec.rb
@@ -161,40 +157,31 @@ files:
 - test/test_helper.rb
 - test/test_message.rb
 - test/test_ssl.rb
+- test/test_urlogin.rb
 - test/tlogger.rb
-has_rdoc: true
 homepage: https://github.com/stompgem/stomp
 licenses: []
-
 post_install_message: 
 rdoc_options: []
-
-require_paths: 
+require_paths:
 - lib
-required_ruby_version: !ruby/object:Gem::Requirement 
+required_ruby_version: !ruby/object:Gem::Requirement
   none: false
-  requirements: 
-  - - ">="
-    - !ruby/object:Gem::Version 
-      hash: 3
-      segments: 
-      - 0
-      version: "0"
-required_rubygems_version: !ruby/object:Gem::Requirement 
+  requirements:
+  - - ! '>='
+    - !ruby/object:Gem::Version
+      version: '0'
+required_rubygems_version: !ruby/object:Gem::Requirement
   none: false
-  requirements: 
-  - - ">="
-    - !ruby/object:Gem::Version 
-      hash: 3
-      segments: 
-      - 0
-      version: "0"
+  requirements:
+  - - ! '>='
+    - !ruby/object:Gem::Version
+      version: '0'
 requirements: []
-
 rubyforge_project: 
-rubygems_version: 1.3.7
+rubygems_version: 1.8.25
 signing_key: 
 specification_version: 3
 summary: Ruby client for the Stomp messaging protocol
 test_files: []
-
+has_rdoc: 
diff --git a/notes/heartbeat_readme.txt b/notes/heartbeat_readme.txt
new file mode 100644
index 0000000..268d79f
--- /dev/null
+++ b/notes/heartbeat_readme.txt
@@ -0,0 +1,169 @@
+Usage notes and comments follow (sorry for the length here, please read carefully).
+
+Write failures:  there is a single type of write failure, and it occurs when 
+an exception of some sort is raised during Heartbeat write.
+This is the only type of write failure that can be detected. 
+If :reliable is true, an exception on heartbeat write will always causes a fail 
+over attempt.
+
+Read failures:  this is actually more complex than originally envisioned. 
+There are really three distinct types of read 'failures':
+
+1) An exception is thrown during Heartbeat read.  If :reliable is true, this 
+   always causes a fail over attempt.
+
+2) Heartbeat reads can not obtain the read_semaphore lock.  This will occur 
+   when the main connection thread has:
+    -- Called Connection#receive
+    -- Only heartbeats but no Stomp frames are on the inbound wire
+    -- Last Heartbeat read time is being maintained by the #receive attempt
+
+3) Heartbeat reads obtain the read_semaphore lock, but the socket shows no 
+   data is available (by IO#ready?).  This will occur when:
+    -- The main thread has not called Connection#receive (the thread is doing other work)
+    -- There is no heartbeat to receive (IO#ready? indicates no input data available)
+
+The requirement to handle cases 2) and 3) results in not one, but two different 
+counters being taken in to consideration.
+
+To handle case 2) add to the connect hash:
+
+:max_hbrlck_fails => x # x is a number strictly greater than 0.  Default is 0, 
+which disables the functionality.
+
+A running count of this failure type is maintained in the HB read thread.  The 
+count is incremented when:
+
+-- Lock obtain fails, *and*
+-- A heartbeat is 'late'
+
+The count is reset to 0 whenever:
+
+-- A heart beat has been received on a timely basis
+
+When the running count *reaches* the value specified in :max_hbrlck_fails, a 
+fail over attempt is initiated.
+
+Advice:  do *not* set this to 1 (in order to avoid fail overs on a transient 
+error).
+
+To handle case 3) add to the connect hash:
+
+:max_hbread_fails => y # y is a number strictly greater than 0.  Default is 0, 
+which disables the functionality.
+
+A running count of this failure type is maintained in the HB read thread.  
+The count is incremented when:
+
+-- Lock obtain succeeds, *and*
+-- IO#ready? indicates no data available
+
+The count is reset to 0 under two conditions:
+
+Condition 1)
+  --  A heartbeat is late, *and*
+  -- Lock obtain succeeds, *and*
+  -- IO#ready? indicates data is available, *and*
+  -- A single character is read from the wire
+
+Condition 2)
+  -- A heartbeat has been received in a timely manner (perhaps by the main thread)
+
+When the running count *reaches* the value specified in :max_hbread_fails, 
+a fail over attempt is initiated.
+
+Advice:  do *not* set this to 1 (in order to avoid fail overs on a transient 
+error).
+
+-----------------------------------------------------------
+
+General advice:
+
+Set your heartbeat intervals to the maximum possible to obtain your desired
+behavior.  Do *not* set them at extremely low values even if the broker allows
+that.  An absurd example:
+
+heart-beat:1,1
+
+which will likely not work well.
+
+-----------------------------------------------------------
+
+General notes:
+
+In your real world apps, think about whether one or both of these parameters 
+are appropriate.
+
+Please add the:
+
+-- on_hbread_fail
+-- on_hbwrite_fail
+
+methods to a callback logger.  In those methods show 'ticker_data.inspect' 
+output.  We would want that log output in future problem reports.
+
+We make the comment about not setting these values to 1 because every server 
+we test with is prone to transient (single event) failures, particularly for 
+client HB reads.
+
+We have done a variety of informal tests here, using both server kill and 
+packet drop strategies as appropriate.  We believe more real world testing is
+required.
+
+-----------------------------------------------------------
+
+08/07/2013
+
+Issue #63 related, specifically fast send heart beats are being used and 
+spurious fail overs occur in rapid succession.
+
+Background:
+
+Fail over from heartbeat failures was introduced in gem version 1.2.10.
+
+Subsequently:
+
+This issue has been observed and documented in the following environment:
+
+-- JRuby engine 1.7.4 *and*
+-- ActiveMQ 5.8.0 *and*
+-- 'fast' client send heartbeats
+
+Heartbeat sends were at 2000ms.
+
+At this point in time, fast send heart beats and spurious fail overs have 
+*not* been observed using:
+
+-- Any native RUBY_ENGINE and ActiveMQ
+-- Any native RUBY_ENGINE and Apollo (client send rates are limited by default)
+-- Any native RUBY_ENGINE and RabbitMQ
+-- JRuby and Apollo (client send rates are limited by default)
+-- JRuby and RabbitMQ
+
+Note that 'fast' will depend on your use case for heartbeats.  Observations
+are that sending heartbeat times less than 5000ms might be considered 'fast'
+in the targeted environment.
+
+The solution / bypass being put in place as of the above date was developed
+through experimentation and is as follows:
+
+- Add 'adjustment' logic to the heartbeat sender (thanks to ppaul for this idea).
+- Re-introduce tolerance logic removed in d922fa.
+- Add a new connection hash parameter to adjust heartbeat sends.
+
+The newly introduced connection hash parameter is:
+
+:fast_hbs_adjust => 0.0 # The default, no adjustment to sender sleep times (sec)
+
+Recommendation for gem users that:
+
+- Use fast send heartbeats
+- Actually notice spurious fail overs
+
+is to provide a very sender sleep time adjustment when connecting.  Examples:
+
+:fast_hbs_adjust => 0.05 # 50 milliseconds
+:fast_hbs_adjust => 0.10 # 100 milliseconds
+
+As usual, YMMV.
+
diff --git a/spec/client_spec.rb b/spec/client_spec.rb
index b8721f7..35c5c5b 100644
--- a/spec/client_spec.rb
+++ b/spec/client_spec.rb
@@ -254,7 +254,7 @@ describe Stomp::Client do
     end
     
     it "should properly parse a URL with failover:" do
-      url = "failover:(stomp://login1:passcode1@localhost:61616,stomp://login2:passcode2@remotehost1:61617),stomp://login3:passcode3@remotehost2:61618)"
+      url = "failover:(stomp://login1:passcode1@localhost:61616,stomp://login2:passcode2@remotehost1:61617,stomp://login3:passcode3@remotehost2:61618)"
       
       @parameters[:hosts] = [
         {:login => "login1", :passcode => "passcode1", :host => "localhost", :port => 61616, :ssl => false},
@@ -283,7 +283,7 @@ describe Stomp::Client do
     end
     
     it "should properly parse a URL with user and/or password blank" do
-      url = "failover:(stomp://:@localhost:61616,stomp://:@remotehost:61617)"
+      url = "failover:(stomp://@localhost:61616,stomp://@remotehost:61617)"
       
       @parameters[:hosts] = [
         {:login => "", :passcode => "", :host => "localhost", :port => 61616, :ssl => false},
@@ -302,7 +302,7 @@ describe Stomp::Client do
       
       url = "failover:(stomp://login1:passcode1@localhost:61616,stomp://login2:passcode2@remotehost:61617)?#{query}"
       
-      #backup and timeout are not implemented yet
+      #
       @parameters = {  
         :initial_reconnect_delay => 5.0,
         :max_reconnect_delay => 60.0,
diff --git a/spec/connection_spec.rb b/spec/connection_spec.rb
index 4cae83c..1289764 100644
--- a/spec/connection_spec.rb
+++ b/spec/connection_spec.rb
@@ -25,7 +25,10 @@ describe Stomp::Connection do
       :hbser => false,
       :stompconn => false,
       :usecrlf => false,
-    }
+      :max_hbread_fails => 0,
+      :max_hbrlck_fails => 0,
+      :fast_hbs_adjust => 0.0,
+   }
         
     #POG:
     class Stomp::Connection
@@ -87,9 +90,12 @@ describe Stomp::Connection do
         "backOffMultiplier" => 2,
         "maxReconnectAttempts" => 0,
         "randomize" => false,
-        "connect_timeout" => 0,
-        "parse_timeout" => 5,
+        "connectTimeout" => 0,
+        "parseTimeout" => 5,
         "usecrlf" => false,
+        :maxHbreadFails => 0,
+        :maxHbrlckFails => 0,
+        :fastHbsAdjust => 0.0,
       }
       
       @connection = Stomp::Connection.new(used_hash)
@@ -211,22 +217,23 @@ describe Stomp::Connection do
         @message.headers[:retry_count].should == 5
       end
       
-      it "should not send the message to the dead letter queue as persistent if redeliveries equal max redeliveries" do
+      it "should not send the message to the dead letter queue as persistent if retry_count is less than max redeliveries" do
         max_redeliveries = 5
         dead_letter_queue = "/queue/Dead"
         
-        @message.headers["retry_count"] = max_redeliveries
+        @message.headers["retry_count"] = max_redeliveries - 1
         transaction_id = "transaction-#{@message.headers["message-id"]}-#{@message.headers["retry_count"]}"
         @retry_headers = @retry_headers.merge :transaction => transaction_id, :retry_count => @message.headers["retry_count"] + 1
         @connection.should_receive(:publish).with(@message.headers["destination"], @message.body, @retry_headers)
         @connection.unreceive @message, :dead_letter_queue => dead_letter_queue, :max_redeliveries => max_redeliveries
       end
       
+      # If the retry_count has reached max_redeliveries, then we're done.
       it "should send the message to the dead letter queue as persistent if max redeliveries have been reached" do
         max_redeliveries = 5
         dead_letter_queue = "/queue/Dead"
         
-        @message.headers["retry_count"] = max_redeliveries + 1
+        @message.headers["retry_count"] = max_redeliveries
         transaction_id = "transaction-#{@message.headers["message-id"]}-#{@message.headers["retry_count"]}"
         @retry_headers = @retry_headers.merge :persistent => true, :transaction => transaction_id, :retry_count => @message.headers["retry_count"] + 1, :original_destination=> @message.headers["destination"]
         @connection.should_receive(:publish).with(dead_letter_queue, @message.body, @retry_headers)
@@ -268,7 +275,9 @@ describe Stomp::Connection do
       
       before(:each) do
         ssl_parameters = {:hosts => [{:login => "login2", :passcode => "passcode2", :host => "remotehost", :ssl => true}]}
-        @ssl_socket = mock(:ssl_socket, :puts => nil, :write => nil, :setsockopt => nil, :flush => true)
+        @ssl_socket = mock(:ssl_socket, :puts => nil, :write => nil, 
+          :setsockopt => nil, :flush => true)
+        @ssl_socket.stub!(:sync_close=)
         
         TCPSocket.should_receive(:open).and_return @tcp_socket
         OpenSSL::SSL::SSLSocket.should_receive(:new).and_return(@ssl_socket)
@@ -338,6 +347,9 @@ describe Stomp::Connection do
           :closed_check => true,
           :hbser => false,
           :stompconn => false,
+          :max_hbread_fails => 0,
+          :max_hbrlck_fails => 0,
+          :fast_hbs_adjust => 0.0,
         }
         
         used_hash =  {
@@ -363,7 +375,6 @@ describe Stomp::Connection do
           :back_off_multiplier => 3,
           :max_reconnect_attempts => 10,
           :randomize => true,
-          :backup => false,
           :reliable => false,
           :connect_timeout => 0,
           :parse_timeout => 20,
@@ -372,9 +383,12 @@ describe Stomp::Connection do
           :max_redeliveries => 10,
           :dmh => false,
           :closed_check => true,
-          :hbser => false,
-          :stompconn => false,
-          :usecrlf => false,
+          :hbser => true,
+          :stompconn => true,
+          :usecrlf => true,
+          :max_hbread_fails => 123,
+          :max_hbrlck_fails => 456,
+          :fast_hbs_adjust => 0.2,
         }
         
         @connection = Stomp::Connection.new(used_hash)
@@ -423,7 +437,14 @@ describe Stomp::Connection do
       
       @connection.instance_variable_set(:@connection_attempts, limit)
       @connection.send(:max_reconnect_attempts?).should be_true
+    end
+
+    # These should be raised for the user to deal with
+    it "should not rescue MaxReconnectAttempts" do
+      @connection = Stomp::Connection.new(@parameters)
+      @connection.stub(:socket).and_raise(Stomp::Error::MaxReconnectAttempts)
       
+      expect { @connection.receive() }.to raise_error
     end
   end
 
diff --git a/stomp.gemspec b/stomp.gemspec
index 494b90f..17111fd 100644
--- a/stomp.gemspec
+++ b/stomp.gemspec
@@ -5,11 +5,11 @@
 
 Gem::Specification.new do |s|
   s.name = %q{stomp}
-  s.version = "1.2.9"
+  s.version = "1.2.14"
 
   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{2013-03-28}
+  s.date = %q{2013-08-19}
   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"]
@@ -65,6 +65,7 @@ Gem::Specification.new do |s|
     "test/test_helper.rb",
     "test/test_message.rb",
     "test/test_ssl.rb",
+    "test/test_urlogin.rb",
     "test/tlogger.rb"
   ]
   s.files = [
@@ -115,6 +116,7 @@ Gem::Specification.new do |s|
     "lib/stomp/message.rb",
     "lib/stomp/sslparams.rb",
     "lib/stomp/version.rb",
+    "notes/heartbeat_readme.txt",
     "spec/client_shared_examples.rb",
     "spec/client_spec.rb",
     "spec/connection_spec.rb",
@@ -128,6 +130,7 @@ Gem::Specification.new do |s|
     "test/test_helper.rb",
     "test/test_message.rb",
     "test/test_ssl.rb",
+    "test/test_urlogin.rb",
     "test/tlogger.rb"
   ]
   s.homepage = %q{https://github.com/stompgem/stomp}
diff --git a/test/test_client.rb b/test/test_client.rb
index 7a258f6..756fbdf 100644
--- a/test/test_client.rb
+++ b/test/test_client.rb
@@ -23,7 +23,7 @@ class TestClient < Test::Unit::TestCase
   end
 
   def teardown
-    @client.close if @client.open? # allow tests to close
+    @client.close if @client && @client.open? # allow tests to close
   end
 
   # Test poll works.
@@ -50,7 +50,7 @@ class TestClient < Test::Unit::TestCase
     sleep 0.01 until receipt
     assert_not_nil receipt.headers['receipt-id']
     checkEmsg(@client)
-  end unless ENV['STOMP_RABBIT'] # TODO: why does Rabbit 1.1 fail ?
+  end
 
   # Test Client subscribe
   def test_asynch_subscribe
@@ -160,61 +160,133 @@ class TestClient < Test::Unit::TestCase
   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
+  # New client uses ack => client.
+  def test_tran_ack_abrt_newcli_cli
+    @client.close if @client && @client.open? # allow tests to close
+    @client = get_client()
+    q = make_destination
+    data = message_text
+    @client.publish q, data
 
     @client.begin 'tx1'
     message = nil
     sid = nil
     if @client.protocol() == Stomp::SPL_10
-      @client.subscribe(make_destination, :ack => 'client') {|m| message = m}
-    else
+      @client.subscribe(q, :ack => 'client') {|m| message = m}
+    else # 1.1 and 1.2 are the same for this
       sid = @client.uuid()
-      @client.subscribe(make_destination, :ack => 'client', :id => sid) {|m| message = m}
+      @client.subscribe(q, :ack => 'client', :id => sid) {|m| message = m}
     end
     sleep 0.01 until message
-    assert_equal message_text, message.body
+    assert_equal data, message.body
     assert_nothing_raised {
-      if @client.protocol() == Stomp::SPL_10
-        @client.acknowledge message, :transaction => 'tx1'
-      else
-        @client.acknowledge message, :transaction => 'tx1', :subscription => sid
+      case @client.protocol()
+        when Stomp::SPL_10
+          @client.acknowledge message, :transaction => 'tx1'
+          checkEmsg(@client)
+        when Stomp::SPL_11
+          @client.acknowledge message, :transaction => 'tx1', :subscription => message.headers['subscription']
+          checkEmsg(@client)
+        else # 1.2+
+          @client.acknowledge message, :transaction => 'tx1', :id => message.headers['ack']
+          checkEmsg(@client)
       end
-      message = nil
-      @client.abort 'tx1'
+      message = nil # reset
+      @client.abort 'tx1' # now abort
     }
     checkEmsg(@client)
     # lets recreate the connection
-    teardown
-    setup
+    @client.close
+    @client = get_client()
     sid = nil
+    message2 = nil
+    @client.begin 'tx2'
     assert_nothing_raised {
       if @client.protocol() == Stomp::SPL_10
-        @client.subscribe(make_destination, :ack => 'client') {|m| message = m}
-      else
+        @client.subscribe(q, :ack => 'client') {|m| message2 = m}
+      else # 1.1 and 1.2 are the same for this
         sid = @client.uuid()
-        @client.subscribe(make_destination, :ack => 'client', :id => sid) {|m| message = m}
+        @client.subscribe(q, :ack => 'client', :id => sid) {|m| message2 = m}
       end
     }
-    Timeout::timeout(4) do
-      sleep 0.01 until message
-    end
+    sleep 0.01 until message2
     assert_not_nil message
-    assert_equal message_text, message.body
+    assert_equal data, message2.body
     assert_nothing_raised {
-    @client.begin 'tx2'
       case @client.protocol()
         when Stomp::SPL_10
-          @client.acknowledge message, :transaction => 'tx2'
+          @client.acknowledge message2, :transaction => 'tx2'
+          checkEmsg(@client)
         when Stomp::SPL_11
-          @client.acknowledge message, :transaction => 'tx2', :subscription => sid
-        else
-          # Skip 1.2+ for now.  Current 1.2 broker appears to think this is 
-          # already ACK'd.
+          @client.acknowledge message2, :transaction => 'tx2', :subscription => message2.headers['subscription']
+          checkEmsg(@client)
+        else # 1.2+
+          @client.acknowledge message2, :transaction => 'tx2', :id => message2.headers['ack']
+          checkEmsg(@client)
       end
       @client.commit 'tx2'
     }
     checkEmsg(@client)
+    @client.close
+  end
+
+  # Test transaction publish and abort, receive with new client.
+  # New client uses ack => auto.
+  def test_tran_ack_abrt_newcli_auto
+    @client.close if @client && @client.open? # allow tests to close
+    @client = get_client()
+    q = make_destination
+    data = message_text
+    @client.publish q, data
+
+    @client.begin 'tx1'
+    message = nil
+    sid = nil
+    if @client.protocol() == Stomp::SPL_10
+      @client.subscribe(q, :ack => 'client') {|m| message = m}
+    else # 1.1 and 1.2 are the same for this
+      sid = @client.uuid()
+      @client.subscribe(q, :ack => 'client', :id => sid) {|m| message = m}
+    end
+    sleep 0.01 until message
+    assert_equal data, message.body
+    assert_nothing_raised {
+      case @client.protocol()
+        when Stomp::SPL_10
+          @client.acknowledge message, :transaction => 'tx1'
+          checkEmsg(@client)
+        when Stomp::SPL_11
+          @client.acknowledge message, :transaction => 'tx1', :subscription => message.headers['subscription']
+          checkEmsg(@client)
+        else # 1.2+
+          @client.acknowledge message, :transaction => 'tx1', :id => message.headers['ack']
+          checkEmsg(@client)
+      end
+      message = nil # reset
+      @client.abort 'tx1' # now abort
+    }
+    checkEmsg(@client)
+    # lets recreate the connection
+    @client.close
+
+    @client = get_client()
+    sid = nil
+    message2 = nil
+    @client.begin 'tx2'
+    assert_nothing_raised {
+      if @client.protocol() == Stomp::SPL_10
+        @client.subscribe(q, :ack => 'auto') {|m| message2 = m}
+      else # 1.1 and 1.2 are the same for this
+        sid = @client.uuid()
+        @client.subscribe(q, :ack => 'auto', :id => sid) {|m| message2 = m}
+      end
+    }
+    sleep 0.01 until message2
+    assert_not_nil message2
+    assert_equal data, message2.body
+    @client.commit 'tx2'
+    checkEmsg(@client)
+    @client.close
   end
 
   # Test that subscription destinations must be unique for a Client.
@@ -313,55 +385,65 @@ class TestClient < Test::Unit::TestCase
     checkEmsg(@client)
   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
+  # Test transaction with client side reacknowledge.
+  def test_transaction_with_client_side_reack
+    @client.close if @client && @client.open? # allow tests to close
+    @client = get_client()
+    q = make_destination
+    data = message_text
+    @client.publish q, data
 
     @client.begin 'tx1'
     message = nil
     sid = nil
     if @client.protocol() == Stomp::SPL_10
-      @client.subscribe(make_destination, :ack => 'client') { |m| message = m }
+      @client.subscribe(q, :ack => 'client') { |m| message = m }
     else
       sid = @client.uuid()
-      @client.subscribe(make_destination, :ack => 'client', :id => sid) { |m| message = m }
+      @client.subscribe(q, :ack => 'client', :id => sid) { |m| message = m }
     end
-
     sleep 0.1 while message.nil?
-
-    assert_equal message_text, message.body
-    if @client.protocol() == Stomp::SPL_10
-      @client.acknowledge message, :transaction => 'tx1'
-    else
-      @client.acknowledge message, :transaction => 'tx1', :subscription => sid
+    assert_equal data, message.body
+    case @client.protocol()
+      when Stomp::SPL_10
+        @client.acknowledge message, :transaction => 'tx1'
+        checkEmsg(@client)
+      when Stomp::SPL_11
+        @client.acknowledge message, :transaction => 'tx1', :subscription => message.headers['subscription']
+        checkEmsg(@client)
+      else # 1.2+
+        @client.acknowledge message, :transaction => 'tx1', :id => message.headers['ack']
+        checkEmsg(@client)
     end
     message = nil
     @client.abort 'tx1'
-
+    # Wait for redlivery (Client logic)
     sleep 0.1 while message.nil?
-
     assert_not_nil message
-    assert_equal message_text, message.body
-
+    assert_equal data, message.body
     assert_nothing_raised {
       @client.begin 'tx2'
       case @client.protocol()
         when Stomp::SPL_10
           @client.acknowledge message, :transaction => 'tx2'
+          checkEmsg(@client)
         when Stomp::SPL_11
-          @client.acknowledge message, :transaction => 'tx2', :subscription => sid
-        else
-          # Skip 1.2+ for now.  Current 1.2 broker appears to think this is 
-          # already ACK'd.
+          @client.acknowledge message, :transaction => 'tx2', :subscription => message.headers['subscription']
+          checkEmsg(@client)
+        else # 1.2+
+          @client.acknowledge message, :transaction => 'tx2', :id => message.headers['ack']
+          checkEmsg(@client)
       end
       @client.commit 'tx2'
     }
     checkEmsg(@client)
+    @client.close
+    @client = nil
   end
 
   # Test that a connection frame is received.
   def test_connection_frame
-  	assert_not_nil @client.connection_frame
+    assert_not_nil @client.connection_frame
     checkEmsg(@client)
   end unless RUBY_ENGINE =~ /jruby/
 
@@ -523,6 +605,41 @@ class TestClient < Test::Unit::TestCase
     end
   end
 
+  # test JRuby detection
+  def test_jruby_presence
+    if defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /jruby/
+      assert @client.jruby?
+    else
+      assert !@client.jruby?
+    end
+  end
+
+  # test max redeliveries is not broken (6c2c1c1)
+  def test_max_redeliveries
+    @client.close
+    rdmsg = "To Be Redelivered"
+    dest = make_destination
+    [1, 2, 3].each do |max_re|
+      @client = get_client()
+      sid = @client.uuid()
+      received = nil
+      rm_actual = 0
+      sh = @client.protocol() == Stomp::SPL_10 ?  {} : {:id => sid}
+      @client.subscribe(dest, sh) {|msg|
+        rm_actual += 1
+        @client.unreceive(msg, :max_redeliveries => max_re)
+        received = msg if rm_actual - 1 == max_re
+      }
+      @client.publish(dest, rdmsg)
+      sleep 0.01 until received
+      assert_equal rdmsg, received.body
+      sleep 0.5
+      @client.unsubscribe dest, sh
+      assert_equal max_re, rm_actual - 1
+      @client.close
+    end
+  end
+
   private
     def message_text
       name = caller_method_name unless name
diff --git a/test/test_connection.rb b/test/test_connection.rb
index 3a08b62..5659186 100644
--- a/test/test_connection.rb
+++ b/test/test_connection.rb
@@ -115,7 +115,7 @@ class TestConnection < Test::Unit::TestCase
       # matching the message-id for the MESSAGE being acknowledged and 
       # subscription, which MUST be set to match the value of the subscription's 
       # id header.
-      @conn.ack msg.headers['message-id'], :subscription => sid
+      @conn.ack msg.headers['message-id'], :subscription => msg.headers['subscription']
     }
     checkEmsg(@conn)
   end
@@ -484,10 +484,11 @@ class TestConnection < Test::Unit::TestCase
   def test_conn10_simple
     @conn.disconnect
     #
+    vhost = ENV['STOMP_RABBIT'] ? "/" : host
     hash = { :hosts => [ 
       {:login => user, :passcode => passcode, :host => host, :port => port, :ssl => false},
       ],
-      :connect_headers => {"accept-version" => "1.0", "host" => host},
+      :connect_headers => {"accept-version" => "1.0", "host" => vhost},
       :reliable => false,
     }
     c = nil
@@ -499,7 +500,7 @@ class TestConnection < Test::Unit::TestCase
     hash = { :hosts => [ 
       {:login => user, :passcode => passcode, :host => host, :port => port, :ssl => false},
       ],
-      :connect_headers => {"accept-version" => "3.14159,1.0,12.0", "host" => host},
+      :connect_headers => {"accept-version" => "3.14159,1.0,12.0", "host" => vhost},
       :reliable => false,
     }
     c = nil
@@ -509,5 +510,14 @@ class TestConnection < Test::Unit::TestCase
     c.disconnect if c
   end
 
+  # test JRuby detection
+  def test_jruby_presence
+    if defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /jruby/
+      assert @conn.jruby
+    else
+      assert !@conn.jruby
+    end
+  end
+
 end
 
diff --git a/test/test_connection1p.rb b/test/test_connection1p.rb
index a8c22ed..d149cb6 100644
--- a/test/test_connection1p.rb
+++ b/test/test_connection1p.rb
@@ -28,7 +28,7 @@ class TestConnection1P < Test::Unit::TestCase
     assert @conn.open?
   end
 
-  # Test missing connect headers.
+  # Test missing connect headers - part 1.
   def test_conn_1p_0010
     @conn.disconnect
     #
@@ -43,6 +43,33 @@ class TestConnection1P < Test::Unit::TestCase
     end    
   end
 
+  # Test missing connect headers - part 2.
+  def test_conn_1p_0015
+    @conn.disconnect
+    #
+    cha = {:host => "localhost"}
+    hash = { :hosts => [ 
+      {:login => user, :passcode => passcode, :host => host, :port => port, :ssl => nil},
+      ],
+      :reliable => true, # Note, issue #57 discussion
+      :connect_headers => cha,
+      :stompconn => get_stomp_conn(),
+      :usecrlf => get_crlf(),
+      :initial_reconnect_delay => 0.1,
+      :max_reconnect_delay => 30,
+      :use_exponential_back_off => true,
+      :back_off_multiplier => 2,
+      :max_reconnect_attempts => 10,
+    }
+    assert_raise Stomp::Error::ProtocolErrorConnect do
+      conn = Stomp::Connection.open(hash)
+    end
+    hash[:connect_headers] = {"accept-version" => "1.1"}
+    assert_raise Stomp::Error::ProtocolErrorConnect do
+      conn = Stomp::Connection.open(hash)
+    end
+  end
+
   # Test requesting only a 1.0 connection.
   def test_conn_1p_0020
     @conn.disconnect
diff --git a/test/test_helper.rb b/test/test_helper.rb
index b422519..f1ee9df 100644
--- a/test/test_helper.rb
+++ b/test/test_helper.rb
@@ -84,7 +84,7 @@ module TestBase
   # 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
+    ssl_params = Stomp::SSLParams.new(:use_ruby_ciphers => jruby?())
     hash = { :hosts => [ 
       {:login => user, :passcode => passcode, :host => host, :port => ssl_port, :ssl => ssl_params},
       ],
@@ -164,5 +164,10 @@ module TestBase
     end
   end
 
+  # Check for JRuby before a connection exists
+  def jruby?()
+    jr = defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /jruby/ ? true : false
+  end
+
 end
 
diff --git a/test/test_urlogin.rb b/test/test_urlogin.rb
new file mode 100644
index 0000000..1f50c15
--- /dev/null
+++ b/test/test_urlogin.rb
@@ -0,0 +1,86 @@
+# -*- encoding: utf-8 -*-
+
+if Kernel.respond_to?(:require_relative)
+  require_relative("test_helper")
+else
+  $:.unshift(File.dirname(__FILE__))
+  require 'test_helper'
+end
+
+=begin
+
+  Main class for testing Stomp::Client URL based Logins.
+
+=end
+class TestURLLogins < Test::Unit::TestCase
+  include TestBase
+  
+  def setup
+    hostname = host()
+    portnum = port()
+    sslpn = ssl_port()
+    @tdstomp = [ 
+          "stomp://guestl:guestp@#{hostname}:#{portnum}",
+          "stomp://#{hostname}:#{portnum}",
+          "stomp://@#{hostname}:#{portnum}",
+          "stomp://f@#$$%^&*()_+=o.o:@#{hostname}:#{portnum}",
+          'stomp://f@#$$%^&*()_+=o.o::b~!@#$%^&*()+-_=?:<>,.@@' + hostname + ":#{portnum}",
+    ]
+    @tdfailover = [
+      "failover://(stomp://#{hostname}:#{portnum})",
+      "failover://(stomp+ssl://#{hostname}:#{sslpn})",
+      "failover://(stomp://#{hostname}:#{portnum})",
+      "failover://(stomp://#{hostname}:#{portnum})?whatup=doc&coyote=kaboom",
+      "failover://(stomp://#{hostname}:#{portnum})?whatup=doc",
+      "failover://(stomp://#{hostname}:#{portnum})?whatup=doc&coyote=kaboom&randomize=true",
+      'failover://(stomp://f@#$$%^&*()_+=o.o::b~!@#$%^&*()+-_=?:<>,.@@' + "localhost" + ":#{portnum}" + ")",
+      'failover://(stomp://f@#$$%^&*()_+=o.o::b~!@#$%^&*()+-_=:<>,.@@' + "localhost" + ":#{portnum}" + ")",
+      'failover://(stomp://f@#$$%^&*()_+=o.o::b~!@#$%^&*()+-_=?:<>,.@@' + "localhost" + ":#{portnum}" + ")?a=b",
+      'failover://(stomp://f@#$$%^&*()_+=o.o::b~!@#$%^&*()+-_=:<>,.@@' + "localhost" + ":#{portnum}" + ")?c=d&e=f",
+      "failover://(stomp://usera:passa@#{hostname}:#{portnum})",
+      "failover://(stomp+ssl://usera:passa@#{hostname}:#{sslpn})",
+      "failover://(stomp://usera:@#{hostname}:#{portnum})",
+      "failover://(stomp://#{hostname}:#{portnum},stomp://#{hostname}:#{portnum})",
+      "failover://(stomp://usera:passa@#{hostname}:#{portnum},stomp://#{hostname}:#{portnum})",
+      "failover://(stomp://usera:@#{hostname}:#{portnum},stomp://#{hostname}:#{portnum})",
+      "failover://(stomp://usera:@#{hostname}:#{portnum},stomp+ssl://#{hostname}:#{sslpn})",
+      "failover://(stomp://#{hostname}:#{portnum},stomp://#{hostname}:#{portnum})?a=b&c=d",
+      "failover://(stomp://#{hostname}:#{portnum},stomp://#{hostname}:#{portnum})?a=b&c=d&connect_timeout=2020",
+    ]
+
+    @badparms = "failover://(stomp://#{hostname}:#{portnum})?a=b&noequal"
+  end
+
+  def teardown
+    @client.close if @client && @client.open? # allow tests to close
+  end
+
+  # test stomp:// URLs
+  def test_0010_stomp_urls()
+    @tdstomp.each_with_index do |url, ndx|
+      c = Stomp::Client.new(url)
+      assert !c.nil?, url
+      assert c.open?, url
+      c.close
+    end
+  end
+
+  # test failover:// urls
+  def test_0020_failover_urls()
+    @tdfailover.each_with_index do |url, ndx|
+      c = Stomp::Client.new(url)
+      assert !c.nil?, url
+      assert c.open?, url
+      c.close
+    end
+  end
+
+  # test failover:// with bad parameters
+  def test_0020_failover_badparms()
+    assert_raise(Stomp::Error::MalformedFailoverOptionsError) {
+      c = Stomp::Client.new(@badparms)
+    }
+  end
+
+end unless ENV['STOMP_RABBIT']
+
diff --git a/test/tlogger.rb b/test/tlogger.rb
index c6ea91f..99231a4 100644
--- a/test/tlogger.rb
+++ b/test/tlogger.rb
@@ -6,6 +6,8 @@ require 'logger'	# use the standard Ruby logger .....
 
 Callback logger for Stomp 1.1+ heartbeat tests.
 
+See the examples directory for a more robust logger example.
+
 =end
 class Tlogger
 
@@ -31,7 +33,7 @@ class Tlogger
   def on_hbwrite_fail(parms, ticker_data)
     begin
       @log.debug "Hbwritef Parms #{info(parms)}"
-      @log.debug "Hbwritef Result #{ticker_data}"
+      @log.debug "Hbwritef Result #{ticker_data.inspect}"
     rescue
       @log.debug "Hbwritef oops"
     end
@@ -42,18 +44,18 @@ class Tlogger
   def on_hbread_fail(parms, ticker_data)
     begin
       @log.debug "Hbreadf Parms #{info(parms)}"
-      @log.debug "Hbreadf Result #{ticker_data}"
+      @log.debug "Hbreadf Result #{ticker_data.inspect}"
     rescue
       @log.debug "Hbreadf oops"
     end
   end
 
   # Stomp 1.1+ - heart beat thread fires
-  def on_hbfire(parms, type, time)
+  def on_hbfire(parms, type, firedata)
     begin
       @log.debug "HBfire #{type} " + "=" * 30
       @log.debug "HBfire #{type} Parms #{info(parms)}"
-      @log.debug "HBfire #{type} Time #{time}"
+      @log.debug "HBfire #{type} Firedata #{firedata.inspect}"
     rescue
       @log.debug "HBfire #{type} oops"
     end

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-ruby-extras/ruby-stomp.git



More information about the Pkg-ruby-extras-commits mailing list