stomper 1.0.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (152) hide show
  1. data/.gitignore +5 -0
  2. data/{spec/spec.opts → .rspec} +0 -2
  3. data/Gemfile +4 -0
  4. data/LICENSE +201 -201
  5. data/README.md +130 -0
  6. data/Rakefile +5 -0
  7. data/examples/basic.rb +38 -0
  8. data/examples/events.rb +54 -0
  9. data/features/acking_messages.feature +147 -0
  10. data/features/disconnecting.feature +12 -0
  11. data/features/establish_connection.feature +44 -0
  12. data/features/protocol_version_negotiation.feature +61 -0
  13. data/features/receipts.feature +72 -0
  14. data/features/scopes.feature +32 -0
  15. data/features/secure_connections.feature +38 -0
  16. data/features/send_and_message.feature +28 -0
  17. data/features/steps/acking_messages_steps.rb +39 -0
  18. data/features/steps/disconnecting_steps.rb +8 -0
  19. data/features/steps/establish_connection_steps.rb +74 -0
  20. data/features/steps/frame_transmission_steps.rb +35 -0
  21. data/features/steps/protocol_version_negotiation_steps.rb +15 -0
  22. data/features/steps/receipts_steps.rb +79 -0
  23. data/features/steps/scopes_steps.rb +52 -0
  24. data/features/steps/secure_connections_steps.rb +41 -0
  25. data/features/steps/send_and_message_steps.rb +35 -0
  26. data/features/steps/subscribing_steps.rb +36 -0
  27. data/features/steps/threaded_receiver_steps.rb +8 -0
  28. data/features/steps/transactions_steps.rb +0 -0
  29. data/features/subscribing.feature +151 -0
  30. data/features/support/env.rb +11 -0
  31. data/features/support/header_helpers.rb +12 -0
  32. data/features/support/ssl/README +6 -0
  33. data/features/support/ssl/broker_cert.csr +17 -0
  34. data/features/support/ssl/broker_cert.pem +72 -0
  35. data/features/support/ssl/broker_key.pem +27 -0
  36. data/features/support/ssl/client_cert.csr +17 -0
  37. data/features/support/ssl/client_cert.pem +72 -0
  38. data/features/support/ssl/client_key.pem +27 -0
  39. data/features/support/ssl/demoCA/cacert.pem +17 -0
  40. data/features/support/ssl/demoCA/index.txt +2 -0
  41. data/features/support/ssl/demoCA/index.txt.attr +1 -0
  42. data/features/support/ssl/demoCA/index.txt.attr.old +1 -0
  43. data/features/support/ssl/demoCA/index.txt.old +1 -0
  44. data/features/support/ssl/demoCA/newcerts/01.pem +72 -0
  45. data/features/support/ssl/demoCA/newcerts/02.pem +72 -0
  46. data/features/support/ssl/demoCA/private/cakey.pem +17 -0
  47. data/features/support/ssl/demoCA/serial +1 -0
  48. data/features/support/ssl/demoCA/serial.old +1 -0
  49. data/features/support/test_stomp_server.rb +150 -0
  50. data/features/threaded_receiver.feature +11 -0
  51. data/features/transactions.feature +66 -0
  52. data/lib/stomper.rb +30 -20
  53. data/lib/stomper/connection.rb +442 -102
  54. data/lib/stomper/errors.rb +59 -0
  55. data/lib/stomper/extensions.rb +10 -0
  56. data/lib/stomper/extensions/common.rb +258 -0
  57. data/lib/stomper/extensions/events.rb +213 -0
  58. data/lib/stomper/extensions/heartbeat.rb +101 -0
  59. data/lib/stomper/extensions/scoping.rb +56 -0
  60. data/lib/stomper/frame.rb +54 -0
  61. data/lib/stomper/frame_serializer.rb +217 -0
  62. data/lib/stomper/headers.rb +15 -0
  63. data/lib/stomper/receipt_manager.rb +36 -0
  64. data/lib/stomper/receivers.rb +7 -0
  65. data/lib/stomper/receivers/threaded.rb +71 -0
  66. data/lib/stomper/scopes.rb +9 -0
  67. data/lib/stomper/scopes/header_scope.rb +49 -0
  68. data/lib/stomper/scopes/receipt_scope.rb +44 -0
  69. data/lib/stomper/scopes/transaction_scope.rb +109 -0
  70. data/lib/stomper/sockets.rb +66 -28
  71. data/lib/stomper/subscription_manager.rb +79 -0
  72. data/lib/stomper/support.rb +68 -0
  73. data/lib/stomper/support/1.8/frame_serializer.rb +53 -0
  74. data/lib/stomper/support/1.8/headers.rb +183 -0
  75. data/lib/stomper/support/1.9/frame_serializer.rb +64 -0
  76. data/lib/stomper/support/1.9/headers.rb +172 -0
  77. data/lib/stomper/support/ruby.rb +13 -0
  78. data/lib/stomper/uris.rb +49 -0
  79. data/lib/stomper/version.rb +7 -0
  80. data/spec/spec_helper.rb +13 -9
  81. data/spec/stomper/connection_spec.rb +712 -0
  82. data/spec/stomper/extensions/common_spec.rb +187 -0
  83. data/spec/stomper/extensions/events_spec.rb +78 -0
  84. data/spec/stomper/extensions/heartbeat_spec.rb +103 -0
  85. data/spec/stomper/extensions/scoping_spec.rb +21 -0
  86. data/spec/stomper/frame_serializer_1.8_spec.rb +318 -0
  87. data/spec/stomper/frame_serializer_spec.rb +316 -0
  88. data/spec/stomper/frame_spec.rb +36 -0
  89. data/spec/stomper/headers_spec.rb +224 -0
  90. data/spec/stomper/receipt_manager_spec.rb +91 -0
  91. data/spec/stomper/receivers/threaded_spec.rb +116 -0
  92. data/spec/stomper/scopes/header_scope_spec.rb +42 -0
  93. data/spec/stomper/scopes/receipt_scope_spec.rb +51 -0
  94. data/spec/stomper/scopes/transaction_scope_spec.rb +183 -0
  95. data/spec/stomper/sockets_spec.rb +113 -0
  96. data/spec/stomper/subscription_manager_spec.rb +107 -0
  97. data/spec/stomper/support_spec.rb +69 -0
  98. data/spec/stomper/uris_spec.rb +54 -0
  99. data/spec/stomper_spec.rb +9 -0
  100. data/spec/support/custom_argument_matchers.rb +57 -0
  101. data/spec/support/existential_frame_matchers.rb +19 -0
  102. data/spec/support/frame_header_matchers.rb +10 -0
  103. data/stomper.gemspec +30 -0
  104. metadata +272 -97
  105. data/AUTHORS +0 -21
  106. data/CHANGELOG +0 -20
  107. data/README.rdoc +0 -120
  108. data/lib/stomper/client.rb +0 -34
  109. data/lib/stomper/frame_reader.rb +0 -73
  110. data/lib/stomper/frame_writer.rb +0 -21
  111. data/lib/stomper/frames.rb +0 -39
  112. data/lib/stomper/frames/abort.rb +0 -10
  113. data/lib/stomper/frames/ack.rb +0 -25
  114. data/lib/stomper/frames/begin.rb +0 -11
  115. data/lib/stomper/frames/client_frame.rb +0 -89
  116. data/lib/stomper/frames/commit.rb +0 -10
  117. data/lib/stomper/frames/connect.rb +0 -10
  118. data/lib/stomper/frames/connected.rb +0 -30
  119. data/lib/stomper/frames/disconnect.rb +0 -10
  120. data/lib/stomper/frames/error.rb +0 -21
  121. data/lib/stomper/frames/message.rb +0 -48
  122. data/lib/stomper/frames/receipt.rb +0 -19
  123. data/lib/stomper/frames/send.rb +0 -10
  124. data/lib/stomper/frames/server_frame.rb +0 -38
  125. data/lib/stomper/frames/subscribe.rb +0 -42
  126. data/lib/stomper/frames/unsubscribe.rb +0 -19
  127. data/lib/stomper/open_uri_interface.rb +0 -41
  128. data/lib/stomper/receipt_handlers.rb +0 -23
  129. data/lib/stomper/receiptor.rb +0 -38
  130. data/lib/stomper/subscriber.rb +0 -76
  131. data/lib/stomper/subscription.rb +0 -128
  132. data/lib/stomper/subscriptions.rb +0 -95
  133. data/lib/stomper/threaded_receiver.rb +0 -59
  134. data/lib/stomper/transaction.rb +0 -185
  135. data/lib/stomper/transactor.rb +0 -50
  136. data/lib/stomper/uri.rb +0 -55
  137. data/spec/client_spec.rb +0 -29
  138. data/spec/connection_spec.rb +0 -22
  139. data/spec/frame_reader_spec.rb +0 -37
  140. data/spec/frame_writer_spec.rb +0 -27
  141. data/spec/frames/client_frame_spec.rb +0 -66
  142. data/spec/frames/indirect_frame_spec.rb +0 -45
  143. data/spec/frames/server_frame_spec.rb +0 -85
  144. data/spec/open_uri_interface_spec.rb +0 -132
  145. data/spec/receiptor_spec.rb +0 -35
  146. data/spec/shared_connection_examples.rb +0 -79
  147. data/spec/subscriber_spec.rb +0 -77
  148. data/spec/subscription_spec.rb +0 -157
  149. data/spec/subscriptions_spec.rb +0 -145
  150. data/spec/threaded_receiver_spec.rb +0 -33
  151. data/spec/transaction_spec.rb +0 -139
  152. data/spec/transactor_spec.rb +0 -46
@@ -1,128 +0,0 @@
1
- module Stomper
2
- # A representation of a subscription to a stomp broker destination. The
3
- # attributes +id+, +destination+, +ack+ and +selector+ have the same
4
- # semantic meaning as the headers of a Stomp "SUBSCRIBE" frame with the same
5
- # name.
6
- class Subscription
7
- attr_reader :id, :destination, :ack, :selector
8
-
9
- # Creates a new Subscription instance from the given parameters.
10
- # The +destination_or_options+ parameter can either be a string
11
- # specification of the destination, such as "/queue/target", or a hash
12
- # corresponding to the headers of a "SUBSCRIBE" frame
13
- # (eg: { :destination => "/queue/target", :id => "sub-001", ... })
14
- #
15
- # The optional +subscription_id+ parameter is a string corresponding
16
- # to the name of this subscription. If this parameter is specified, it
17
- # should be unique within the context of a given Stomper::Client, otherwise
18
- # the behavior of the Stomper::Client#unsubscribe method may have unintended
19
- # consequences.
20
- #
21
- # The optional +ack+ parameter specifies the mode that a client
22
- # will use to acknowledge received messages and may be either :client or :auto.
23
- # The default, :auto, does not require the client to notify the broker when
24
- # it has received a message; however, setting +ack+ to :client will require
25
- # each message received by this subscription to be acknowledged through the
26
- # use of Stomper::Client#ack in order to ensure proper interaction between
27
- # client and broker.
28
- #
29
- # The +selector+ parameter (again, optional) sets a SQL 92 selector for
30
- # this subscription with the stomp broker as per the Stomp Protocol specification.
31
- # Support of this functionality is entirely the responsibility of the broker,
32
- # there is no client side filtering being done on incoming messages.
33
- #
34
- # When a message is "received" by an instance of Subscription, the supplied
35
- # +block+ is inovked with the received message sent as a parameter.
36
- #
37
- # If no +subscription_id+ is specified, either explicitly or through a
38
- # hash key of 'id' in +destination_or_options+, one may be automatically
39
- # generated of the form +sub-<Time.now.to_f>+. The automatic generation
40
- # of a subscription id occurs if and only if naive? returns false.
41
- #
42
- # While direct creation of Subscription instances is possible, the preferred
43
- # method is for them to be constructed by a Stomper::Client through the use
44
- # of the Stomper::Client#subscribe method.
45
- #
46
- # @see naive?
47
- # @see Subscriber#subscribe
48
- # @see Subscriber#unsubscribe
49
- # @see Client#ack
50
- def initialize(destination_or_options, subscription_id=nil, ack=nil, selector=nil, &block)
51
- if destination_or_options.is_a?(Hash)
52
- destination = destination_or_options[:destination]
53
- subscription_id ||= destination_or_options[:id]
54
- ack ||= destination_or_options[:ack]
55
- selector ||= destination_or_options[:selector]
56
- else
57
- destination = destination_or_options.to_s
58
- end
59
- @id = subscription_id
60
- @destination = destination
61
- @ack = (ack || :auto).to_sym
62
- @selector = selector
63
- @call_back = block
64
- @id ||= "sub-#{Time.now.to_f}" unless naive?
65
- end
66
-
67
- # Returns true if this subscription has no explicitly specified id,
68
- # has no selector specified, and acknowledges messages through the :auto
69
- # mode.
70
- def naive?
71
- @id.nil? && @selector.nil? && @ack == :auto
72
- end
73
-
74
- # Returns true if this subscription is responsible for a Stomper::Client
75
- # instance receiving +message_frame+.
76
- #
77
- # See also: receives_for?, perform
78
- def accepts?(message_frame)
79
- receives_for?(message_frame.destination, message_frame.subscription)
80
- end
81
-
82
- # Returns true if this subscription is responsible for receiving
83
- # messages for the given destination or subscription id, specified
84
- # by +dest+ and +subid+ respectively.
85
- #
86
- # Note: if +subid+ is non-nil or this subscription is not naive?,
87
- # then this method returns true if and only if the supplied +subid+ is
88
- # equal to the +id+ of this subscription. Otherwise, the return value
89
- # depends only upon the equality of +dest+ and this subscriptions +destination+
90
- # attribute.
91
- #
92
- # See also: naive?
93
- def receives_for?(dest, subid=nil)
94
- if naive? && subid.nil?
95
- @destination == dest
96
- else
97
- @id == subid
98
- end
99
- end
100
-
101
- # Invokes the block associated with this subscription if
102
- # this subscription accepts the supplied +message_frame+.
103
- #
104
- # See also: accepts?
105
- def perform(message_frame)
106
- @call_back.call(message_frame) if accepts?(message_frame)
107
- end
108
-
109
- # Converts this representation of a subscription into a
110
- # Stomper::Frames::Subscribe client frame that can be transmitted
111
- # to a stomp broker through a Stomper::Connection instance.
112
- def to_subscribe
113
- headers = { :destination => @destination, :ack => @ack.to_s }
114
- headers[:id] = @id unless @id.nil?
115
- headers[:selector] = @selector unless @selector.nil?
116
- Stomper::Frames::Subscribe.new(@destination, headers)
117
- end
118
-
119
- # Converts this representation of a subscription into a
120
- # Stomper::Frames::Unsubscribe client frame that can be transmitted
121
- # to a stomp broker through a Stomper::Connection instance.
122
- def to_unsubscribe
123
- headers = { :destination => @destination }
124
- headers[:id] = @id unless @id.nil?
125
- Stomper::Frames::Unsubscribe.new(@destination, headers)
126
- end
127
- end
128
- end
@@ -1,95 +0,0 @@
1
- module Stomper
2
- # A Subscription collection class used internally by Stomper::Client to store
3
- # its subscriptions. Instances of this class utilize synchronization making
4
- # it safe to use in a multi-threaded context.
5
- class Subscriptions
6
- include Enumerable
7
-
8
- # Creates a new Subscriptions container.
9
- def initialize
10
- @subs = []
11
- @sub_lock = Mutex.new
12
- end
13
-
14
- # Adds the supplied subscription, +sub+, to the collection.
15
- def <<(sub)
16
- add(sub)
17
- end
18
-
19
- # Adds the supplied subscription, +sub+, to the collection.
20
- def add(sub)
21
- raise ArgumentError, "appended object must be a subscription" unless sub.is_a?(Subscription)
22
- @sub_lock.synchronize { @subs << sub }
23
- end
24
-
25
- # Removes all Subscription objects from the collection that match
26
- # the supplied destination, +dest+, and subscription id, +subid+.
27
- # If +dest+ is a hash, the value referenced by the :destination key
28
- # will be used as the destination, and +subid+ will be set to the value
29
- # referenced by :id, unless it is explicitly set beforehand. If +dest+ is
30
- # an instance of Subscription, the +destination+ attribute will be used
31
- # as the destination, and +subid+ will be set to the +id+ attribute, unless
32
- # explicitly set beforehand. The Subscription objects removed are all of
33
- # those, and only those, for which the Stomper::Subscription#receives_for?
34
- # method returns true given the destination and/or subscription id.
35
- #
36
- # This method returns an array of all the Subscription objects that were
37
- # removed, or an empty array if none were removed.
38
- #
39
- # See also: Stomper::Subscription#receives_for?, Stomper::Client#unsubscribe
40
- def remove(dest, subid=nil)
41
- if dest.is_a?(Hash)
42
- subid ||= dest[:id]
43
- dest = dest[:destination]
44
- elsif dest.is_a?(Subscription)
45
- subid ||= dest.id
46
- dest = dest.destination
47
- end
48
- _remove(dest, subid)
49
- end
50
-
51
- # Returns the number of Subscription objects within the container through
52
- # the use of synchronization.
53
- def size
54
- @sub_lock.synchronize { @subs.size }
55
- end
56
-
57
- # Returns the first Subscription object within the container through
58
- # the use of synchronization.
59
- def first
60
- @sub_lock.synchronize { @subs.first }
61
- end
62
-
63
- # Returns the last Subscription object within the container through
64
- # the use of synchronization.
65
- def last
66
- @sub_lock.synchronize { @subs.last }
67
- end
68
-
69
- # Evaluates the supplied +block+ for each Subscription object
70
- # within the container, or yields an Enumerator for the collection
71
- # if no +block+ is given. As this method is synchronized, it is
72
- # entirely possible to enter into a dead-lock if the supplied block
73
- # in turn calls any other synchronized method of the container.
74
- # [This could be remedied by creating a new array with
75
- # the same Subscription objects currently contained, and performing
76
- # the +each+ call on the new array. Give this some thought.]
77
- def each(&block)
78
- @sub_lock.synchronize { @subs.each(&block) }
79
- end
80
-
81
- # Passes the supplied +message+ to all Subscription objects within the
82
- # collection through their Stomper::Subscription#perform method.
83
- def perform(message)
84
- @sub_lock.synchronize { @subs.each { |sub| sub.perform(message) } }
85
- end
86
-
87
- private
88
- def _remove(dest, subid)
89
- @sub_lock.synchronize do
90
- to_remove, @subs = @subs.partition { |s| s.receives_for?(dest,subid) }
91
- to_remove
92
- end
93
- end
94
- end
95
- end
@@ -1,59 +0,0 @@
1
- module Stomper
2
- module ThreadedReceiver
3
- def self.extended(base)
4
- base.instance_eval do
5
- @receiver_mutex = Mutex.new
6
- end
7
- end
8
-
9
- # Starts the threaded receiver on a connection, calling receive
10
- # on the connection repeatedly in a separate thread until the receiver
11
- # is stopped or the connection is closed.
12
- #
13
- # @return self
14
- # @see ThreadedReceiver#stop
15
- # @see Connection#receive
16
- # @see Connection#connected?
17
- def start(opts={})
18
- connect unless connected?
19
- do_start = false
20
- @receiver_mutex.synchronize do
21
- do_start = !started?
22
- end
23
- if do_start
24
- @started = true
25
- @run_thread = Thread.new() do
26
- while started? && connected?
27
- receive
28
- end
29
- end
30
- end
31
- self
32
- end
33
-
34
- # Stops the threaded receiver on a connection thereby stopping further
35
- # calls to receive.
36
- #
37
- # @return self
38
- # @see ThreadedReceiver#start
39
- # @see Connection#receive
40
- # @see Connection#connected?
41
- def stop
42
- do_stop = false
43
- @receiver_mutex.synchronize do
44
- do_stop = started?
45
- end
46
- if do_stop
47
- @started = false
48
- @run_thread.join
49
- @run_thread = nil
50
- end
51
- self
52
- end
53
-
54
- private
55
- def started?
56
- @started
57
- end
58
- end
59
- end
@@ -1,185 +0,0 @@
1
- module Stomper
2
- # An exception raised whenever a Transaction object has been aborted
3
- # due to an unhandled exception generated by its supplied block, or when
4
- # the block explicitly aborts the transaction.
5
- #
6
- # See also: Stomper::Transaction#perform
7
- class TransactionAborted < RuntimeError; end
8
-
9
- # An encapsulation of a stomp transaction. Manually managing transactions
10
- # is possible through the use of Stomper::Client#begin, Stomper::Client#commit,
11
- # and Stomper::Client#abort.
12
- #
13
- # === Example Usage
14
- #
15
- # When the transaction is passed to the block:
16
- #
17
- # client.transaction do |t|
18
- # t.send("/queue/target", "doing some work")
19
- #
20
- # # do something that might raise an exception, indicating that any
21
- # # messages and acknowledgements we have sent should be "undone"
22
- #
23
- # t.send("/queue/target", "completed work")
24
- # end
25
- #
26
- # When the block is evaluated within the transaction:
27
- #
28
- # client.transaction do
29
- # send("/queue/target", "doing some work")
30
- #
31
- # # ...
32
- #
33
- # send("/queue/target", "completed work")
34
- # end
35
- #
36
- # Nesting transactions:
37
- #
38
- # client.transaction do |t|
39
- # t.transaction do |nt|
40
- # nt.send("/queue/target", ...)
41
- #
42
- # nt.transaction do |nnt|
43
- # nnt.send("/queue/target", ...)
44
- #
45
- # # do something with potentially exceptional results
46
- # end
47
- #
48
- # nt.send("/queue/target", ...)
49
- # end
50
- #
51
- # t.send("/queue/target", ...)
52
- # end
53
- #
54
- # See also: Stomper::Client#transaction
55
- #
56
- class Transaction
57
- # The id of this transaction, used to reference the transaction with the stomp broker.
58
- attr_reader :id
59
-
60
- # Creates a new Transaction instance. The +client+ parameter
61
- # is an instance of Stomper::Client and is required so that the Transaction
62
- # instance has somewhere to forward +begin+, +ack+ and +abort+ methods
63
- # to. If the +trans_id+ parameter is not specified, an id is automatically
64
- # generated of the form +tx-<Time.now.to_f>+. This name can be accessed
65
- # through the +id+ attribute and is used in naming the transaction to
66
- # the stomp broker. If +block+ is given, the Transaction instance immediately
67
- # calls its perform method with the supplied +block+.
68
- def initialize(client, trans_id=nil, &block)
69
- @client = client
70
- @id = trans_id || "tx-#{Time.now.to_f}"
71
- @committed = false
72
- @aborted = false
73
- perform(&block) if block_given?
74
- end
75
-
76
- # Invokes the given +block+. If the +block+ executes normally, the
77
- # transaction is committed, otherwise it is aborted.
78
- # If +block+ accepts a parameter, this method yields itself to the block,
79
- # otherwise, +block+ is evaluated within the context of this instance through
80
- # +instance_eval+.
81
- #
82
- # If a call to +abort+ is issued within the block, the transaction is aborted
83
- # as demanded, and no attempt is made to commit it; however, no code after the
84
- # call to +abort+ will be evaluated, as +abort+ raises a TransactionAborted
85
- # exception.
86
- #
87
- # If a call to +commit+ is issued within the block, the transaction is committed
88
- # as demanded, and no attempt is made to commit it after +block+ has finished
89
- # executing. As +commit+ does not raise an excpetion, all code after the call
90
- # to commit will be evaluated.
91
- #
92
- # If you are using Transaction objects directly, and not relying on their
93
- # generation through Stomper::Client#transaction, be warned that this method
94
- # will raise a TransactionAborted exception if the +block+ evaluation fails.
95
- # This behavior allows for nesting transactions and ensuring that if a nested
96
- # transaction fails, so do all of its ancestors.
97
- #
98
- # @param [Proc] block A block of code that is evaluated as part of the transaction.
99
- # @raise [TransactionAborted] raises an exception if the given block raises an exception
100
- def perform(&block) #:yields: transaction
101
- begin
102
- @client.begin(@id)
103
- if block.arity == 1
104
- yield self
105
- else
106
- instance_eval(&block)
107
- end
108
- commit
109
- rescue => err
110
- _abort
111
- raise TransactionAborted, "aborted transaction '#{@id}' originator: #{err.to_s}"
112
- end
113
- end
114
-
115
- # Returns true if the Transaction object has already been committed, false
116
- # otherwise.
117
- def committed?
118
- @committed
119
- end
120
-
121
- # Returns true if the Transaction object has already been aborted, false
122
- # otherwise.
123
- def aborted?
124
- @aborted
125
- end
126
-
127
- # Similar to Stomper::Client#transaction, this method creates a new
128
- # Transaction object, nested inside of this one. To prevent name
129
- # collisions, this method automatically generates a transaction id,
130
- # if one is not specified, of the form +<parent_transaction_id>-<Time.now.to_f>+.
131
- def transaction(transaction_id=nil,&block)
132
- # To get a transaction name guaranteed to not collide with this one
133
- # we will supply an explicit id to the constructor unless an id was
134
- # provided
135
- transaction_id ||= "#{@id}-#{Time.now.to_f}"
136
- self.class.new(@client, transaction_id, &block)
137
- end
138
-
139
- # Wraps the Stomper::Client#send method, injecting a "transaction" header
140
- # into the +headers+ hash, thus informing the stomp broker that the message
141
- # generated here is part of this transaction.
142
- def send(destination, body, headers={})
143
- @client.send(destination, body, headers.merge({:transaction => @id }))
144
- end
145
-
146
- # Wraps the Stomper::Client#ack method, injecting a "transaction" header
147
- # into the +headers+ hash, thus informing the stomp broker that the message
148
- # acknowledgement is part of this transaction.
149
- def ack(message_or_id, headers={})
150
- @client.ack(message_or_id, headers.merge({ :transaction => @id }))
151
- end
152
-
153
- # Aborts this transaction if it has not already been committed or aborted.
154
- # Note that it does so by raising a TransactionAborted exception, allowing
155
- # the +abort+ call to force any ancestral transactions to also fail.
156
- #
157
- # @see Transaction#commit
158
- # @see Transaction#committed?
159
- # @see Transaction#aborted?
160
- def abort
161
- raise TransactionAborted, "transaction '#{@id}' aborted explicitly" if _abort
162
- end
163
-
164
- # Commits this transaction unless it has already been committed or aborted.
165
- #
166
- # @see Transaction#abort
167
- # @see Transaction#committed?
168
- # @see Transaction#aborted?
169
- def commit
170
- # Guard against sending multiple commit messages to the server for a
171
- # single transaction.
172
- @client.commit(@id) unless committed? || aborted?
173
- @committed = true
174
- end
175
-
176
- private
177
- def _abort
178
- # Guard against sending multiple abort messages to the server for a
179
- # single transaction.
180
- return false if committed? || aborted?
181
- @client.abort(@id)
182
- @aborted = true
183
- end
184
- end
185
- end