gz_activemessaging 0.13.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. checksums.yaml +15 -0
  2. data/.travis.yml +40 -0
  3. data/Appraisals +19 -0
  4. data/Gemfile +15 -0
  5. data/Gemfile.lock +87 -0
  6. data/README.md +27 -0
  7. data/Rakefile +49 -0
  8. data/VERSION +1 -0
  9. data/activemessaging.gemspec +137 -0
  10. data/gemfiles/activesupport23.gemfile +10 -0
  11. data/gemfiles/activesupport23.gemfile.lock +51 -0
  12. data/gemfiles/activesupport30.gemfile +11 -0
  13. data/gemfiles/activesupport30.gemfile.lock +53 -0
  14. data/gemfiles/activesupport31.gemfile +11 -0
  15. data/gemfiles/activesupport31.gemfile.lock +55 -0
  16. data/gemfiles/activesupport32.gemfile +10 -0
  17. data/gemfiles/activesupport32.gemfile.lock +55 -0
  18. data/generators/a13g_test_harness/a13g_test_harness_generator.rb +19 -0
  19. data/generators/a13g_test_harness/templates/active_messaging_test.rhtml +13 -0
  20. data/generators/a13g_test_harness/templates/active_messaging_test_controller.rb +29 -0
  21. data/generators/a13g_test_harness/templates/index.rhtml +17 -0
  22. data/generators/filter/USAGE +0 -0
  23. data/generators/filter/filter_generator.rb +19 -0
  24. data/generators/filter/templates/filter.rb +12 -0
  25. data/generators/filter/templates/filter_test.rb +28 -0
  26. data/generators/processor/USAGE +8 -0
  27. data/generators/processor/processor_generator.rb +31 -0
  28. data/generators/processor/templates/application_processor.rb +18 -0
  29. data/generators/processor/templates/broker.yml +140 -0
  30. data/generators/processor/templates/jruby_poller +117 -0
  31. data/generators/processor/templates/messaging.rb +12 -0
  32. data/generators/processor/templates/poller +25 -0
  33. data/generators/processor/templates/poller.rb +26 -0
  34. data/generators/processor/templates/processor.rb +8 -0
  35. data/generators/processor/templates/processor_test.rb +20 -0
  36. data/generators/tracer/USAGE +8 -0
  37. data/generators/tracer/templates/controller.rb +14 -0
  38. data/generators/tracer/templates/helper.rb +2 -0
  39. data/generators/tracer/templates/index.rhtml +4 -0
  40. data/generators/tracer/templates/layout.rhtml +16 -0
  41. data/generators/tracer/templates/trace_processor.rb +100 -0
  42. data/generators/tracer/tracer_generator.rb +25 -0
  43. data/init.rb +1 -0
  44. data/lib/activemessaging.rb +133 -0
  45. data/lib/activemessaging/adapter.rb +20 -0
  46. data/lib/activemessaging/adapters/amqp.rb +215 -0
  47. data/lib/activemessaging/adapters/asqs.rb +487 -0
  48. data/lib/activemessaging/adapters/base.rb +71 -0
  49. data/lib/activemessaging/adapters/beanstalk.rb +88 -0
  50. data/lib/activemessaging/adapters/jms.rb +243 -0
  51. data/lib/activemessaging/adapters/reliable_msg.rb +186 -0
  52. data/lib/activemessaging/adapters/stomp.rb +212 -0
  53. data/lib/activemessaging/adapters/synch.rb +95 -0
  54. data/lib/activemessaging/adapters/test.rb +137 -0
  55. data/lib/activemessaging/adapters/wmq.rb +193 -0
  56. data/lib/activemessaging/base_message.rb +28 -0
  57. data/lib/activemessaging/filter.rb +29 -0
  58. data/lib/activemessaging/gateway.rb +429 -0
  59. data/lib/activemessaging/message_sender.rb +30 -0
  60. data/lib/activemessaging/named_base.rb +54 -0
  61. data/lib/activemessaging/processor.rb +44 -0
  62. data/lib/activemessaging/railtie.rb +26 -0
  63. data/lib/activemessaging/test_helper.rb +189 -0
  64. data/lib/activemessaging/threaded_poller.rb +234 -0
  65. data/lib/activemessaging/trace_filter.rb +34 -0
  66. data/lib/generators/active_messaging/install/USAGE +21 -0
  67. data/lib/generators/active_messaging/install/install_generator.rb +39 -0
  68. data/lib/generators/active_messaging/install/templates/application_processor.rb +18 -0
  69. data/lib/generators/active_messaging/install/templates/broker.yml +139 -0
  70. data/lib/generators/active_messaging/install/templates/poller +24 -0
  71. data/lib/generators/active_messaging/install/templates/poller.rb +22 -0
  72. data/lib/generators/active_messaging/install/templates/threaded_poller +46 -0
  73. data/lib/generators/active_messaging/processor/USAGE +2 -0
  74. data/lib/generators/active_messaging/processor/processor_generator.rb +39 -0
  75. data/lib/generators/active_messaging/processor/templates/messaging.rb +12 -0
  76. data/lib/generators/active_messaging/processor/templates/processor.rb +8 -0
  77. data/lib/generators/active_messaging/processor/templates/processor_spec.rb +24 -0
  78. data/lib/generators/active_messaging/processor/templates/processor_test.rb +20 -0
  79. data/lib/tasks/start_consumers.rake +8 -0
  80. data/poller.rb +14 -0
  81. data/test/all_tests.rb +10 -0
  82. data/test/app/config/broker.yml +4 -0
  83. data/test/asqs_test.rb +125 -0
  84. data/test/config_test.rb +42 -0
  85. data/test/filter_test.rb +131 -0
  86. data/test/gateway_test.rb +220 -0
  87. data/test/jms_test.rb +64 -0
  88. data/test/reliable_msg_test.rb +83 -0
  89. data/test/stomp_test.rb +168 -0
  90. data/test/test_helper.rb +36 -0
  91. data/test/tracer_test.rb +57 -0
  92. metadata +202 -0
@@ -0,0 +1,71 @@
1
+ require 'activemessaging/adapter'
2
+ require 'activemessaging/base_message'
3
+
4
+ module ActiveMessaging
5
+ module Adapters
6
+
7
+ # use this as a base for implementing new connections
8
+ class BaseConnection
9
+ include ActiveMessaging::Adapter
10
+
11
+ #use the register method to add the adapter to the configurable list of supported adapters
12
+ # register :base
13
+
14
+ #configurable params
15
+ attr_accessor :reliable
16
+
17
+ #generic init method needed by a13g
18
+ def initialize cfg
19
+ end
20
+
21
+ # called to cleanly get rid of connection
22
+ def disconnect
23
+ end
24
+
25
+ # destination_name string, headers hash
26
+ # subscribe to listen on a destination
27
+ def subscribe destination_name, message_headers={}
28
+ end
29
+
30
+ # destination_name string, headers hash
31
+ # unsubscribe to listen on a destination
32
+ def unsubscribe destination_name, message_headers={}
33
+ end
34
+
35
+ # destination_name string, body string, headers hash
36
+ # send a single message to a destination
37
+ def send destination_name, message_body, message_headers={}
38
+ end
39
+
40
+ # receive a single message from any of the subscribed destinations
41
+ # check each destination once, then sleep for poll_interval
42
+ # adding options,optionally, so a poller can get certain messages (e.g. by priority)
43
+ def receive(options={})
44
+ end
45
+
46
+ # called after a message is successfully received and processed
47
+ def received message, headers={}
48
+ end
49
+
50
+ # called after a message is successfully received but unsuccessfully processed
51
+ # purpose is to return the message to the destination so receiving and processing and be attempted again
52
+ def unreceive message, headers={}
53
+ end
54
+
55
+ end
56
+
57
+ ## I recommend having a destination object to represent each subscribed destination
58
+ # class Destination
59
+ # attr_accessor :name
60
+ #
61
+ # def to_s
62
+ # "<Base::Destination name='#{name}'>"
63
+ # end
64
+ # end
65
+
66
+ ## You should also define your own message based on the BaseMessage class
67
+ # class Message < ActiveMessaging::BaseMessage
68
+ # end
69
+
70
+ end
71
+ end
@@ -0,0 +1,88 @@
1
+ #
2
+ # contributed by Al-Faisal El-Dajani on 11/04/2009
3
+ #
4
+ # One caveat: beanstalk does not accept the underscore '_' as a legal character in queue names.
5
+ # So in messaging.rb you'll need to modify your queue names to use something other than the underscore, a dash perhaps.
6
+ # Accepting the underscore as a valid char in queue names is an open issue in beanstalk, and should be fixed in a future version.
7
+ #
8
+
9
+ require 'beanstalk-client'
10
+ require 'activemessaging/adapters/base'
11
+
12
+ module ActiveMessaging
13
+ module Adapters
14
+ module Beanstalk
15
+
16
+ class Connection < ActiveMessaging::Adapters::BaseConnection
17
+ register :beanstalk
18
+
19
+ attr_accessor :connection, :host, :port
20
+
21
+ def initialize cfg
22
+ @host = cfg[:host] || 'localhost'
23
+ @port = cfg[:port] || 11300
24
+
25
+ @connection = ::Beanstalk::Pool.new(["#{@host}:#{@port}"])
26
+ end
27
+
28
+ def disconnect
29
+ @connection.close
30
+ end
31
+
32
+ def subscribe tube, message_headers={}
33
+ @connection.watch(tube)
34
+ end
35
+
36
+ def unsubscribe tube, message_headers={}
37
+ @connection.ignore(tube)
38
+ end
39
+
40
+ def send tube, message, message_headers={}
41
+ priority = message_headers[:priority] || 65536
42
+ delay = message_headers[:delay] || 0
43
+ ttr = message_headers[:ttr] || 120
44
+
45
+ @connection.use(tube)
46
+ @connection.put(message, priority, delay, ttr)
47
+ end
48
+
49
+ def receive(options={})
50
+ message = @connection.reserve
51
+ Beanstalk::Message.new message
52
+ end
53
+
54
+ def received message, message_headers={}
55
+ message.delete
56
+ end
57
+
58
+ def unreceive message, message_headers={}
59
+ message.release
60
+ end
61
+
62
+ end
63
+
64
+ class Message < ActiveMessaging::BaseMessage
65
+ attr_accessor :beanstalk_job
66
+
67
+ def initialize beanstalk_job
68
+ bsh = {
69
+ 'destination' => beanstalk_job.stats['tube'],
70
+ 'priority' => beanstalk_job.pri,
71
+ 'delay' => beanstalk_job.delay,
72
+ 'ttr' => beanstalk_job.ttr
73
+ }
74
+ super(beanstalk_job.body, beanstalk_job.id, bsh, beanstalk_job.stats['tube'])
75
+ @beanstalk_job = beanstalk_job
76
+ end
77
+
78
+ def delete
79
+ @beanstalk_job.delete
80
+ end
81
+
82
+ def release
83
+ @beanstalk_job.release
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,243 @@
1
+ if defined?(JRUBY_VERSION)
2
+ #require 'java'
3
+ include Java
4
+ require 'activemq'
5
+
6
+ begin
7
+ java_import javax.naming.InitialContext
8
+ java_import javax.jms.MessageListener
9
+ rescue NameError
10
+ raise LoadError, "ActiveMessaging::Adapter::Jms needs Jave EE classes on the CLASSPATH"
11
+ end
12
+
13
+ module ActiveMessaging
14
+ module Adapters
15
+ module Jms
16
+
17
+ class Connection
18
+ include ActiveMessaging::Adapter
19
+ register :jms
20
+
21
+ attr_accessor :reliable, :connection, :session, :producers, :consumers
22
+
23
+ def initialize cfg={}
24
+ @url = cfg[:url]
25
+ @login = cfg[:login]
26
+ @passcode = cfg[:passcode]
27
+ #initialize our connection factory
28
+ if cfg.has_key? :connection_factory
29
+ #this initialize is probably activemq specific. There might be a more generic
30
+ #way of getting this without resorting to jndi lookup.
31
+ eval <<-end_eval
32
+ @connection_factory = Java::#{cfg[:connection_factory]}.new(@login, @passcode, @url)
33
+ end_eval
34
+ elsif cfg.has_key? :jndi
35
+ @connection_factory = javax.naming.InitialContext.new().lookup(cfg[:jndi])
36
+ else
37
+ raise "Either jndi or connection_factory has to be set in the config."
38
+ end
39
+ raise "Connection factory could not be initialized." if @connection_factory.nil?
40
+
41
+ @connection = @connection_factory.create_connection()
42
+ @session = @connection.createSession(false, 1)
43
+ @destinations = []
44
+ @producers = {}
45
+ @consumers = {}
46
+ @connection.start
47
+ end
48
+
49
+ def subscribe queue_name, headers={}
50
+ queue_name = check_destination_type queue_name, headers
51
+ find_or_create_consumer queue_name, headers
52
+ end
53
+
54
+ def unsubscribe queue_name, headers={}
55
+ queue_name = check_destination_type queue_name, headers
56
+ consumer = @consumers[queue_name]
57
+ unless consumer.nil?
58
+ consumer.close
59
+ @consumers.delete queue_name
60
+ end
61
+ end
62
+
63
+ def send queue_name, body, headers={}
64
+ queue_name = check_destination_type queue_name, headers
65
+ producer = find_or_create_producer queue_name, headers.symbolize_keys
66
+ message = @session.create_text_message body
67
+ headers.stringify_keys.each do |key, value|
68
+ if ['id', 'message-id', 'JMSMessageID'].include? key
69
+ message.setJMSMessageID value.to_s
70
+ elsif ['correlation-id', 'JMSCorrelationID'].include? key
71
+ message.setJMSCorrelationID value.to_s
72
+ elsif ['expires', 'JMSExpiration'].include? key
73
+ message.setJMSExpiration value.to_i
74
+ elsif ['persistent', 'JMSDeliveryMode'].include? key
75
+ message.setJMSDeliveryMode(value ? 2 : 1)
76
+ elsif ['priority', 'JMSPriority'].include? key
77
+ message.setJMSPriority value.to_i
78
+ elsif ['reply-to', 'JMSReplyTo'].include? key
79
+ message.setJMSReplyTo value.to_s
80
+ elsif ['type', 'JMSType'].include? key
81
+ message.setJMSType value.to_s
82
+ else #is this the most appropriate thing to do here?
83
+ message.set_string_property key, value.to_s
84
+ end
85
+ end
86
+ producer.send message
87
+ end
88
+
89
+ def receive(options={})
90
+ queue_name = options[:queue_name]
91
+ headers = options[:headers] || {}
92
+ receive_message(queue_name, headers)
93
+ end
94
+
95
+ def receive_message(queue_name=nil, headers={})
96
+ if queue_name.nil?
97
+ @consumers.find do |k, c|
98
+ message = c.receive(1)
99
+ return condition_message(message) unless message.nil?
100
+ end
101
+ else
102
+ consumer = subscribe(queue_name, headers)
103
+ message = consumer.receive(1)
104
+ unsubscribe(queue_name, headers)
105
+ condition_message(message)
106
+ end
107
+ end
108
+
109
+ def received message, headers={}
110
+ #do nothing
111
+ end
112
+
113
+ def unreceive message, headers={}
114
+ # do nothing
115
+ end
116
+
117
+ def close
118
+ @consumers.each {|k, c| c.stop }
119
+ @connection.stop
120
+ @session.close
121
+ @connection.close
122
+ @connection = nil
123
+ @session = nil
124
+ @consumers = {}
125
+ @producers = {}
126
+ end
127
+
128
+ def find_or_create_producer queue_name, headers={}
129
+ producer = @producers[queue_name]
130
+ if producer.nil?
131
+ destination = find_or_create_destination queue_name, headers
132
+ producer = @session.create_producer destination
133
+ end
134
+ producer
135
+ end
136
+
137
+ def find_or_create_consumer queue_name, headers={}
138
+ consumer = @consumers[queue_name]
139
+ if consumer.nil?
140
+ destination = find_or_create_destination queue_name, headers
141
+ if headers.symbolize_keys.has_key? :selector
142
+ consumer = @session.create_consumer destination, headers.symbolize_keys[:selector]
143
+ else
144
+ consumer = @session.create_consumer destination
145
+ end
146
+
147
+ @consumers[queue_name] = consumer
148
+ end
149
+ consumer
150
+ end
151
+
152
+ def find_or_create_destination queue_name, headers={}
153
+ destination = find_destination queue_name, headers[:destination_type]
154
+ if destination.nil?
155
+ if headers.symbolize_keys[:destination_type] == :topic
156
+ destination = @session.create_topic(queue_name.to_s)
157
+ @destinations << destination
158
+ elsif headers.symbolize_keys[:destination_type] == :queue
159
+ destination = @session.create_queue(queue_name.to_s)
160
+ @destinations << destination
161
+ else
162
+ raise "headers[:destination_type] must be either :queue or :topic. was #{headers[:destination_type]}"
163
+ end
164
+ end
165
+ destination
166
+ end
167
+
168
+ protected
169
+
170
+ def condition_message message
171
+ message.class.class_eval {
172
+ alias_method :body, :text unless method_defined? :body
173
+
174
+ def headers
175
+ destination.to_s =~ %r{(queue|topic)://(.*)}
176
+ puts "/#{$1}/#{$2}"
177
+ {'destination' => "/#{$1}/#{$2}"}
178
+ end
179
+
180
+ def matches_subscription?(subscription)
181
+ self.headers['destination'].to_s == subscription.value.to_s
182
+ end
183
+
184
+ } unless message.nil? || message.respond_to?(:headers)
185
+ message
186
+ end
187
+
188
+ def check_destination_type queue_name, headers
189
+ stringy_h = headers.stringify_keys
190
+ if queue_name =~ %r{^/(topic|queue)/(.*)$} && !stringy_h.has_key?('destination_type')
191
+ headers['destination_type'] = $1.to_sym
192
+ return $2
193
+ else
194
+ raise "Must specify destination type either with either 'headers[\'destination_type\']=[:queue|:topic]' or /[topic|queue]/destination_name for queue name '#{queue_name}'" unless [:topic, :queue].include? stringy_h['destination_type']
195
+ end
196
+ end
197
+
198
+ def find_destination queue_name, type
199
+ @destinations.find do |d|
200
+ if d.is_a?(javax.jms.Topic) && type == :topic
201
+ d.topic_name == queue_name
202
+ elsif d.is_a?(javax.jms.Queue) && type == :queue
203
+ d.queue_name == queue_name
204
+ end
205
+ end
206
+ end
207
+ end
208
+ #
209
+ # class RubyMessageListener
210
+ # include javax.jms.MessageListener
211
+ #
212
+ # def initialize(connection, destination, name)
213
+ # @connection = connection
214
+ # @destination = destination
215
+ # @name = name
216
+ # end
217
+ #
218
+ # def onMessage(msg)
219
+ # headers = {}
220
+ # enm = msg.getPropertyNames
221
+ # while enm.hasMoreElements
222
+ # key = enm.nextElement
223
+ # headers[key.to_s] = msg.getStringProperty(key)
224
+ # end
225
+ # Gateway.dispatch(JMSRecvMessage.new(headers,msg.text,@name))
226
+ # rescue => e
227
+ # STDERR.puts "something went really wrong with a message: #{e.inspect}"
228
+ # end
229
+ # end
230
+ #
231
+ # class JMSRecvMessage < ActiveMessaging::Adapters::Base::Message
232
+ # def initialize(headers, body, name, command='MESSAGE')
233
+ # @headers = headers
234
+ # @body = body
235
+ # @command = command
236
+ # @headers['destination'] = name
237
+ # end
238
+ # end
239
+ end
240
+ end
241
+ end
242
+
243
+ end
@@ -0,0 +1,186 @@
1
+ require 'reliable-msg'
2
+
3
+ require 'activemessaging/adapters/base'
4
+
5
+ # add access to the queue_manager to use for adding transactions
6
+ module ReliableMsg
7
+
8
+ class Client
9
+
10
+ def queue_manager
11
+ qm
12
+ end
13
+
14
+ end
15
+ end
16
+
17
+
18
+ module ActiveMessaging
19
+ module Adapters
20
+ class ReliableMsgConnection < ActiveMessaging::Adapters::BaseConnection
21
+
22
+ THREAD_OLD_TXS = :a13g_reliable_msg_old_txs
23
+
24
+ QUEUE_PARAMS = [:expires,:delivery,:priority,:max_deliveries,:drb_uri,:tx_timeout,:connect_count]
25
+ TOPIC_PARAMS = [:expires,:drb_uri,:tx_timeout,:connect_count]
26
+
27
+ register :reliable_msg
28
+
29
+ #configurable params
30
+ attr_accessor :subscriptions, :destinations, :poll_interval, :current_subscription, :tx_timeout
31
+
32
+ #generic init method needed by a13g
33
+ def initialize cfg
34
+ @poll_interval = cfg[:poll_interval] || 1
35
+ @reliable = cfg[:reliable] || true
36
+ @tx_timeout = cfg[:tx_timeout] || ::ReliableMsg::Client::DEFAULT_TX_TIMEOUT
37
+
38
+ @subscriptions = {}
39
+ @destinations = {}
40
+ @current_subscription = 0
41
+ end
42
+
43
+ # called to cleanly get rid of connection
44
+ def disconnect
45
+ nil
46
+ end
47
+
48
+ # destination_name string, headers hash
49
+ # subscribe to listen on a destination
50
+ # use '/destination-type/name' convetion, like stomp
51
+ def subscribe destination_name, message_headers={}
52
+ get_or_create_destination(destination_name, message_headers)
53
+ if subscriptions.has_key? destination_name
54
+ subscriptions[destination_name].add
55
+ else
56
+ subscriptions[destination_name] = Subscription.new(destination_name, message_headers)
57
+ end
58
+ end
59
+
60
+ # destination_name string, headers hash
61
+ # unsubscribe to listen on a destination
62
+ def unsubscribe destination_name, message_headers={}
63
+ subscriptions[destination_name].remove
64
+ subscriptions.delete(destination_name) if subscriptions[destination_name].count <= 0
65
+ end
66
+
67
+ # destination_name string, body string, headers hash
68
+ # send a single message to a destination
69
+ def send destination_name, message_body, message_headers={}
70
+ dest = get_or_create_destination(destination_name)
71
+ begin
72
+ dest.put message_body, message_headers
73
+ rescue Object=>err
74
+ raise err unless reliable
75
+ puts "send failed, will retry in #{@poll_interval} seconds"
76
+ sleep @poll_interval
77
+ end
78
+ end
79
+
80
+ def get_or_create_destination destination_name, message_headers={}
81
+ return destinations[destination_name] if destinations.has_key? destination_name
82
+ dd = /^\/(queue|topic)\/(.*)$/.match(destination_name)
83
+ rm_class = dd[1].titleize
84
+ message_headers.delete("id")
85
+ dest_headers = message_headers.reject {|k,v| rm_class == 'Queue' ? !QUEUE_PARAMS.include?(k) : !TOPIC_PARAMS.include?(k)}
86
+ rm_dest = "ReliableMsg::#{rm_class}".constantize.new(dd[2], dest_headers)
87
+ destinations[destination_name] = rm_dest
88
+ end
89
+
90
+ # receive a single message from any of the subscribed destinations
91
+ # check each destination once, then sleep for poll_interval
92
+ def receive(options={})
93
+
94
+ raise "No subscriptions to receive messages from." if (subscriptions.nil? || subscriptions.empty?)
95
+ start = current_subscription
96
+ while true
97
+ self.current_subscription = ((current_subscription < subscriptions.length-1) ? current_subscription + 1 : 0)
98
+ sleep poll_interval if (current_subscription == start)
99
+ destination_name = subscriptions.keys.sort[current_subscription]
100
+ destination = destinations[destination_name]
101
+ unless destination.nil?
102
+ # from the way we use this, assume this is the start of a transaction,
103
+ # there should be no current transaction
104
+ ctx = Thread.current[::ReliableMsg::Client::THREAD_CURRENT_TX]
105
+ raise "There should not be an existing reliable-msg transaction. #{ctx.inspect}" if ctx
106
+
107
+ # start a new transaction
108
+ @tx = {:qm=>destination.queue_manager}
109
+ @tx[:tid] = @tx[:qm].begin @tx_timeout
110
+ Thread.current[::ReliableMsg::Client::THREAD_CURRENT_TX] = @tx
111
+ begin
112
+
113
+ # now call a get on the destination - it will use the transaction
114
+ #the commit or the abort will occur in the received or unreceive methods
115
+ reliable_msg = destination.get subscriptions[destination_name].headers[:selector]
116
+ @tx[:qm].commit(@tx[:tid]) if reliable_msg.nil?
117
+
118
+ rescue Object=>err
119
+ #abort the transaction on error
120
+ @tx[:qm].abort(@tx[:tid])
121
+
122
+ raise err unless reliable
123
+ puts "receive failed, will retry in #{@poll_interval} seconds"
124
+ sleep poll_interval
125
+ end
126
+ return Message.new(reliable_msg.object, reliable_msg.id, reliable_msg.headers, destination_name, @tx) if reliable_msg
127
+
128
+ Thread.current[::ReliableMsg::Client::THREAD_CURRENT_TX] = nil
129
+ end
130
+ end
131
+ end
132
+
133
+ # called after a message is successfully received and processed
134
+ def received message, headers={}
135
+ begin
136
+ message.transaction[:qm].commit(message.transaction[:tid])
137
+ rescue Object=>ex
138
+ puts "received failed: #{ex.message}"
139
+ ensure
140
+ Thread.current[::ReliableMsg::Client::THREAD_CURRENT_TX] = nil
141
+ end
142
+
143
+ end
144
+
145
+ # called after a message is successfully received and processed
146
+ def unreceive message, headers={}
147
+ begin
148
+ message.transaction[:qm].abort(message.transaction[:tid])
149
+ rescue Object=>ex
150
+ puts "unreceive failed: #{ex.message}"
151
+ ensure
152
+ Thread.current[::ReliableMsg::Client::THREAD_CURRENT_TX] = nil
153
+ end
154
+ end
155
+
156
+ end
157
+
158
+ class Subscription
159
+ attr_accessor :name, :headers, :count
160
+
161
+ def initialize(destination, headers={}, count=1)
162
+ @destination, @headers, @count = destination, headers, count
163
+ end
164
+
165
+ def add
166
+ @count += 1
167
+ end
168
+
169
+ def remove
170
+ @count -= 1
171
+ end
172
+
173
+ end
174
+
175
+ class Message < ActiveMessaging::BaseMessage
176
+ attr_accessor :transaction
177
+
178
+ def initialize body, id, headers, destination, transaction=nil
179
+ super(body, id, headers, destination)
180
+ @transaction = transaction
181
+ end
182
+
183
+ end
184
+
185
+ end
186
+ end