stomper 1.0.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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