torquebox-messaging 1.0.1-java → 1.1-java
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.
- data/lib/gem_hook.rb +1 -0
- data/lib/{jruby-complete-1.6.2.jar → jruby-complete-1.6.3.jar} +0 -0
- data/lib/torquebox/messaging/backgroundable.rb +12 -1
- data/lib/torquebox/messaging/client.rb +1 -0
- data/lib/torquebox/messaging/destination.rb +22 -10
- data/lib/torquebox/messaging/ext/javax_jms_session.rb +9 -1
- data/lib/torquebox/messaging/future.rb +112 -0
- data/lib/torquebox/messaging/future_responder.rb +92 -0
- data/lib/torquebox/messaging/future_status.rb +37 -0
- data/lib/torquebox/messaging/task.rb +19 -4
- data/lib/torquebox-base-core.jar +0 -0
- data/lib/torquebox-base-metadata.jar +0 -0
- data/lib/torquebox-base-spi.jar +0 -0
- data/lib/torquebox-mc-support.jar +0 -0
- data/lib/torquebox-messaging-core.jar +0 -0
- data/lib/torquebox-messaging.jar +0 -0
- data/lib/torquebox-messaging.rb +3 -3
- data/spec/backgroundable_spec.rb +29 -9
- data/spec/client_spec.rb +2 -5
- data/spec/destination_spec.rb +66 -3
- data/spec/future_spec.rb +59 -0
- data/spec/task_spec.rb +56 -24
- metadata +13 -8
data/lib/gem_hook.rb
CHANGED
Binary file
|
@@ -16,12 +16,15 @@
|
|
16
16
|
# 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
17
17
|
|
18
18
|
require 'torquebox/messaging/destination'
|
19
|
+
require 'torquebox/messaging/future'
|
20
|
+
require 'torquebox/messaging/future_status'
|
19
21
|
|
20
22
|
module TorqueBox
|
21
23
|
module Messaging
|
22
24
|
module Backgroundable
|
23
25
|
def self.included(base)
|
24
26
|
base.extend(ClassMethods)
|
27
|
+
base.send(:include, FutureStatus)
|
25
28
|
end
|
26
29
|
|
27
30
|
def background(options = { })
|
@@ -104,7 +107,15 @@ module TorqueBox
|
|
104
107
|
|
105
108
|
class << self
|
106
109
|
def publish_message(receiver, method, args, options = { })
|
107
|
-
Queue.new(QUEUE_NAME)
|
110
|
+
queue = Queue.new(QUEUE_NAME)
|
111
|
+
future = Future.new( queue )
|
112
|
+
queue.publish({:receiver => receiver,
|
113
|
+
:future_id => future.correlation_id,
|
114
|
+
:future_queue => QUEUE_NAME,
|
115
|
+
:method => method,
|
116
|
+
:args => args}, options)
|
117
|
+
|
118
|
+
future
|
108
119
|
rescue javax.naming.NameNotFoundException => ex
|
109
120
|
raise RuntimeError.new("The backgroundable queue is not available. Did you disable it by setting its concurrency to 0?")
|
110
121
|
end
|
@@ -56,6 +56,7 @@ module TorqueBox
|
|
56
56
|
TorqueBox::Naming.connect( naming_host, naming_port ) do |context|
|
57
57
|
connection_factory = context['/ConnectionFactory']
|
58
58
|
connection = connection_factory.createConnection
|
59
|
+
connection.client_id = options[:client_id]
|
59
60
|
session = connection.createSession( transacted, canonical_ack_mode( ack_mode ) )
|
60
61
|
connection.start
|
61
62
|
session.naming_context = context
|
@@ -1,15 +1,15 @@
|
|
1
1
|
# Copyright 2008-2011 Red Hat, Inc, and individual contributors.
|
2
|
-
#
|
2
|
+
#
|
3
3
|
# This is free software; you can redistribute it and/or modify it
|
4
4
|
# under the terms of the GNU Lesser General Public License as
|
5
5
|
# published by the Free Software Foundation; either version 2.1 of
|
6
6
|
# the License, or (at your option) any later version.
|
7
|
-
#
|
7
|
+
#
|
8
8
|
# This software is distributed in the hope that it will be useful,
|
9
9
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
10
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
11
11
|
# Lesser General Public License for more details.
|
12
|
-
#
|
12
|
+
#
|
13
13
|
# You should have received a copy of the GNU Lesser General Public
|
14
14
|
# License along with this software; if not, write to the Free
|
15
15
|
# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
@@ -25,14 +25,16 @@ module TorqueBox
|
|
25
25
|
|
26
26
|
module Destination
|
27
27
|
include Enumerable
|
28
|
-
|
29
|
-
attr_reader :name
|
30
28
|
|
29
|
+
attr_reader :name
|
30
|
+
attr_reader :connect_options
|
31
|
+
attr_reader :enumerable_options
|
32
|
+
|
31
33
|
PRIORITY_MAP = {
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
34
|
+
:low => 1,
|
35
|
+
:normal => 4,
|
36
|
+
:high => 7,
|
37
|
+
:critical => 9
|
36
38
|
}
|
37
39
|
|
38
40
|
def initialize(name, connect_options=nil, enumerable_options=nil)
|
@@ -91,7 +93,7 @@ module TorqueBox
|
|
91
93
|
end
|
92
94
|
end
|
93
95
|
end
|
94
|
-
|
96
|
+
|
95
97
|
def to_s
|
96
98
|
name
|
97
99
|
end
|
@@ -164,9 +166,19 @@ module TorqueBox
|
|
164
166
|
|
165
167
|
class Topic
|
166
168
|
include Destination
|
169
|
+
DEFAULT_SUBSCRIBER_NAME = 'subscriber-1'
|
170
|
+
|
167
171
|
def destination
|
168
172
|
@destination ||= Java::org.torquebox.messaging.core::ManagedTopic.new
|
169
173
|
end
|
174
|
+
|
175
|
+
def unsubscribe(name = DEFAULT_SUBSCRIBER_NAME, options = {})
|
176
|
+
wait_for_destination(options[:startup_timeout]) {
|
177
|
+
Client.connect(@connect_options) do |session|
|
178
|
+
session.unsubscribe(name)
|
179
|
+
end
|
180
|
+
}
|
181
|
+
end
|
170
182
|
end
|
171
183
|
|
172
184
|
end
|
@@ -46,7 +46,15 @@ module javax.jms::Session
|
|
46
46
|
timeout = options.fetch(:timeout, 0)
|
47
47
|
selector = options.fetch(:selector, nil)
|
48
48
|
destination = lookup_destination( destination_name )
|
49
|
-
|
49
|
+
if options[:durable] && destination.class.name =~ /Topic/
|
50
|
+
raise ArgumentError.new( "You must set the :client_id via Topic.new's connect_options to use :durable" ) unless connection.client_id
|
51
|
+
consumer = createDurableSubscriber( destination,
|
52
|
+
options.fetch(:subscriber_name, TorqueBox::Messaging::Topic::DEFAULT_SUBSCRIBER_NAME),
|
53
|
+
selector,
|
54
|
+
false )
|
55
|
+
else
|
56
|
+
consumer = createConsumer( destination, selector )
|
57
|
+
end
|
50
58
|
jms_message = consumer.receive( timeout )
|
51
59
|
if jms_message
|
52
60
|
decode ? jms_message.decode : jms_message
|
@@ -0,0 +1,112 @@
|
|
1
|
+
# Copyright 2008-2011 Red Hat, Inc, and individual contributors.
|
2
|
+
#
|
3
|
+
# This is free software; you can redistribute it and/or modify it
|
4
|
+
# under the terms of the GNU Lesser General Public License as
|
5
|
+
# published by the Free Software Foundation; either version 2.1 of
|
6
|
+
# the License, or (at your option) any later version.
|
7
|
+
#
|
8
|
+
# This software is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
11
|
+
# Lesser General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU Lesser General Public
|
14
|
+
# License along with this software; if not, write to the Free
|
15
|
+
# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
16
|
+
# 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
17
|
+
|
18
|
+
module TorqueBox
|
19
|
+
module Messaging
|
20
|
+
# A Future encapsulates the result of a long running
|
21
|
+
# process, and is used in conjunction with a {FutureResponder}.
|
22
|
+
class Future
|
23
|
+
|
24
|
+
# Returns the remote error (if any)
|
25
|
+
attr_reader :error
|
26
|
+
attr_reader :correlation_id
|
27
|
+
attr_accessor :default_result_timeout
|
28
|
+
|
29
|
+
# @param [TorqueBox::Messaging::Queue] response_queue The queue
|
30
|
+
# where response messages are to be received.
|
31
|
+
# @param [Hash] options Additional options
|
32
|
+
# @option options [String] :correlation_id (Future.unique_id) The correlation_id used on
|
33
|
+
# the messages to uniquely identify the call they are for.
|
34
|
+
# @option options [Integer] :default_result_timeout (30_000) The timeout
|
35
|
+
# used by default for the receive call. The processing must at
|
36
|
+
# least start before the timeout expires, and finish before 2x
|
37
|
+
# this timeout.
|
38
|
+
def initialize(response_queue, options = { })
|
39
|
+
@queue = response_queue
|
40
|
+
@correlation_id = options[:correlation_id] || self.class.unique_id
|
41
|
+
@default_result_timeout = options[:default_result_timeout] || 30_000
|
42
|
+
end
|
43
|
+
|
44
|
+
def started?
|
45
|
+
receive unless @started
|
46
|
+
@started
|
47
|
+
end
|
48
|
+
|
49
|
+
def complete?
|
50
|
+
receive unless @complete || @error
|
51
|
+
@complete
|
52
|
+
end
|
53
|
+
|
54
|
+
def error?
|
55
|
+
receive unless @complete || @error
|
56
|
+
!!@error
|
57
|
+
end
|
58
|
+
|
59
|
+
# Returns the latest response from the remote processor, if
|
60
|
+
# any. Status reporting is optional, and must be handled by the
|
61
|
+
# processed task itself.
|
62
|
+
# @see FutureResponder#status
|
63
|
+
def status
|
64
|
+
receive unless @complete || @error
|
65
|
+
@status
|
66
|
+
end
|
67
|
+
|
68
|
+
# Attempts to return the remote result.
|
69
|
+
# @param [Integer] timeout The processing must at least start
|
70
|
+
# before the timeout expires, and finish before 2x this timeout.
|
71
|
+
# @raise [TimeoutException] if the timeout expires when
|
72
|
+
# receiving the result
|
73
|
+
# @return the remote result
|
74
|
+
def result(timeout = default_result_timeout)
|
75
|
+
receive( timeout ) unless @started
|
76
|
+
raise TimeoutException.new( "timeout expired waiting for processing to start" ) unless @started
|
77
|
+
receive( timeout ) unless @complete || @error
|
78
|
+
raise TimeoutException.new( "timeout expired waiting for processing to finish" ) unless @complete || @error
|
79
|
+
raise @error if @error
|
80
|
+
@result
|
81
|
+
end
|
82
|
+
|
83
|
+
# Delegates to {#result} with the default timeout.
|
84
|
+
def method_missing(method, *args, &block)
|
85
|
+
result.send( method, *args, &block )
|
86
|
+
end
|
87
|
+
|
88
|
+
# @return [String] a unique id useful for correlating a
|
89
|
+
# result to its call
|
90
|
+
def self.unique_id
|
91
|
+
java.util.UUID.randomUUID.to_s
|
92
|
+
end
|
93
|
+
|
94
|
+
protected
|
95
|
+
def receive(timeout = 1)
|
96
|
+
response = @queue.receive( :timeout => timeout, :selector => "JMSCorrelationID = '#{@correlation_id}'" )
|
97
|
+
|
98
|
+
if response
|
99
|
+
@started = true
|
100
|
+
@status = response[:status] if response.has_key?( :status )
|
101
|
+
@complete = response.has_key?( :result )
|
102
|
+
@result ||= response[:result]
|
103
|
+
@error ||= response[:error]
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
|
109
|
+
class TimeoutException < RuntimeError; end
|
110
|
+
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# Copyright 2008-2011 Red Hat, Inc, and individual contributors.
|
2
|
+
#
|
3
|
+
# This is free software; you can redistribute it and/or modify it
|
4
|
+
# under the terms of the GNU Lesser General Public License as
|
5
|
+
# published by the Free Software Foundation; either version 2.1 of
|
6
|
+
# the License, or (at your option) any later version.
|
7
|
+
#
|
8
|
+
# This software is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
11
|
+
# Lesser General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU Lesser General Public
|
14
|
+
# License along with this software; if not, write to the Free
|
15
|
+
# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
16
|
+
# 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
17
|
+
|
18
|
+
module TorqueBox
|
19
|
+
module Messaging
|
20
|
+
# A FutureResponder encapsulates sending the results of a long
|
21
|
+
# running process to a {Future}.
|
22
|
+
class FutureResponder
|
23
|
+
|
24
|
+
# @param [TorqueBox::Messaging::Queue] response_queue The queue
|
25
|
+
# where response messages are to be published.
|
26
|
+
# @param [String] correlation_id The correlation_id used on
|
27
|
+
# the messages to uniquely identify the call they are for.
|
28
|
+
# @param [Integer] message_ttl The time-to-live used on messages
|
29
|
+
# to prevent them from staying in the queue indefinately if
|
30
|
+
# the result is never accessed.
|
31
|
+
def initialize(response_queue, correlation_id, message_ttl = 600_000)
|
32
|
+
@queue = response_queue
|
33
|
+
@correlation_id = correlation_id
|
34
|
+
@message_ttl = message_ttl
|
35
|
+
end
|
36
|
+
|
37
|
+
# Signal that processing has started.
|
38
|
+
def started
|
39
|
+
publish( :started => true, :priority => :low )
|
40
|
+
end
|
41
|
+
|
42
|
+
# Report the current status back to the client. The status value
|
43
|
+
# is application specific.
|
44
|
+
def status=(status)
|
45
|
+
publish( :status => status )
|
46
|
+
end
|
47
|
+
|
48
|
+
# Signal that processing has completed.
|
49
|
+
# @param The result of the operation.
|
50
|
+
def result=(result)
|
51
|
+
publish( :result => result, :priority => :high )
|
52
|
+
end
|
53
|
+
|
54
|
+
# Signal that an error occurred during processing.
|
55
|
+
# @param [Exception] The error!
|
56
|
+
def error=(error)
|
57
|
+
publish( :error => error, :priority => :high )
|
58
|
+
end
|
59
|
+
|
60
|
+
# Handles started/complete/error for you around the given
|
61
|
+
# block. The current responder is avaiable inside the block via
|
62
|
+
# {.current}, which is useful for sending {#status} messages.
|
63
|
+
def respond
|
64
|
+
started
|
65
|
+
Thread.current[:future_responder] = self
|
66
|
+
self.result = yield
|
67
|
+
rescue Exception => e
|
68
|
+
self.error = e
|
69
|
+
puts "FutureResponder#respond: An error occured: ", e
|
70
|
+
puts e.backtrace.join( "\n" )
|
71
|
+
end
|
72
|
+
|
73
|
+
# Convenience method that returns the thread local
|
74
|
+
# responder. Only valid inside a block passed to {#respond}.
|
75
|
+
def self.current
|
76
|
+
Thread.current[:future_responder]
|
77
|
+
end
|
78
|
+
|
79
|
+
# Convenience method that allows you to send a status message
|
80
|
+
# via the {.current} responder. Only valid inside a block passed
|
81
|
+
# to {#respond}.
|
82
|
+
def self.status=(status)
|
83
|
+
current.status = status if current
|
84
|
+
end
|
85
|
+
|
86
|
+
protected
|
87
|
+
def publish(message)
|
88
|
+
@queue.publish( message, :correlation_id => @correlation_id, :ttl => @message_ttl )
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# Copyright 2008-2011 Red Hat, Inc, and individual contributors.
|
2
|
+
#
|
3
|
+
# This is free software; you can redistribute it and/or modify it
|
4
|
+
# under the terms of the GNU Lesser General Public License as
|
5
|
+
# published by the Free Software Foundation; either version 2.1 of
|
6
|
+
# the License, or (at your option) any later version.
|
7
|
+
#
|
8
|
+
# This software is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
11
|
+
# Lesser General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU Lesser General Public
|
14
|
+
# License along with this software; if not, write to the Free
|
15
|
+
# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
16
|
+
# 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
17
|
+
|
18
|
+
require 'torquebox/messaging/future_responder'
|
19
|
+
|
20
|
+
module TorqueBox
|
21
|
+
module Messaging
|
22
|
+
module FutureStatus
|
23
|
+
|
24
|
+
def __future
|
25
|
+
@__future ||= FutureProxy.new
|
26
|
+
end
|
27
|
+
alias_method :future, :__future
|
28
|
+
|
29
|
+
class FutureProxy
|
30
|
+
def status=(status)
|
31
|
+
FutureResponder.status = status
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
@@ -16,27 +16,42 @@
|
|
16
16
|
# 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
17
17
|
|
18
18
|
require 'torquebox/messaging/destination'
|
19
|
+
require 'torquebox/messaging/future_responder'
|
20
|
+
require 'torquebox/messaging/future'
|
21
|
+
require 'torquebox/messaging/future_status'
|
19
22
|
|
20
23
|
module TorqueBox
|
21
24
|
module Messaging
|
22
25
|
|
23
26
|
class Task
|
24
|
-
|
27
|
+
include FutureStatus
|
28
|
+
|
25
29
|
def self.queue_name
|
26
30
|
suffix = org.torquebox.common.util.StringUtils.underscore(name[0...-4])
|
27
31
|
"/queues/torquebox/#{ENV['TORQUEBOX_APP_NAME']}/tasks/#{suffix}"
|
28
32
|
end
|
29
33
|
|
30
34
|
def self.async(method, payload = {}, options = {})
|
31
|
-
|
32
|
-
|
35
|
+
queue = Queue.new(queue_name)
|
36
|
+
future = Future.new( queue )
|
37
|
+
message = {
|
38
|
+
:method => method,
|
39
|
+
:payload => payload,
|
40
|
+
:future_id => future.correlation_id,
|
41
|
+
:future_queue => queue_name
|
42
|
+
}
|
43
|
+
queue.publish( message, options )
|
44
|
+
|
45
|
+
future
|
33
46
|
rescue javax.naming.NameNotFoundException => ex
|
34
47
|
raise RuntimeError.new("The queue for #{self.name} is not available. Did you disable it by setting its concurrency to 0?")
|
35
48
|
end
|
36
49
|
|
37
50
|
def process!(message)
|
38
51
|
hash = message.decode
|
39
|
-
|
52
|
+
FutureResponder.new( Queue.new( hash[:future_queue] ), hash[:future_id] ).respond do
|
53
|
+
self.send hash[:method].to_sym, hash[:payload]
|
54
|
+
end
|
40
55
|
end
|
41
56
|
|
42
57
|
end
|
data/lib/torquebox-base-core.jar
CHANGED
Binary file
|
Binary file
|
data/lib/torquebox-base-spi.jar
CHANGED
Binary file
|
Binary file
|
Binary file
|
data/lib/torquebox-messaging.jar
CHANGED
Binary file
|
data/lib/torquebox-messaging.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module TorqueboxMessaging
|
2
|
-
VERSION = '1.
|
3
|
-
MAVEN_VERSION = '1.
|
2
|
+
VERSION = '1.1'
|
3
|
+
MAVEN_VERSION = '1.1'
|
4
4
|
end
|
5
5
|
begin
|
6
6
|
require 'java'
|
@@ -21,7 +21,7 @@ begin
|
|
21
21
|
require File.dirname(__FILE__) + '/activation-1.1.jar'
|
22
22
|
require File.dirname(__FILE__) + '/jaxb-api-2.1.9.jar'
|
23
23
|
require File.dirname(__FILE__) + '/torquebox-base-spi.jar'
|
24
|
-
require File.dirname(__FILE__) + '/jruby-complete-1.6.
|
24
|
+
require File.dirname(__FILE__) + '/jruby-complete-1.6.3.jar'
|
25
25
|
require File.dirname(__FILE__) + '/torquebox-base-metadata.jar'
|
26
26
|
require File.dirname(__FILE__) + '/torquebox-base-core.jar'
|
27
27
|
require File.dirname(__FILE__) + '/picketbox-bare-3.0.0.CR2.jar'
|
data/spec/backgroundable_spec.rb
CHANGED
@@ -62,6 +62,7 @@ describe TorqueBox::Messaging::Backgroundable do
|
|
62
62
|
@queue = mock('queue')
|
63
63
|
@queue.stub(:publish)
|
64
64
|
TorqueBox::Messaging::Queue.stub(:new).and_return(@queue)
|
65
|
+
TorqueBox::Messaging::Future.stub(:unique_id).and_return('1234')
|
65
66
|
end
|
66
67
|
|
67
68
|
it "should put a message on the queue" do
|
@@ -69,9 +70,20 @@ describe TorqueBox::Messaging::Backgroundable do
|
|
69
70
|
MyTestModel.new.an_async_action(nil, nil)
|
70
71
|
end
|
71
72
|
|
72
|
-
it "should
|
73
|
+
it "should return a future" do
|
74
|
+
result = MyTestModel.new.an_async_action(nil, nil)
|
75
|
+
result.is_a?(TorqueBox::Messaging::Future).should be_true
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should include the proper options in the message" do
|
73
79
|
object = MyTestModel.new
|
74
|
-
@queue.should_receive(:publish).with({
|
80
|
+
@queue.should_receive(:publish).with({
|
81
|
+
:receiver => object,
|
82
|
+
:future_id => '1234',
|
83
|
+
:future_queue => "/queues/torquebox//backgroundable",
|
84
|
+
:method => '__sync_an_async_action',
|
85
|
+
:args => [:a, :b]
|
86
|
+
}, { })
|
75
87
|
object.an_async_action(:a, :b)
|
76
88
|
end
|
77
89
|
|
@@ -99,21 +111,27 @@ describe TorqueBox::Messaging::Backgroundable do
|
|
99
111
|
|
100
112
|
it "should queue any method called on it" do
|
101
113
|
@queue.should_receive(:publish).with({:receiver => anything,
|
102
|
-
|
103
|
-
:args => anything
|
114
|
+
:method => :foo,
|
115
|
+
:args => anything,
|
116
|
+
:future_id => anything,
|
117
|
+
:future_queue => anything}, { })
|
104
118
|
@object.background.foo
|
105
119
|
end
|
106
120
|
|
107
121
|
it "should queue the receiver" do
|
108
122
|
@queue.should_receive(:publish).with({:receiver => @object,
|
109
|
-
|
110
|
-
:args => anything
|
123
|
+
:method => anything,
|
124
|
+
:args => anything,
|
125
|
+
:future_id => anything,
|
126
|
+
:future_queue => anything}, { })
|
111
127
|
@object.background.foo
|
112
128
|
end
|
113
129
|
|
114
130
|
it "should queue the args" do
|
115
131
|
@queue.should_receive(:publish).with({:receiver => anything,
|
116
|
-
|
132
|
+
:method => anything,
|
133
|
+
:future_id => anything,
|
134
|
+
:future_queue => anything,
|
117
135
|
:args => [1,2]}, {})
|
118
136
|
@object.background.foo(1,2)
|
119
137
|
end
|
@@ -131,8 +149,10 @@ describe TorqueBox::Messaging::Backgroundable do
|
|
131
149
|
|
132
150
|
it "should pass through any options" do
|
133
151
|
@queue.should_receive(:publish).with({:receiver => anything,
|
134
|
-
|
135
|
-
:args => anything
|
152
|
+
:method => anything,
|
153
|
+
:args => anything,
|
154
|
+
:future_id => anything,
|
155
|
+
:future_queue => anything},
|
136
156
|
{:ttl => 1})
|
137
157
|
@object.background(:ttl => 1).foo
|
138
158
|
end
|
data/spec/client_spec.rb
CHANGED
@@ -79,7 +79,7 @@ describe TorqueBox::Messaging::Client do
|
|
79
79
|
received_message.should eql( message )
|
80
80
|
end
|
81
81
|
|
82
|
-
it "should
|
82
|
+
it "should properly decode a non-String message" do
|
83
83
|
received_message = nil
|
84
84
|
TorqueBox::Messaging::Client.connect() do |session|
|
85
85
|
session.publish( '/queues/foo', [] )
|
@@ -88,10 +88,9 @@ describe TorqueBox::Messaging::Client do
|
|
88
88
|
session.commit
|
89
89
|
end
|
90
90
|
received_message.decode.should eql( [] )
|
91
|
-
received_message.get_string_property( 'torquebox_encoding' ).should eql( 'base64' )
|
92
91
|
end
|
93
92
|
|
94
|
-
it "should
|
93
|
+
it "should properly decode a String message" do
|
95
94
|
received_message = nil
|
96
95
|
TorqueBox::Messaging::Client.connect() do |session|
|
97
96
|
session.publish( '/queues/foo', "foo" )
|
@@ -99,9 +98,7 @@ describe TorqueBox::Messaging::Client do
|
|
99
98
|
received_message = session.receive( '/queues/foo', :decode => false )
|
100
99
|
session.commit
|
101
100
|
end
|
102
|
-
received_message.text.should eql( "foo" )
|
103
101
|
received_message.decode.should eql( "foo" )
|
104
|
-
received_message.get_string_property( 'torquebox_encoding' ).should be_nil
|
105
102
|
end
|
106
103
|
|
107
104
|
it "should timeout if asked" do
|
data/spec/destination_spec.rb
CHANGED
@@ -144,7 +144,7 @@ describe TorqueBox::Messaging::Destination do
|
|
144
144
|
queue = TorqueBox::Messaging::Queue.new "/queues/browseable"
|
145
145
|
queue.start
|
146
146
|
queue.publish "howdy"
|
147
|
-
queue.first.
|
147
|
+
queue.first.decode.should == 'howdy'
|
148
148
|
queue.destroy
|
149
149
|
end
|
150
150
|
|
@@ -153,8 +153,9 @@ describe TorqueBox::Messaging::Destination do
|
|
153
153
|
queue.start
|
154
154
|
queue.publish "howdy", :properties => {:blurple => 5}
|
155
155
|
queue.publish "ahoyhoy", :properties => {:blurple => 6}
|
156
|
-
queue.first.
|
157
|
-
queue.detect { |m| m.
|
156
|
+
queue.first.decode.should == 'ahoyhoy'
|
157
|
+
queue.detect { |m| m.decode == 'howdy' }.should be_nil
|
158
|
+
queue.detect { |m| m.decode == 'ahoyhoy' }.should_not be_nil
|
158
159
|
queue.destroy
|
159
160
|
|
160
161
|
end
|
@@ -183,6 +184,18 @@ describe TorqueBox::Messaging::Destination do
|
|
183
184
|
message.should eql( "howdy" )
|
184
185
|
end
|
185
186
|
|
187
|
+
it "should receive a binary file correctly" do
|
188
|
+
queue = TorqueBox::Messaging::Queue.new "/queues/foo"
|
189
|
+
queue.start
|
190
|
+
|
191
|
+
data = File.open("#{File.dirname(__FILE__)}/../src/test/resources/sample.pdf", "r") { |file| file.read }
|
192
|
+
queue.publish data
|
193
|
+
message = queue.receive
|
194
|
+
|
195
|
+
queue.destroy
|
196
|
+
message.should eql( data )
|
197
|
+
end
|
198
|
+
|
186
199
|
it "should publish to multiple topic consumers" do
|
187
200
|
topic = TorqueBox::Messaging::Topic.new "/topics/foo"
|
188
201
|
topic.start
|
@@ -201,6 +214,56 @@ describe TorqueBox::Messaging::Destination do
|
|
201
214
|
msgs.to_a.should eql( ["howdy"] * count )
|
202
215
|
end
|
203
216
|
|
217
|
+
context "durable topics" do
|
218
|
+
describe 'receive' do
|
219
|
+
it "should be durable" do
|
220
|
+
topic = TorqueBox::Messaging::Topic.new "/topics/foo", :client_id => 'blarg'
|
221
|
+
topic.start
|
222
|
+
|
223
|
+
topic.receive :durable => true, :timeout => 1
|
224
|
+
topic.publish 'biscuit'
|
225
|
+
response = topic.receive :durable => true, :timeout => 10_000
|
226
|
+
response.should == 'biscuit'
|
227
|
+
|
228
|
+
topic.destroy
|
229
|
+
end
|
230
|
+
|
231
|
+
it "should raise if client_id is not set" do
|
232
|
+
topic = TorqueBox::Messaging::Topic.new "/topics/foo"
|
233
|
+
topic.start
|
234
|
+
|
235
|
+
lambda { topic.receive :durable => true, :timeout => 1 }.should raise_error(ArgumentError)
|
236
|
+
|
237
|
+
topic.destroy
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
describe 'unsubscribe' do
|
242
|
+
it "should work" do
|
243
|
+
topic = TorqueBox::Messaging::Topic.new "/topics/foo", :client_id => 'blarg'
|
244
|
+
topic.start
|
245
|
+
|
246
|
+
topic.receive :durable => true, :timeout => 1
|
247
|
+
topic.publish 'biscuit'
|
248
|
+
response = topic.receive :durable => true, :timeout => 10_000
|
249
|
+
response.should == 'biscuit'
|
250
|
+
|
251
|
+
topic.unsubscribe
|
252
|
+
|
253
|
+
topic.publish 'ham'
|
254
|
+
response = topic.receive :durable => true, :timeout => 10
|
255
|
+
response.should be_nil
|
256
|
+
|
257
|
+
topic.publish 'gravy'
|
258
|
+
response = topic.receive :durable => true, :timeout => 10_000
|
259
|
+
response.should == 'gravy'
|
260
|
+
|
261
|
+
topic.destroy
|
262
|
+
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
204
267
|
context "synchronous messaging" do
|
205
268
|
it "should return value of block given to receive_and_publish" do
|
206
269
|
queue = TorqueBox::Messaging::Queue.new "/queues/publish_and_receive"
|
data/spec/future_spec.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'torquebox/messaging/future'
|
2
|
+
|
3
|
+
include TorqueBox::Messaging
|
4
|
+
|
5
|
+
class Future
|
6
|
+
attr_writer :started
|
7
|
+
attr_writer :complete
|
8
|
+
attr_writer :error
|
9
|
+
attr_writer :result
|
10
|
+
end
|
11
|
+
|
12
|
+
describe TorqueBox::Messaging::Future do
|
13
|
+
|
14
|
+
before(:each) do
|
15
|
+
@queue = mock( Queue )
|
16
|
+
@future = Future.new( @queue )
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "#result" do
|
20
|
+
|
21
|
+
it "should raise if it fails to start before timeout" do
|
22
|
+
@future.stub(:receive)
|
23
|
+
lambda { @future.result( 1 ) }.should raise_error( TimeoutException )
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should raise if it fails to complete before timeout" do
|
27
|
+
@future.stub(:receive)
|
28
|
+
@future.started = true
|
29
|
+
lambda { @future.result( 1 ) }.should raise_error( TimeoutException )
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should raise if a remote error occurs" do
|
33
|
+
@future.stub(:receive)
|
34
|
+
@future.started = true
|
35
|
+
@future.error = ArgumentError.new
|
36
|
+
lambda { @future.result( 1 ) }.should raise_error( ArgumentError )
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should return the result if complete" do
|
40
|
+
@future.stub(:receive)
|
41
|
+
@future.started = true
|
42
|
+
@future.complete = true
|
43
|
+
@future.result = :success!
|
44
|
+
@future.result.should == :success!
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "#method_missing" do
|
50
|
+
|
51
|
+
it "should delegate to #result" do
|
52
|
+
@result = mock(:result)
|
53
|
+
@future.should_receive(:result).and_return(@result)
|
54
|
+
@result.should_receive(:blah)
|
55
|
+
@future.blah
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
data/spec/task_spec.rb
CHANGED
@@ -1,39 +1,71 @@
|
|
1
|
-
|
1
|
+
require 'torquebox/messaging/future_responder'
|
2
|
+
require 'torquebox/messaging/future'
|
3
|
+
require 'torquebox/messaging/destination'
|
2
4
|
require 'torquebox/messaging/task'
|
3
5
|
|
4
|
-
class MyTestTask < TorqueBox::Messaging::Task
|
6
|
+
class MyTestTask < TorqueBox::Messaging::Task
|
5
7
|
attr_accessor :payload
|
8
|
+
|
9
|
+
def action(payload={ })
|
10
|
+
future.status = 1
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class TorqueBox::Messaging::FutureResponder
|
15
|
+
def respond
|
16
|
+
yield
|
17
|
+
end
|
6
18
|
end
|
7
19
|
|
8
20
|
describe TorqueBox::Messaging::Task do
|
9
21
|
|
10
|
-
it "should send payload correctly" do
|
11
|
-
expectation = [{:method => :payload=, :payload => {:foo => 'bar'}}, { }]
|
12
|
-
queue = mock("queue")
|
13
|
-
queue.should_receive(:publish).with(*expectation)
|
14
|
-
TorqueBox::Messaging::Queue.should_receive(:new).with(MyTestTask.queue_name).and_return(queue)
|
15
22
|
|
16
|
-
|
17
|
-
|
23
|
+
describe '#async' do
|
24
|
+
before(:each) do
|
25
|
+
TorqueBox::Messaging::Future.stub(:unique_id).and_return('1234')
|
26
|
+
@send_queue = mock('queue')
|
27
|
+
@send_queue.stub(:publish)
|
28
|
+
TorqueBox::Messaging::Queue.should_receive(:new).with(MyTestTask.queue_name).and_return(@send_queue)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should send payload correctly" do
|
32
|
+
expectation = [{:method => :payload=, :payload => {:foo => 'bar'}, :future_id => '1234', :future_queue => MyTestTask.queue_name}, { }]
|
33
|
+
@send_queue.should_receive(:publish).with(*expectation)
|
34
|
+
|
35
|
+
MyTestTask.async(:payload=, :foo => 'bar')
|
36
|
+
end
|
18
37
|
|
19
|
-
|
20
|
-
|
21
|
-
message = mock("message")
|
22
|
-
message.should_receive(:decode).and_return(expectation)
|
38
|
+
it "should handle nil payload as empty hash" do
|
39
|
+
@send_queue.should_receive(:publish).with(hash_including(:payload => {}), {})
|
23
40
|
|
24
|
-
|
25
|
-
|
26
|
-
task.payload[:foo].should == 'bar'
|
27
|
-
end
|
41
|
+
MyTestTask.async(:payload=)
|
42
|
+
end
|
28
43
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
MyTestTask.async(:payload=)
|
44
|
+
it "should return a future" do
|
45
|
+
result = MyTestTask.async(:payload=)
|
46
|
+
result.is_a?(TorqueBox::Messaging::Future).should be_true
|
47
|
+
end
|
34
48
|
end
|
35
49
|
|
50
|
+
describe "#process!" do
|
51
|
+
it "should process payload correctly" do
|
52
|
+
expectation = {:method => :payload=, :payload => {:foo => 'bar'}, :future_id => '1234', :future_queue => MyTestTask.queue_name}
|
53
|
+
message = mock("message")
|
54
|
+
message.should_receive(:decode).and_return(expectation)
|
36
55
|
|
56
|
+
task = MyTestTask.new
|
57
|
+
task.process! message
|
58
|
+
task.payload[:foo].should == 'bar'
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe 'the future proxy' do
|
63
|
+
it "should be available inside a task method" do
|
64
|
+
TorqueBox::Messaging::FutureResponder.should_receive(:status=).with(1)
|
65
|
+
MyTestTask.new.action
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
37
69
|
describe "queue_name" do
|
38
70
|
before(:each) do
|
39
71
|
ENV['TORQUEBOX_APP_NAME'] = 'app_name'
|
@@ -42,11 +74,11 @@ describe TorqueBox::Messaging::Task do
|
|
42
74
|
after(:each) do
|
43
75
|
ENV.delete('TORQUEBOX_APP_NAME')
|
44
76
|
end
|
45
|
-
|
77
|
+
|
46
78
|
it "should derive the queue name from the class name" do
|
47
79
|
MyTestTask.queue_name.should =~ %r{/my_test$}
|
48
80
|
end
|
49
|
-
|
81
|
+
|
50
82
|
it "should include the app name in the queue name" do
|
51
83
|
MyTestTask.queue_name.should =~ %r{/app_name/}
|
52
84
|
end
|
metadata
CHANGED
@@ -2,15 +2,15 @@
|
|
2
2
|
name: torquebox-messaging
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 1.
|
5
|
+
version: "1.1"
|
6
6
|
platform: java
|
7
|
-
authors: []
|
7
|
+
authors: ["The TorqueBox Team"]
|
8
8
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-
|
13
|
+
date: 2011-07-13 00:00:00 -04:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -21,7 +21,7 @@ dependencies:
|
|
21
21
|
requirements:
|
22
22
|
- - "="
|
23
23
|
- !ruby/object:Gem::Version
|
24
|
-
version: 1.
|
24
|
+
version: "1.1"
|
25
25
|
type: :runtime
|
26
26
|
version_requirements: *id001
|
27
27
|
- !ruby/object:Gem::Dependency
|
@@ -32,7 +32,7 @@ dependencies:
|
|
32
32
|
requirements:
|
33
33
|
- - "="
|
34
34
|
- !ruby/object:Gem::Version
|
35
|
-
version: 1.
|
35
|
+
version: "1.1"
|
36
36
|
type: :development
|
37
37
|
version_requirements: *id002
|
38
38
|
- !ruby/object:Gem::Dependency
|
@@ -43,7 +43,7 @@ dependencies:
|
|
43
43
|
requirements:
|
44
44
|
- - "="
|
45
45
|
- !ruby/object:Gem::Version
|
46
|
-
version: 1.
|
46
|
+
version: "1.1"
|
47
47
|
type: :development
|
48
48
|
version_requirements: *id003
|
49
49
|
- !ruby/object:Gem::Dependency
|
@@ -54,7 +54,7 @@ dependencies:
|
|
54
54
|
requirements:
|
55
55
|
- - "="
|
56
56
|
- !ruby/object:Gem::Version
|
57
|
-
version: 1.
|
57
|
+
version: "1.1"
|
58
58
|
type: :runtime
|
59
59
|
version_requirements: *id004
|
60
60
|
- !ruby/object:Gem::Dependency
|
@@ -96,7 +96,7 @@ files:
|
|
96
96
|
- lib/activation-1.1.jar
|
97
97
|
- lib/jaxb-api-2.1.9.jar
|
98
98
|
- lib/torquebox-base-spi.jar
|
99
|
-
- lib/jruby-complete-1.6.
|
99
|
+
- lib/jruby-complete-1.6.3.jar
|
100
100
|
- lib/torquebox-base-metadata.jar
|
101
101
|
- lib/torquebox-base-core.jar
|
102
102
|
- lib/picketbox-bare-3.0.0.CR2.jar
|
@@ -116,6 +116,9 @@ files:
|
|
116
116
|
- lib/torquebox/messaging/backgroundable.rb
|
117
117
|
- lib/torquebox/messaging/client.rb
|
118
118
|
- lib/torquebox/messaging/destination.rb
|
119
|
+
- lib/torquebox/messaging/future.rb
|
120
|
+
- lib/torquebox/messaging/future_responder.rb
|
121
|
+
- lib/torquebox/messaging/future_status.rb
|
119
122
|
- lib/torquebox/messaging/task.rb
|
120
123
|
- lib/torquebox/messaging/ext/javax_jms_queue_browser.rb
|
121
124
|
- lib/torquebox/messaging/ext/javax_jms_session.rb
|
@@ -124,6 +127,7 @@ files:
|
|
124
127
|
- spec/destination_spec.rb
|
125
128
|
- spec/dispatcher-queues.yml
|
126
129
|
- spec/dispatcher_not_running.rb
|
130
|
+
- spec/future_spec.rb
|
127
131
|
- spec/queues.yml
|
128
132
|
- spec/task_spec.rb
|
129
133
|
- spec/ext/java_jmx_session_spec.rb
|
@@ -159,5 +163,6 @@ test_files:
|
|
159
163
|
- spec/backgroundable_spec.rb
|
160
164
|
- spec/client_spec.rb
|
161
165
|
- spec/destination_spec.rb
|
166
|
+
- spec/future_spec.rb
|
162
167
|
- spec/task_spec.rb
|
163
168
|
- spec/ext/java_jmx_session_spec.rb
|