jruby-hornetq 0.2.0.alpha → 0.2.1.alpha
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/HISTORY.md +8 -0
- data/README.md +88 -5
- data/Rakefile +4 -4
- data/bin/hornetq_server +26 -55
- data/examples/{batch_client.rb → client/advanced/batch_client.rb} +11 -4
- data/examples/{client.rb → client/advanced/client.rb} +8 -10
- data/examples/{consumer.rb → client/advanced/consumer.rb} +2 -2
- data/examples/{hornetq.yml → client/advanced/hornetq.yml} +11 -10
- data/examples/{multi_client.rb → client/advanced/multi_client.rb} +6 -3
- data/examples/{multi_consumer.rb → client/advanced/multi_consumer.rb} +2 -2
- data/examples/{producer.rb → client/advanced/producer.rb} +3 -4
- data/examples/{server.rb → client/advanced/server.rb} +6 -9
- data/examples/client/client.rb +31 -0
- data/examples/client/consumer.rb +22 -0
- data/examples/client/invm.rb +38 -0
- data/examples/client/producer.rb +21 -0
- data/examples/client/server.rb +31 -0
- data/examples/server/backup_server.yml +6 -0
- data/examples/server/live_server.yml +1 -0
- data/examples/server/standalone_server.yml +1 -0
- data/lib/data/bindings/hornetq-bindings-1.bindings +0 -0
- data/lib/data/bindings/hornetq-bindings-2.bindings +0 -0
- data/lib/hornetq.rb +30 -9
- data/lib/hornetq/client.rb +19 -0
- data/lib/hornetq/{hornet_q_client.rb → client/factory.rb} +85 -88
- data/lib/hornetq/{org_hornetq_api_core_client_client_session.rb → client/org_hornetq_api_core_client_client_session.rb} +2 -2
- data/lib/hornetq/{org_hornetq_core_client_impl_client_message_impl.rb → client/org_hornetq_core_client_impl_client_message_impl.rb} +62 -2
- data/lib/hornetq/{org_hornetq_core_client_impl_client_producer_impl.rb → client/org_hornetq_core_client_impl_client_producer_impl.rb} +0 -0
- data/lib/hornetq/{org_hornetq_utils_typed_properties.rb → client/org_hornetq_utils_typed_properties.rb} +0 -0
- data/lib/hornetq/{client_requestor.rb → client/requestor.rb} +2 -2
- data/lib/hornetq/{client_server.rb → client/server.rb} +2 -2
- data/lib/hornetq/{session_pool.rb → client/session_pool.rb} +20 -20
- data/lib/hornetq/{lib → java}/hornetq-core-client.jar +0 -0
- data/lib/hornetq/{lib → java}/hornetq-core.jar +0 -0
- data/lib/hornetq/{lib → java}/netty.jar +0 -0
- data/lib/hornetq/org_hornetq_core_server_hornet_q_server.rb +13 -0
- data/lib/hornetq/server.rb +12 -0
- data/lib/hornetq/server/factory.rb +86 -0
- data/lib/hornetq/uri.rb +59 -0
- data/test/server_factory_test.rb +184 -0
- data/test/uri_test.rb +74 -0
- metadata +44 -28
- data/examples/backup_server.yml +0 -4
- data/examples/live_server.yml +0 -5
- data/examples/run_broker.rb +0 -59
- data/examples/standalone_server.yml +0 -3
@@ -4,13 +4,13 @@ module Java::org.hornetq.api.core.client::ClientSession
|
|
4
4
|
# To be consistent create Requestor from Session
|
5
5
|
def create_requestor(request_address)
|
6
6
|
#Java::org.hornetq.api.core.client::ClientRequestor.new(self, request_address);
|
7
|
-
|
7
|
+
HornetQ::Client::Requestor.new(self, request_address)
|
8
8
|
end
|
9
9
|
|
10
10
|
# Create a server handler for receiving requests and responding with
|
11
11
|
# replies to the supplied address
|
12
12
|
def create_server(input_queue, timeout=0)
|
13
|
-
|
13
|
+
HornetQ::Client::Server.new(self, input_queue, timeout)
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
@@ -18,7 +18,7 @@ class Java::OrgHornetqCoreClientImpl::ClientMessageImpl
|
|
18
18
|
# Set the Reply To Queue Name
|
19
19
|
# When supplied, the consumer of the message is expected to send a response to the
|
20
20
|
# specified queue. However, this is by convention, so no response is guaranteed
|
21
|
-
# Note: Rather than set this directly, consider creating a
|
21
|
+
# Note: Rather than set this directly, consider creating a Client::Requestor:
|
22
22
|
# requestor = session.create_requestor('Request Queue')
|
23
23
|
#
|
24
24
|
def reply_to_queue_name=(name)
|
@@ -42,8 +42,13 @@ class Java::OrgHornetqCoreClientImpl::ClientMessageImpl
|
|
42
42
|
# WARNING: Do not call after setting the body otherwise the send will have
|
43
43
|
# an empty body
|
44
44
|
def body
|
45
|
+
# Allow this buffer to be read multiple times
|
46
|
+
body_buffer.reset_reader_index
|
47
|
+
|
45
48
|
case type
|
46
49
|
when Java::org.hornetq.api.core.Message::BYTES_TYPE #4
|
50
|
+
buf = body_buffer
|
51
|
+
String.new(buf.read_bytes(buf.readable_bytes))
|
47
52
|
when Java::org.hornetq.api.core.Message::DEFAULT_TYPE #0
|
48
53
|
when Java::org.hornetq.api.core.Message::MAP_TYPE #5
|
49
54
|
Java::org.hornetq.utils::TypedProperties.new.decode(body_buffer)
|
@@ -60,10 +65,11 @@ class Java::OrgHornetqCoreClientImpl::ClientMessageImpl
|
|
60
65
|
#
|
61
66
|
# Data is automatically converted based on the message type
|
62
67
|
#
|
63
|
-
#
|
68
|
+
# DEPRECATED
|
64
69
|
def <<(data)
|
65
70
|
case type
|
66
71
|
when Java::org.hornetq.api.core.Message::BYTES_TYPE #4
|
72
|
+
body_buffer.write_bytes(data)
|
67
73
|
when Java::org.hornetq.api.core.Message::DEFAULT_TYPE #0
|
68
74
|
raise "Cannot use Message#<< when the Message#type has not been set"
|
69
75
|
when Java::org.hornetq.api.core.Message::MAP_TYPE #5
|
@@ -89,6 +95,60 @@ class Java::OrgHornetqCoreClientImpl::ClientMessageImpl
|
|
89
95
|
end
|
90
96
|
end
|
91
97
|
|
98
|
+
# Set the body of the message
|
99
|
+
# The type of the message is automatically set based on the type passed in.
|
100
|
+
# The following types are automatically supported in order of priority
|
101
|
+
# String => :text
|
102
|
+
# Java::org.hornetq.api.core::SimpleString => :text
|
103
|
+
# Java::org.hornetq.utils::TypedProperties => :map
|
104
|
+
# Hash (actually any object responding to => :map
|
105
|
+
def body=(data)
|
106
|
+
body_buffer.reset_writer_index
|
107
|
+
if data.is_a? String
|
108
|
+
# Ruby String
|
109
|
+
self.type = Java::org.hornetq.api.core.Message::TEXT_TYPE
|
110
|
+
body_buffer.writeNullableSimpleString(Java::org.hornetq.api.core::SimpleString.new(data))
|
111
|
+
elsif data.is_a? Java::org.hornetq.api.core::SimpleString
|
112
|
+
# SimpleString instance
|
113
|
+
self.type = Java::org.hornetq.api.core.Message::TEXT_TYPE
|
114
|
+
body_buffer.writeNullableSimpleString(data)
|
115
|
+
elsif data.is_a? Java::org.hornetq.utils::TypedProperties
|
116
|
+
# TypedProperties
|
117
|
+
self.type = Java::org.hornetq.api.core.Message::MAP_TYPE
|
118
|
+
data.encode(body_buffer)
|
119
|
+
elsif data.responds_to? :each_pair
|
120
|
+
# Ruby Hash, or anything that responds to :each_pair
|
121
|
+
# TODO What about Hash inside of Hash?
|
122
|
+
self.type = Java::org.hornetq.api.core.Message::MAP_TYPE
|
123
|
+
properties = Java::org.hornetq.utils::TypedProperties.new
|
124
|
+
data.each_pair do |key, val|
|
125
|
+
properties[key.to_s] = val
|
126
|
+
end
|
127
|
+
properties.encode(body_buffer)
|
128
|
+
elsif data.responds_to? :to_s
|
129
|
+
# Can be converted to a Ruby String
|
130
|
+
self.type = Java::org.hornetq.api.core.Message::TEXT_TYPE
|
131
|
+
body_buffer.writeNullableSimpleString(Java::org.hornetq.api.core::SimpleString.new(data.to_s))
|
132
|
+
else
|
133
|
+
# Otherwise Serialize Ruby object
|
134
|
+
self.type = Java::org.hornetq.api.core.Message::BYTES_TYPE
|
135
|
+
self['encoding', 'jruby']
|
136
|
+
# If BYTES type is not working we could use Base64.encode64
|
137
|
+
self << Marshal.dump(data)
|
138
|
+
self.text = encoded
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
# Serialize JRuby object and base64 encode
|
143
|
+
def decode
|
144
|
+
if self.get_string_property( 'torquebox_encoding' ) == 'base64'
|
145
|
+
serialized = Base64.decode64( self.text )
|
146
|
+
Marshal.restore( serialized )
|
147
|
+
else
|
148
|
+
self.text
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
92
152
|
# Get a property
|
93
153
|
def [](key)
|
94
154
|
getObjectProperty(key.to_s)
|
File without changes
|
File without changes
|
@@ -1,8 +1,8 @@
|
|
1
|
-
module
|
1
|
+
module HornetQ::Client
|
2
2
|
# Create a Server for receiving requests and replying
|
3
3
|
# to arbitrary queues
|
4
4
|
# Create an instance of this class per thread
|
5
|
-
class
|
5
|
+
class Server
|
6
6
|
def initialize(session, request_queue, timeout)
|
7
7
|
@session = session
|
8
8
|
@consumer = session.create_consumer(request_queue)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'gene_pool'
|
2
2
|
|
3
|
-
module
|
3
|
+
module HornetQ::Client
|
4
4
|
# Since a Session can only be used by one thread at a time, we could create
|
5
5
|
# a Session for every thread. That could result in excessive unused Sessions.
|
6
6
|
# An alternative is to create a pool of sessions that can be shared by
|
@@ -15,11 +15,11 @@ module HornetQClient
|
|
15
15
|
# end
|
16
16
|
#
|
17
17
|
# Parameters:
|
18
|
-
# see regular session parameters from:
|
18
|
+
# see regular session parameters from: HornetQ::Client::Factory::create_session
|
19
19
|
#
|
20
20
|
# Additional parameters for controlling the session pool itself
|
21
21
|
# :pool_name Name of the pool as it shows up in the logger.
|
22
|
-
# Default: '
|
22
|
+
# Default: 'HornetQ::Client::SessionPool'
|
23
23
|
# :pool_size Maximum Pool Size. Default: 10
|
24
24
|
# The pool only grows as needed and will never exceed
|
25
25
|
# :pool_size
|
@@ -35,18 +35,18 @@ module HornetQClient
|
|
35
35
|
# ....
|
36
36
|
# end
|
37
37
|
class SessionPool
|
38
|
-
def initialize(factory,
|
39
|
-
# Save Session
|
38
|
+
def initialize(factory, params={})
|
39
|
+
# Save Session params since it will be used every time a new session is
|
40
40
|
# created in the pool
|
41
|
-
|
41
|
+
session_params = params.nil? ? {} : params.dup
|
42
42
|
# TODO Use same logger as HornetQ?
|
43
43
|
# TODO How to shrink unused connections?
|
44
44
|
@pool = GenePool.new(
|
45
|
-
:name =>
|
46
|
-
:pool_size =>
|
47
|
-
:warn_timeout =>
|
48
|
-
:logger =>
|
49
|
-
s = factory.create_session(
|
45
|
+
:name => session_params[:pool_name] || self.class.name,
|
46
|
+
:pool_size => session_params[:pool_size] || 10,
|
47
|
+
:warn_timeout => session_params[:pool_warn_timeout] || 5,
|
48
|
+
:logger => session_params[:pool_logger]) do
|
49
|
+
s = factory.create_session(session_params)
|
50
50
|
# Start the session since it will be used immediately upon creation
|
51
51
|
s.start
|
52
52
|
puts "Creating Session"
|
@@ -56,7 +56,7 @@ module HornetQClient
|
|
56
56
|
# Obtain a session from the pool and pass it to the supplied block
|
57
57
|
# The session is automatically returned to the pool once the block completes
|
58
58
|
def session(&block)
|
59
|
-
@pool.with_connection
|
59
|
+
@pool.with_connection &block
|
60
60
|
end
|
61
61
|
|
62
62
|
# Obtain a session from the pool and create a ClientConsumer.
|
@@ -64,7 +64,7 @@ module HornetQClient
|
|
64
64
|
# Once the block is complete the consumer is closed and the session is
|
65
65
|
# returned to the pool.
|
66
66
|
#
|
67
|
-
# See
|
67
|
+
# See HornetQ::Client::ClientConsumer for more information on the consumer
|
68
68
|
# parameters
|
69
69
|
#
|
70
70
|
# Example
|
@@ -89,12 +89,12 @@ module HornetQClient
|
|
89
89
|
# Once the block is complete the consumer is closed and the session is
|
90
90
|
# returned to the pool.
|
91
91
|
#
|
92
|
-
# See
|
92
|
+
# See HornetQ::Client::ClientProducer for more information on the producer
|
93
93
|
# parameters
|
94
94
|
#
|
95
95
|
# Example
|
96
96
|
# session_pool.producer('MyAddress') do |session, producer|
|
97
|
-
# message = session.create_message(
|
97
|
+
# message = session.create_message(HornetQ::Client::Message::TEXT_TYPE,false)
|
98
98
|
# message << "#{Time.now}: ### Hello, World ###"
|
99
99
|
# producer.send(message)
|
100
100
|
# end
|
@@ -110,15 +110,15 @@ module HornetQClient
|
|
110
110
|
end
|
111
111
|
end
|
112
112
|
|
113
|
-
# Obtain a session from the pool and create a
|
113
|
+
# Obtain a session from the pool and create a Client::Requestor.
|
114
114
|
# Pass both into the supplied block.
|
115
115
|
# Once the block is complete the requestor is closed and the session is
|
116
116
|
# returned to the pool.
|
117
117
|
#
|
118
|
-
# See
|
118
|
+
# See HornetQ::Client::Requestor for more information on the requestor
|
119
119
|
#
|
120
120
|
# Example
|
121
|
-
# session_pool.requestor(
|
121
|
+
# session_pool.requestor(params) do |session, requestor|
|
122
122
|
# ....
|
123
123
|
# end
|
124
124
|
def requestor(address, &block)
|
@@ -133,12 +133,12 @@ module HornetQClient
|
|
133
133
|
end
|
134
134
|
end
|
135
135
|
|
136
|
-
# Obtain a session from the pool and create a
|
136
|
+
# Obtain a session from the pool and create a Client::Server.
|
137
137
|
# Pass both into the supplied block.
|
138
138
|
# Once the block is complete the requestor is closed and the session is
|
139
139
|
# returned to the pool.
|
140
140
|
#
|
141
|
-
# See
|
141
|
+
# See HornetQ::Client::Server for more information on the server
|
142
142
|
#
|
143
143
|
# Example
|
144
144
|
# session_pool.server(queue, timeout) do |session, server|
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# Add methods to Server Interface
|
2
|
+
module Java::org.hornetq.core.server::HornetQServer
|
3
|
+
|
4
|
+
# Shutdown the server when a typical interrupt signal (1,2,15) is caught
|
5
|
+
def enable_shutdown_on_signal
|
6
|
+
['HUP', 'INT', 'TERM'].each do |signal_name|
|
7
|
+
Signal.trap(signal_name) do
|
8
|
+
puts "caught #{signal_name}"
|
9
|
+
stop
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module HornetQ
|
2
|
+
module Server
|
3
|
+
# Only load as needed
|
4
|
+
def self.load_requirements
|
5
|
+
HornetQ.require_jar 'hornetq-core'
|
6
|
+
HornetQ.require_jar 'netty'
|
7
|
+
require 'hornetq/org_hornetq_core_server_hornet_q_server'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
require 'hornetq/server/factory'
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module HornetQ::Server
|
2
|
+
|
3
|
+
class Factory
|
4
|
+
def self.create_server(parms={})
|
5
|
+
HornetQ::Server.load_requirements
|
6
|
+
|
7
|
+
if parms.kind_of?(String)
|
8
|
+
uri = HornetQ::URI.new(parms)
|
9
|
+
parms = uri.params
|
10
|
+
else
|
11
|
+
raise "Missing :uri param in HornetQ::Server.create_server" unless parms[:uri]
|
12
|
+
uri = HornetQ::URI.new(parms.delete(:uri))
|
13
|
+
# parms override uri params
|
14
|
+
parms = uri.params.merge(parms)
|
15
|
+
end
|
16
|
+
config = Java::org.hornetq.core.config.impl.ConfigurationImpl.new
|
17
|
+
data_directory = parms.delete(:data_directory) || HornetQ::DEFAULT_DATA_DIRECTORY
|
18
|
+
config.paging_directory = "#{data_directory}/paging"
|
19
|
+
config.bindings_directory = "#{data_directory}/bindings"
|
20
|
+
config.journal_directory = "#{data_directory}/journal"
|
21
|
+
config.large_messages_directory = "#{data_directory}/large-messages"
|
22
|
+
|
23
|
+
parms.each_pair do |key, val|
|
24
|
+
method = key.to_s+'='
|
25
|
+
if config.respond_to? method
|
26
|
+
config.send method, val
|
27
|
+
#puts "Debug: #{key} = #{config.send key}" if config.respond_to? key.to_sym
|
28
|
+
else
|
29
|
+
puts "Warning: Option:#{key} class=#{key.class} with value:#{val} is invalid and being ignored"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
if Java::org.hornetq.core.journal.impl.AIOSequentialFileFactory.isSupported
|
34
|
+
config.journal_type = Java::org.hornetq.core.server.JournalType::ASYNCIO
|
35
|
+
else
|
36
|
+
puts("AIO wasn't located on this platform, it will fall back to using pure Java NIO. If your platform is Linux, install LibAIO to enable the AIO journal");
|
37
|
+
config.journal_type = Java::org.hornetq.core.server.JournalType::NIO
|
38
|
+
end
|
39
|
+
|
40
|
+
if uri.host == 'invm'
|
41
|
+
acceptor = Java::org.hornetq.api.core.TransportConfiguration.new(HornetQ::INVM_ACCEPTOR_CLASS_NAME)
|
42
|
+
else
|
43
|
+
acceptor = Java::org.hornetq.api.core.TransportConfiguration.new(HornetQ::NETTY_ACCEPTOR_CLASS_NAME, {'host' => uri.host, 'port' => uri.port })
|
44
|
+
connector = Java::org.hornetq.api.core.TransportConfiguration.new(HornetQ::NETTY_CONNECTOR_CLASS_NAME, {'host' => uri.host, 'port' => uri.port })
|
45
|
+
connector_conf_map = java.util.HashMap.new
|
46
|
+
connector_conf_map.put('netty-connector', connector)
|
47
|
+
config.connector_configurations = connector_conf_map
|
48
|
+
end
|
49
|
+
acceptor_conf_set = java.util.HashSet.new
|
50
|
+
acceptor_conf_set.add(acceptor)
|
51
|
+
config.acceptor_configurations = acceptor_conf_set
|
52
|
+
|
53
|
+
|
54
|
+
if parms[:backup]
|
55
|
+
puts "backup"
|
56
|
+
config.backup = true
|
57
|
+
config.shared_store = false
|
58
|
+
elsif uri.backup_host
|
59
|
+
puts "live"
|
60
|
+
#backup_params.put('reconnectAttempts', -1)
|
61
|
+
backup_connector = Java::org.hornetq.api.core.TransportConfiguration.new(HornetQ::NETTY_CONNECTOR_CLASS_NAME, {'host' => uri.backup_host, 'port' => uri.backup_port })
|
62
|
+
connector_conf_map.put('backup-connector', backup_connector)
|
63
|
+
config.backup_connector_name = 'backup-connector'
|
64
|
+
elsif uri.host == 'invm'
|
65
|
+
puts 'invm'
|
66
|
+
else
|
67
|
+
puts 'standalone'
|
68
|
+
end
|
69
|
+
|
70
|
+
return Java::org.hornetq.core.server.HornetQServers.newHornetQServer(config)
|
71
|
+
end
|
72
|
+
|
73
|
+
# Start a new server instance and stop it once the supplied block completes
|
74
|
+
def self.start(params={}, &block)
|
75
|
+
server = nil
|
76
|
+
begin
|
77
|
+
server = self.create_server(params)
|
78
|
+
server.start
|
79
|
+
block.call(server)
|
80
|
+
ensure
|
81
|
+
server.stop if server
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
data/lib/hornetq/uri.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
module HornetQ
|
2
|
+
class URI
|
3
|
+
attr_reader :scheme, :host, :port, :backup_host, :backup_port, :path, :params
|
4
|
+
|
5
|
+
# hornetq://localhost
|
6
|
+
# hornetq://localhost,192.168.0.22
|
7
|
+
# hornetq://localhost:5445,backupserver:5445/?protocol=netty
|
8
|
+
# hornetq://localhost/?protocol=invm
|
9
|
+
# hornetq://discoveryserver:5445/?protocol=discovery
|
10
|
+
|
11
|
+
def initialize(uri)
|
12
|
+
raise Exception,"Invalid protocol format: #{uri}" unless uri =~ /(.*):\/\/(.*)/
|
13
|
+
@scheme, @host = $1, $2
|
14
|
+
raise Exception,"Bad URI(only scheme hornetq:// is supported): #{uri}" unless @scheme == 'hornetq'
|
15
|
+
raise 'Mandatory hostname missing in uri' if @host.empty?
|
16
|
+
if @host =~ /(.*?)(\/.*)/
|
17
|
+
@host, @path = $1, $2
|
18
|
+
else
|
19
|
+
@path = '/'
|
20
|
+
end
|
21
|
+
if @host =~ /(.*),(.*)/
|
22
|
+
@host, @backup_host = $1, $2
|
23
|
+
end
|
24
|
+
if @host =~ /(.*):(.*)/
|
25
|
+
@host, @port = $1, HornetQ.netty_port($2)
|
26
|
+
else
|
27
|
+
@port = HornetQ::DEFAULT_NETTY_PORT
|
28
|
+
end
|
29
|
+
if @backup_host
|
30
|
+
if @backup_host =~ /(.*):(.*)/
|
31
|
+
@backup_host, @backup_port = $1, HornetQ.netty_port($2)
|
32
|
+
else
|
33
|
+
@backup_port = HornetQ::DEFAULT_NETTY_PORT
|
34
|
+
end
|
35
|
+
end
|
36
|
+
query = nil
|
37
|
+
if @path =~ /(.*)\?(.*)/
|
38
|
+
@path, query = $1, $2
|
39
|
+
end
|
40
|
+
|
41
|
+
# Extract settings passed in query
|
42
|
+
@params = {}
|
43
|
+
if query
|
44
|
+
query.split('&').each do |i|
|
45
|
+
key, value = i.split('=')
|
46
|
+
value = true if value == 'true'
|
47
|
+
value = false if value == 'false'
|
48
|
+
value = value.to_i if value =~ /^\d+$/
|
49
|
+
value = value.to_f if value =~ /^\d+\.\d*$/
|
50
|
+
@params[key.to_sym] = value
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def [](key)
|
56
|
+
@params[key]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,184 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'shoulda'
|
4
|
+
require 'hornetq'
|
5
|
+
require 'fileutils'
|
6
|
+
|
7
|
+
class MyThread < ::Thread
|
8
|
+
def initialize(name, &block)
|
9
|
+
super() do
|
10
|
+
begin
|
11
|
+
yield
|
12
|
+
rescue => e
|
13
|
+
puts("Thread #{name} died due to exception #{e.message}\n#{e.backtrace.join("\n")}")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class ServerFactoryTest < Test::Unit::TestCase
|
20
|
+
context 'standalone server' do
|
21
|
+
setup do
|
22
|
+
@server = nil
|
23
|
+
@tmp_data_dir = "/tmp/data_dir/#{$$}"
|
24
|
+
@uri = "hornetq://localhost:15445"
|
25
|
+
@server_thread = MyThread.new('standalone server') do
|
26
|
+
@server = HornetQ::Server::Factory.create_server(:uri => @uri, :data_directory => @tmp_data_dir)
|
27
|
+
@server.start
|
28
|
+
end
|
29
|
+
# Give the server time to startup
|
30
|
+
sleep 5
|
31
|
+
end
|
32
|
+
|
33
|
+
teardown do
|
34
|
+
@server.stop
|
35
|
+
@server_thread.join
|
36
|
+
FileUtils.rm_rf(@tmp_data_dir)
|
37
|
+
end
|
38
|
+
|
39
|
+
should 'pass simple messages' do
|
40
|
+
count = 10
|
41
|
+
queue_name = 'test_queue'
|
42
|
+
config = {
|
43
|
+
:connector => { :uri => @uri },
|
44
|
+
:session => { :username =>'guest', :password => 'guest'}
|
45
|
+
}
|
46
|
+
|
47
|
+
# Create a HornetQ session
|
48
|
+
HornetQ::Client::Factory.create_session(config) do |session|
|
49
|
+
session.create_queue(queue_name, queue_name, true)
|
50
|
+
producer = session.create_producer(queue_name)
|
51
|
+
(1..count).each do |i|
|
52
|
+
message = session.create_message(HornetQ::Client::Message::TEXT_TYPE,false)
|
53
|
+
message.durable = true
|
54
|
+
# Set the message body text
|
55
|
+
message << "Message ##{i}"
|
56
|
+
# Send message to the queue
|
57
|
+
producer.send(message)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
HornetQ::Client::Factory.create_session(config) do |session|
|
62
|
+
consumer = session.create_consumer(queue_name)
|
63
|
+
session.start
|
64
|
+
|
65
|
+
i = 0
|
66
|
+
while message = consumer.receive(1000)
|
67
|
+
i += 1
|
68
|
+
message.acknowledge
|
69
|
+
assert_equal "Message ##{i}", message.body
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context 'live and backup server' do
|
76
|
+
setup do
|
77
|
+
@count = 20
|
78
|
+
|
79
|
+
@server = nil
|
80
|
+
@tmp_data_dir = "/tmp/data_dir/#{$$}"
|
81
|
+
@uri = "hornetq://localhost:15445,localhost:15446"
|
82
|
+
|
83
|
+
@backup_server = nil
|
84
|
+
@backup_tmp_data_dir = "/tmp/backup_data_dir/#{$$}"
|
85
|
+
@backup_uri = "hornetq://localhost:15446"
|
86
|
+
|
87
|
+
@backup_server_thread = MyThread.new('backup server') do
|
88
|
+
begin
|
89
|
+
@backup_server = HornetQ::Server::Factory.create_server(:uri => @backup_uri, :data_directory => @backup_tmp_data_dir, :backup => true)
|
90
|
+
@backup_server.start
|
91
|
+
rescue Exception => e
|
92
|
+
puts "Error in backup server thread: #{e.message}\n#{e.backtrace.join("\n")}"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
# Give the backup server time to startup
|
96
|
+
sleep 10
|
97
|
+
|
98
|
+
@server_thread = MyThread.new('live server') do
|
99
|
+
begin
|
100
|
+
@server = HornetQ::Server::Factory.create_server(:uri => @uri, :data_directory => @tmp_data_dir)
|
101
|
+
@server.start
|
102
|
+
rescue Exception => e
|
103
|
+
puts "Error in live server thread: #{e.message}\n#{e.backtrace.join("\n")}"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# Give the live server time to startup
|
108
|
+
sleep 10
|
109
|
+
|
110
|
+
@queue_name = 'test_queue'
|
111
|
+
@config = {
|
112
|
+
:connector => {
|
113
|
+
:uri => @uri,
|
114
|
+
:failover_on_initial_connection => true,
|
115
|
+
:failover_on_server_shutdown => true,
|
116
|
+
},
|
117
|
+
:session => { :username =>'guest', :password => 'guest'}
|
118
|
+
}
|
119
|
+
|
120
|
+
@killer_thread = MyThread.new('killer') do
|
121
|
+
sleep 5
|
122
|
+
@server.stop
|
123
|
+
end
|
124
|
+
|
125
|
+
@producer_thread = MyThread.new('producer') do
|
126
|
+
# Create a HornetQ session
|
127
|
+
HornetQ::Client::Factory.create_session(@config) do |session|
|
128
|
+
session.create_queue(@queue_name, @queue_name, true)
|
129
|
+
producer = session.create_producer(@queue_name)
|
130
|
+
(1..@count).each do |i|
|
131
|
+
message = session.create_message(HornetQ::Client::Message::TEXT_TYPE,false)
|
132
|
+
message.durable = true
|
133
|
+
# Set the message body text
|
134
|
+
message << "Message ##{i}"
|
135
|
+
# Send message to the queue
|
136
|
+
begin
|
137
|
+
puts "Producing message: #{message.body}"
|
138
|
+
producer.send(message)
|
139
|
+
sleep 1
|
140
|
+
rescue Java::org.hornetq.api.core.HornetQException => e
|
141
|
+
puts "Received producer exception: #{e.message} with code=#{e.cause.code}"
|
142
|
+
if e.cause.getCode == Java::org.hornetq.api.core.HornetQException::UNBLOCKED
|
143
|
+
puts "Retrying the send"
|
144
|
+
retry
|
145
|
+
end
|
146
|
+
rescue Exception => e
|
147
|
+
puts "Received producer exception: #{e.message}"
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
teardown do
|
155
|
+
@server.stop
|
156
|
+
@backup_server.stop
|
157
|
+
[ @server_thread, @backup_server_thread, @killer_thread, @producer_thread ].each do |thread|
|
158
|
+
thread.join
|
159
|
+
end
|
160
|
+
FileUtils.rm_rf([@tmp_data_dir, @backup_tmp_data_dir])
|
161
|
+
end
|
162
|
+
|
163
|
+
should 'failover to backup server w/o message loss' do
|
164
|
+
# Let the producer create the queue
|
165
|
+
sleep 2
|
166
|
+
HornetQ::Client::Factory.create_session(@config) do |session|
|
167
|
+
consumer = session.create_consumer(@queue_name)
|
168
|
+
session.start
|
169
|
+
|
170
|
+
i = 0
|
171
|
+
while message = consumer.receive(1000)
|
172
|
+
i += 1
|
173
|
+
message.acknowledge
|
174
|
+
assert_equal "Message ##{i}", message.body
|
175
|
+
puts "Consuming message #{message.body}"
|
176
|
+
end
|
177
|
+
assert_equal @count, i
|
178
|
+
end
|
179
|
+
|
180
|
+
killer_thread.join
|
181
|
+
producer_thread.join
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|