gz_activemessaging 0.13.1

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 (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