activemessaging 0.6.1 → 0.7.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.
@@ -1,82 +1,70 @@
1
+ require 'activemessaging/adapter'
2
+ require 'activemessaging/base_message'
3
+
1
4
  module ActiveMessaging
2
5
  module Adapters
3
- module Base
4
-
5
-
6
- # use this as a base for implementing new connections
7
- class Connection
8
- include ActiveMessaging::Adapter
9
-
10
- #use the register method to add the adapter to the configurable list of supported adapters
11
- # register :generic
12
6
 
13
- #configurable params
14
- attr_accessor :reliable
7
+ # use this as a base for implementing new connections
8
+ class BaseConnection
9
+ include ActiveMessaging::Adapter
15
10
 
16
- #generic init method needed by a13g
17
- def initialize cfg
18
- end
11
+ #use the register method to add the adapter to the configurable list of supported adapters
12
+ # register :base
19
13
 
20
- # called to cleanly get rid of connection
21
- def disconnect
22
- end
14
+ #configurable params
15
+ attr_accessor :reliable
23
16
 
24
- # destination_name string, headers hash
25
- # subscribe to listen on a destination
26
- def subscribe destination_name, message_headers={}
27
- end
28
-
29
- # destination_name string, headers hash
30
- # unsubscribe to listen on a destination
31
- def unsubscribe destination_name, message_headers={}
32
- end
17
+ #generic init method needed by a13g
18
+ def initialize cfg
19
+ end
33
20
 
34
- # destination_name string, body string, headers hash
35
- # send a single message to a destination
36
- def send destination_name, message_body, message_headers={}
37
- end
21
+ # called to cleanly get rid of connection
22
+ def disconnect
23
+ end
38
24
 
39
- # receive a single message from any of the subscribed destinations
40
- # check each destination once, then sleep for poll_interval
41
- def receive
42
- end
25
+ # destination_name string, headers hash
26
+ # subscribe to listen on a destination
27
+ def subscribe destination_name, message_headers={}
28
+ end
43
29
 
44
- # called after a message is successfully received and processed
45
- def received message, headers={}
46
- end
30
+ # destination_name string, headers hash
31
+ # unsubscribe to listen on a destination
32
+ def unsubscribe destination_name, message_headers={}
33
+ end
47
34
 
48
- # called after a message is successfully received but unsuccessfully processed
49
- # purpose is to return the message to the destination so receiving and processing and be attempted again
50
- def unreceive message, headers={}
51
- end
52
-
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={}
53
38
  end
54
39
 
55
- # I recommend having a destination object to represent each subscribed destination
56
- class Destination
57
- attr_accessor :name
40
+ # receive a single message from any of the subscribed destinations
41
+ # check each destination once, then sleep for poll_interval
42
+ def receive
43
+ end
58
44
 
59
- def to_s
60
- "<Base::Destination name='#{name}'>"
61
- end
45
+ # called after a message is successfully received and processed
46
+ def received message, headers={}
62
47
  end
63
48
 
64
- # based on stomp message
65
- # command = MESSAGE for successful message from adapter, ERROR for problem from adapter
66
- # !!!! must have headers['destination'] = subscription.destination in order to match message to subscription in gateway!!!!
67
- class Message
68
- attr_accessor :headers, :body, :command
69
-
70
- def initialize headers, id, body, response, destination, command='MESSAGE'
71
- @headers, @body, @command = headers, body, command
72
- headers['destination'] = destination.name
73
- end
74
-
75
- def to_s
76
- "<Base::Message body='#{body}' headers='#{headers.inspect}' command='#{command}' >"
77
- end
49
+ # called after a message is successfully received but unsuccessfully processed
50
+ # purpose is to return the message to the destination so receiving and processing and be attempted again
51
+ def unreceive message, headers={}
78
52
  end
79
-
53
+
80
54
  end
55
+
56
+ ## I recommend having a destination object to represent each subscribed destination
57
+ # class Destination
58
+ # attr_accessor :name
59
+ #
60
+ # def to_s
61
+ # "<Base::Destination name='#{name}'>"
62
+ # end
63
+ # end
64
+
65
+ ## You should also define your own message based on the BaseMessage class
66
+ # class Message < ActiveMessaging::BaseMessage
67
+ # end
68
+
81
69
  end
82
70
  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
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
@@ -25,7 +25,7 @@ module ActiveMessaging
25
25
  #this initialize is probably activemq specific. There might be a more generic
26
26
  #way of getting this without resorting to jndi lookup.
27
27
  eval <<-end_eval
28
- @connection_factory = Java::#{cfg[:connection_factory]}.new(@login, @password, @url)
28
+ @connection_factory = Java::#{cfg[:connection_factory]}.new(@login, @passcode, @url)
29
29
  end_eval
30
30
  elsif cfg.has_key? :jndi
31
31
  @connection_factory = javax.naming.InitialContext.new().lookup(cfg[:jndi])
@@ -164,18 +164,18 @@ module ActiveMessaging
164
164
  def condition_message message
165
165
  message.class.class_eval {
166
166
  alias_method :body, :text unless method_defined? :body
167
-
168
- def command
169
- "MESSAGE"
170
- end
171
-
167
+
172
168
  def headers
173
169
  destination.to_s =~ %r{(queue|topic)://(.*)}
174
170
  puts "/#{$1}/#{$2}"
175
171
  {'destination' => "/#{$1}/#{$2}"}
176
172
  end
177
173
 
178
- } unless message.nil? || message.respond_to?(:command)
174
+ def matches_subscription?(subscription)
175
+ self.headers['destination'].to_s == subscription.value.to_s
176
+ end
177
+
178
+ } unless message.nil? || message.respond_to?(:headers)
179
179
  message
180
180
  end
181
181
 
@@ -1,5 +1,8 @@
1
1
  require 'reliable-msg'
2
2
 
3
+ require 'activemessaging/adapters/base'
4
+
5
+ # add access to the queue_manager to use for adding transactions
3
6
  module ReliableMsg
4
7
 
5
8
  class Client
@@ -14,177 +17,170 @@ end
14
17
 
15
18
  module ActiveMessaging
16
19
  module Adapters
17
- module ReliableMsg
20
+ class ReliableMsgConnection < ActiveMessaging::Adapters::BaseConnection
18
21
 
19
22
  THREAD_OLD_TXS = :a13g_reliable_msg_old_txs
20
23
 
21
24
  QUEUE_PARAMS = [:expires,:delivery,:priority,:max_deliveries,:drb_uri,:tx_timeout,:connect_count]
22
25
  TOPIC_PARAMS = [:expires,:drb_uri,:tx_timeout,:connect_count]
23
26
 
24
- class Connection
25
- include ActiveMessaging::Adapter
27
+ register :reliable_msg
26
28
 
27
- register :reliable_msg
29
+ #configurable params
30
+ attr_accessor :subscriptions, :destinations, :poll_interval, :current_subscription, :tx_timeout
28
31
 
29
- #configurable params
30
- attr_accessor :reliable, :subscriptions, :destinations, :poll_interval, :current_subscription, :tx_timeout
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
31
37
 
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
38
+ @subscriptions = {}
39
+ @destinations = {}
40
+ @current_subscription = 0
41
+ end
37
42
 
38
- @subscriptions = {}
39
- @destinations = {}
40
- @current_subscription = 0
41
- end
43
+ # called to cleanly get rid of connection
44
+ def disconnect
45
+ nil
46
+ end
42
47
 
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
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)
58
57
  end
58
+ end
59
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
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
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
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
88
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
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
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.id, reliable_msg.object, reliable_msg.headers, destination_name, 'MESSAGE', @tx) if reliable_msg
127
-
128
- Thread.current[::ReliableMsg::Client::THREAD_CURRENT_TX] = nil
90
+ # receive a single message from any of the subscribed destinations
91
+ # check each destination once, then sleep for poll_interval
92
+ def receive
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
129
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
130
129
  end
131
130
  end
131
+ end
132
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
-
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
143
141
  end
144
142
 
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
143
  end
157
144
 
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
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
167
153
  end
154
+ end
168
155
 
169
- def remove
170
- @count -= 1
171
- end
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
172
168
 
169
+ def remove
170
+ @count -= 1
173
171
  end
174
172
 
175
- class Message
176
- attr_accessor :id, :body, :headers, :command, :transaction
177
-
178
- def initialize id, body, headers, destination_name, command='MESSAGE', transaction=nil
179
- @id, @body, @headers, @command, @transaction = id, body, headers, command, transaction
180
- headers['destination'] = destination_name
181
- end
173
+ end
174
+
175
+ class Message < ActiveMessaging::BaseMessage
176
+ attr_accessor :transaction
182
177
 
183
- def to_s
184
- "<ReliableMessaging::Message id='#{id}' body='#{body}' headers='#{headers.inspect}' command='#{command}' >"
185
- end
178
+ def initialize body, id, headers, destination, transaction=nil
179
+ super(body, id, headers, destination)
180
+ @transaction = transaction
186
181
  end
187
-
182
+
188
183
  end
184
+
189
185
  end
190
186
  end