jruby-jms 1.1.0-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.
- checksums.yaml +7 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +36 -0
- data/HISTORY.md +52 -0
- data/LICENSE.txt +201 -0
- data/README.md +205 -0
- data/Rakefile +30 -0
- data/examples/advanced/session_pool.rb +37 -0
- data/examples/client-server/replier.rb +29 -0
- data/examples/client-server/requestor.rb +40 -0
- data/examples/file-to-q/files_to_q.rb +51 -0
- data/examples/file-to-q/q_to_files.rb +44 -0
- data/examples/invm/invm.rb +44 -0
- data/examples/invm/log4j.properties +58 -0
- data/examples/jms.yml +149 -0
- data/examples/performance/consumer.rb +25 -0
- data/examples/performance/producer.rb +31 -0
- data/examples/producer-consumer/browser.rb +24 -0
- data/examples/producer-consumer/consumer.rb +24 -0
- data/examples/producer-consumer/consumer_async.rb +41 -0
- data/examples/producer-consumer/producer.rb +25 -0
- data/examples/publish-subscribe/publish.rb +24 -0
- data/examples/publish-subscribe/subscribe.rb +31 -0
- data/lib/jms.rb +20 -0
- data/lib/jms/bytes_message.rb +52 -0
- data/lib/jms/connection.rb +529 -0
- data/lib/jms/imports.rb +21 -0
- data/lib/jms/logging.rb +50 -0
- data/lib/jms/map_message.rb +91 -0
- data/lib/jms/message.rb +285 -0
- data/lib/jms/message_consumer.rb +117 -0
- data/lib/jms/message_listener_impl.rb +79 -0
- data/lib/jms/message_producer.rb +59 -0
- data/lib/jms/mq_workaround.rb +70 -0
- data/lib/jms/object_message.rb +26 -0
- data/lib/jms/oracle_a_q_connection_factory.rb +48 -0
- data/lib/jms/queue_browser.rb +28 -0
- data/lib/jms/session.rb +473 -0
- data/lib/jms/session_pool.rb +168 -0
- data/lib/jms/text_message.rb +31 -0
- data/lib/jms/version.rb +3 -0
- data/nbproject/private/private.properties +3 -0
- data/nbproject/private/rake-d.txt +5 -0
- data/parallel_minion.gemspec +21 -0
- data/test/connection_test.rb +160 -0
- data/test/jms.yml +111 -0
- data/test/log4j.properties +32 -0
- data/test/message_test.rb +130 -0
- data/test/session_pool_test.rb +86 -0
- data/test/session_test.rb +140 -0
- metadata +113 -0
@@ -0,0 +1,117 @@
|
|
1
|
+
################################################################################
|
2
|
+
# Copyright 2008, 2009, 2010, 2011 J. Reid Morrison
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
################################################################################
|
16
|
+
|
17
|
+
# Interface javax.jms.MessageConsumer
|
18
|
+
module JMS::MessageConsumer
|
19
|
+
# Obtain a message from the Destination or Topic
|
20
|
+
# In JMS terms, the message is received from the Destination
|
21
|
+
# :timeout follows the rules for MQSeries:
|
22
|
+
# -1 : Wait forever
|
23
|
+
# 0 : Return immediately if no message is available
|
24
|
+
# x : Wait for x milli-seconds for a message to be received from the broker
|
25
|
+
# Note: Messages may still be on the queue, but the broker has not supplied any messages
|
26
|
+
# in the time interval specified
|
27
|
+
# Default: 0
|
28
|
+
def get(params={})
|
29
|
+
timeout = params[:timeout] || 0
|
30
|
+
if timeout == -1
|
31
|
+
self.receive
|
32
|
+
elsif timeout == 0
|
33
|
+
self.receiveNoWait
|
34
|
+
else
|
35
|
+
self.receive(timeout)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# For each message available to be consumed call the Proc supplied
|
40
|
+
# Returns the statistics gathered when :statistics => true, otherwise nil
|
41
|
+
#
|
42
|
+
# Parameters:
|
43
|
+
# :timeout How to timeout waiting for messages on the Queue or Topic
|
44
|
+
# -1 : Wait forever
|
45
|
+
# 0 : Return immediately if no message is available
|
46
|
+
# x : Wait for x milli-seconds for a message to be received from the broker
|
47
|
+
# Note: Messages may still be on the queue, but the broker has not supplied any messages
|
48
|
+
# in the time interval specified
|
49
|
+
# Default: 0
|
50
|
+
#
|
51
|
+
# :statistics Capture statistics on how many messages have been read
|
52
|
+
# true : This method will capture statistics on the number of messages received
|
53
|
+
# and the time it took to process them.
|
54
|
+
# The statistics can be reset by calling MessageConsumer::each again
|
55
|
+
# with :statistics => true
|
56
|
+
#
|
57
|
+
# The statistics gathered are returned when :statistics => true and :async => false
|
58
|
+
def each(params={}, &proc)
|
59
|
+
raise "Destination::each requires a code block to be executed for each message received" unless proc
|
60
|
+
|
61
|
+
message_count = nil
|
62
|
+
start_time = nil
|
63
|
+
|
64
|
+
if params[:statistics]
|
65
|
+
message_count = 0
|
66
|
+
start_time = Time.now
|
67
|
+
end
|
68
|
+
|
69
|
+
# Receive messages according to timeout
|
70
|
+
while message = self.get(params) do
|
71
|
+
proc.call(message)
|
72
|
+
message_count += 1 if message_count
|
73
|
+
end
|
74
|
+
|
75
|
+
unless message_count.nil?
|
76
|
+
duration = Time.now - start_time
|
77
|
+
{:messages => message_count,
|
78
|
+
:duration => duration,
|
79
|
+
:messages_per_second => duration > 0 ? (message_count/duration).to_i : 0,
|
80
|
+
:ms_per_msg => message_count > 0 ? (duration*1000.0)/message_count : 0
|
81
|
+
}
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Receive messages in a separate thread when they arrive
|
86
|
+
# Allows messages to be recieved in a separate thread. I.e. Asynchronously
|
87
|
+
# This method will return to the caller before messages are processed.
|
88
|
+
# It is then the callers responsibility to keep the program active so that messages
|
89
|
+
# can then be processed.
|
90
|
+
#
|
91
|
+
# Parameters:
|
92
|
+
# :statistics Capture statistics on how many messages have been read
|
93
|
+
# true : This method will capture statistics on the number of messages received
|
94
|
+
# and the time it took to process them.
|
95
|
+
# The timer starts when each() is called and finishes when either the last message was received,
|
96
|
+
# or when Destination::statistics is called. In this case MessageConsumer::statistics
|
97
|
+
# can be called several times during processing without affecting the end time.
|
98
|
+
# Also, the start time and message count is not reset until MessageConsumer::each
|
99
|
+
# is called again with :statistics => true
|
100
|
+
#
|
101
|
+
# The statistics gathered are returned when :statistics => true and :async => false
|
102
|
+
#
|
103
|
+
def on_message(params={}, &proc)
|
104
|
+
raise "MessageConsumer::on_message requires a code block to be executed for each message received" unless proc
|
105
|
+
|
106
|
+
@listener = JMS::MessageListenerImpl.new(params,&proc)
|
107
|
+
self.setMessageListener @listener
|
108
|
+
end
|
109
|
+
|
110
|
+
# Return the current statistics for a running MessageConsumer::on_message
|
111
|
+
def on_message_statistics
|
112
|
+
stats = @listener.statistics if @listener
|
113
|
+
raise "First call MessageConsumer::on_message with :statistics=>true before calling MessageConsumer::statistics()" unless stats
|
114
|
+
stats
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
################################################################################
|
2
|
+
# Copyright 2008, 2009, 2010, 2011 J. Reid Morrison
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
################################################################################
|
16
|
+
|
17
|
+
module JMS
|
18
|
+
|
19
|
+
private
|
20
|
+
# For internal use only by JMS::Connection
|
21
|
+
class MessageListenerImpl
|
22
|
+
include JMS::MessageListener
|
23
|
+
|
24
|
+
# Parameters:
|
25
|
+
# :statistics Capture statistics on how many messages have been read
|
26
|
+
# true : This method will capture statistics on the number of messages received
|
27
|
+
# and the time it took to process them.
|
28
|
+
# The timer starts when the listener instance is created and finishes when either the last message was received,
|
29
|
+
# or when Destination::statistics is called. In this case MessageConsumer::statistics
|
30
|
+
# can be called several times during processing without affecting the end time.
|
31
|
+
# Also, the start time and message count is not reset until MessageConsumer::each
|
32
|
+
# is called again with :statistics => true
|
33
|
+
#
|
34
|
+
# The statistics gathered are returned when :statistics => true and :async => false
|
35
|
+
def initialize(params={}, &proc)
|
36
|
+
@proc = proc
|
37
|
+
|
38
|
+
if params[:statistics]
|
39
|
+
@message_count = 0
|
40
|
+
@start_time = Time.now
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Method called for every message received on the queue
|
45
|
+
# Per the JMS specification, this method will be called sequentially for each message on the queue.
|
46
|
+
# This method will not be called again until its prior invocation has completed.
|
47
|
+
# Must be onMessage() since on_message() does not work for interface methods that must be implemented
|
48
|
+
def onMessage(message)
|
49
|
+
begin
|
50
|
+
if @message_count
|
51
|
+
@message_count += 1
|
52
|
+
@last_time = Time.now
|
53
|
+
end
|
54
|
+
@proc.call message
|
55
|
+
rescue SyntaxError, NameError => boom
|
56
|
+
JMS::logger.error "Unhandled Exception processing JMS Message. Doesn't compile: " + boom
|
57
|
+
JMS::logger.error "Ignoring poison message:\n#{message.inspect}"
|
58
|
+
JMS::logger.error boom.backtrace.join("\n")
|
59
|
+
rescue StandardError => bang
|
60
|
+
JMS::logger.error "Unhandled Exception processing JMS Message. Doesn't compile: " + bang
|
61
|
+
JMS::logger.error "Ignoring poison message:\n#{message.inspect}"
|
62
|
+
JMS::logger.error bang.backtrace.join("\n")
|
63
|
+
rescue => exc
|
64
|
+
JMS::logger.error "Unhandled Exception processing JMS Message. Exception occurred:\n#{exc}"
|
65
|
+
JMS::logger.error "Ignoring poison message:\n#{message.inspect}"
|
66
|
+
JMS::logger.error exc.backtrace.join("\n")
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Return Statistics gathered for this listener
|
71
|
+
def statistics
|
72
|
+
raise "First call MessageConsumer::on_message with :statistics=>true before calling MessageConsumer::statistics()" unless @message_count
|
73
|
+
duration =(@last_time || Time.now) - @start_time
|
74
|
+
{:messages => @message_count,
|
75
|
+
:duration => duration,
|
76
|
+
:messages_per_second => (@message_count/duration).to_i}
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
################################################################################
|
2
|
+
# Copyright 2008, 2009, 2010, 2011 J. Reid Morrison
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
################################################################################
|
16
|
+
|
17
|
+
# Extend JMS Message Producer Interface with Ruby methods
|
18
|
+
#
|
19
|
+
# For further help on javax.jms.MessageProducer
|
20
|
+
# http://download.oracle.com/javaee/6/api/javax/jms/MessageProducer.html
|
21
|
+
#
|
22
|
+
# Interface javax.jms.Producer
|
23
|
+
module JMS::MessageProducer
|
24
|
+
|
25
|
+
# Return the Delivery Mode as a Ruby symbol
|
26
|
+
# :persistent
|
27
|
+
# :non_persistent
|
28
|
+
# nil if unknown
|
29
|
+
def delivery_mode_sym
|
30
|
+
case delivery_mode
|
31
|
+
when JMS::DeliveryMode::PERSISTENT
|
32
|
+
:persistent
|
33
|
+
when JMS::DeliveryMode::NON_PERSISTENT
|
34
|
+
:non_persistent
|
35
|
+
else
|
36
|
+
nil
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Set the JMS Delivery Mode from a Ruby Symbol
|
41
|
+
# Valid values for mode
|
42
|
+
# :persistent
|
43
|
+
# :non_persistent
|
44
|
+
#
|
45
|
+
# Example:
|
46
|
+
# producer.delivery_mode_sym = :persistent
|
47
|
+
def delivery_mode_sym=(mode)
|
48
|
+
val = case mode
|
49
|
+
when :persistent
|
50
|
+
JMS::DeliveryMode::PERSISTENT
|
51
|
+
when :non_persistent
|
52
|
+
JMS::DeliveryMode::NON_PERSISTENT
|
53
|
+
else
|
54
|
+
raise "Unknown delivery mode symbol: #{mode}"
|
55
|
+
end
|
56
|
+
self.delivery_mode = val
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# Workaround for IBM MQ JMS implementation that implements some undocumented methods
|
2
|
+
|
3
|
+
begin
|
4
|
+
|
5
|
+
class com.ibm.mq.jms::MQQueueSession
|
6
|
+
|
7
|
+
if self.instance_methods.include? "consume"
|
8
|
+
def consume(params, &proc)
|
9
|
+
Java::JavaxJms::Session.instance_method(:consume).bind(self).call(params, &proc)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
class com.ibm.mq.jms::MQSession
|
17
|
+
|
18
|
+
if self.instance_methods.include? "consume"
|
19
|
+
def consume(params, &proc)
|
20
|
+
Java::JavaxJms::Session.instance_method(:consume).bind(self).call(params, &proc)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
if self.instance_methods.include? "create_destination"
|
25
|
+
def create_destination(params)
|
26
|
+
Java::JavaxJms::Session.instance_method(:create_destination).bind(self).call(params)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
class com.ibm.mq.jms::MQQueueBrowser
|
34
|
+
|
35
|
+
if self.instance_methods.include? "each"
|
36
|
+
def each(params, &proc)
|
37
|
+
Java::ComIbmMsgClientJms::JmsQueueBrowser.instance_method(:each).bind(self).call(params, &proc)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
class com.ibm.mq.jms::MQQueueReceiver
|
44
|
+
|
45
|
+
if self.instance_methods.include? "each"
|
46
|
+
def each(params, &proc)
|
47
|
+
Java::JavaxJms::MessageConsumer.instance_method(:each).bind(self).call(params, &proc)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
if self.instance_methods.include? "get"
|
52
|
+
def get(params={})
|
53
|
+
Java::JavaxJms::MessageConsumer.instance_method(:get).bind(self).call(params)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
class com.ibm.mq.jms::MQQueue
|
61
|
+
|
62
|
+
if self.instance_methods.include? "delete"
|
63
|
+
undef_method :delete
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
rescue NameError
|
69
|
+
# Ignore errors (when we aren't using MQ)
|
70
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
################################################################################
|
2
|
+
# Copyright 2008, 2009, 2010, 2011 J. Reid Morrison
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
################################################################################
|
16
|
+
|
17
|
+
#Interface javax.jms.ObjectMessage
|
18
|
+
module JMS::ObjectMessage
|
19
|
+
def data
|
20
|
+
getObject
|
21
|
+
end
|
22
|
+
|
23
|
+
def data(val)
|
24
|
+
setObject(val)
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
################################################################################
|
2
|
+
# Copyright 2008, 2009, 2010, 2011 J. Reid Morrison
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
################################################################################
|
16
|
+
|
17
|
+
module JMS
|
18
|
+
# Full Qualified name causes a Java exception
|
19
|
+
java_import 'oracle.jms.AQjmsFactory'
|
20
|
+
|
21
|
+
# Connection Factory to support Oracle AQ
|
22
|
+
class OracleAQConnectionFactory
|
23
|
+
attr_accessor :username, :url
|
24
|
+
#attr_writer :password
|
25
|
+
attr_accessor :password
|
26
|
+
|
27
|
+
# Creates a connection per standard JMS 1.1 techniques from the Oracle AQ JMS Interface
|
28
|
+
def create_connection(*args)
|
29
|
+
# Since username and password are not assigned (see lib/jms/connection.rb:200)
|
30
|
+
# and connection_factory.create_connection expects 2 arguments when username is not null ...
|
31
|
+
if args.length == 2
|
32
|
+
@username = args[0]
|
33
|
+
@password = args[1]
|
34
|
+
end
|
35
|
+
|
36
|
+
# Full Qualified name causes a Java exception
|
37
|
+
#cf = oracle.jms.AQjmsFactory.getConnectionFactory(@url, java.util.Properties.new)
|
38
|
+
cf = AQjmsFactory.getConnectionFactory(@url, java.util.Properties.new)
|
39
|
+
|
40
|
+
if username
|
41
|
+
cf.createConnection(@username, @password)
|
42
|
+
else
|
43
|
+
cf.createConnection()
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
################################################################################
|
2
|
+
# Copyright 2008, 2009, 2010, 2011 J. Reid Morrison
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
################################################################################
|
16
|
+
|
17
|
+
#Interface javax.jms.QueueBrowser
|
18
|
+
module JMS::QueueBrowser
|
19
|
+
# For each message on the queue call the supplied Proc
|
20
|
+
def each(params={}, &block)
|
21
|
+
raise "JMS::QueueBrowser::each requires a code block to be executed for each message received" unless block
|
22
|
+
|
23
|
+
e = self.getEnumeration
|
24
|
+
while e.hasMoreElements
|
25
|
+
block.call(e.nextElement)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/jms/session.rb
ADDED
@@ -0,0 +1,473 @@
|
|
1
|
+
################################################################################
|
2
|
+
# Copyright 2008, 2009, 2010, 2011 J. Reid Morrison
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
################################################################################
|
16
|
+
|
17
|
+
# For each thread that will be processing messages concurrently a separate
|
18
|
+
# session is required. All sessions can share a single connection to the same
|
19
|
+
# JMS Provider.
|
20
|
+
#
|
21
|
+
# Interface javax.jms.Session
|
22
|
+
#
|
23
|
+
# See: http://download.oracle.com/javaee/6/api/javax/jms/Session.html
|
24
|
+
#
|
25
|
+
# Other methods still directly accessible through this class:
|
26
|
+
#
|
27
|
+
# create_browser(queue, message_selector)
|
28
|
+
# Creates a QueueBrowser object to peek at the messages on the specified queue using a message selector.
|
29
|
+
#
|
30
|
+
# create_bytes_message()
|
31
|
+
# Creates a BytesMessage object
|
32
|
+
#
|
33
|
+
# create_consumer(destination)
|
34
|
+
# Creates a MessageConsumer for the specified destination
|
35
|
+
# See: Connection::consumer
|
36
|
+
#
|
37
|
+
# Example:
|
38
|
+
# destination = session.create_destination(:queue_name => "MyQueue")
|
39
|
+
# session.create_consumer(destination)
|
40
|
+
#
|
41
|
+
# create_consumer(destination, message_selector)
|
42
|
+
# Creates a MessageConsumer for the specified destination, using a message selector
|
43
|
+
#
|
44
|
+
# create_consumer(destination, message_selector, boolean NoLocal)
|
45
|
+
# Creates MessageConsumer for the specified destination, using a message selector
|
46
|
+
#
|
47
|
+
# create_durable_subscriber(Topic topic, java.lang.String name)
|
48
|
+
# Creates a durable subscriber to the specified topic
|
49
|
+
#
|
50
|
+
# create_durable_subscriber(Topic topic, java.lang.String name, java.lang.String messageSelector, boolean noLocal)
|
51
|
+
# Creates a durable subscriber to the specified topic, using a message selector and specifying whether messages published by its own connection should be delivered to it.
|
52
|
+
#
|
53
|
+
# create_map_Message()
|
54
|
+
# Creates a MapMessage object
|
55
|
+
#
|
56
|
+
# create_message()
|
57
|
+
# Creates a Message object
|
58
|
+
#
|
59
|
+
# create_object_message()
|
60
|
+
# Creates an ObjectMessage object
|
61
|
+
#
|
62
|
+
# create_object_message(java.io.Serializable object)
|
63
|
+
# Creates an initialized ObjectMessage object
|
64
|
+
#
|
65
|
+
# create_producer(destination)
|
66
|
+
# Creates a MessageProducer to send messages to the specified destination
|
67
|
+
#
|
68
|
+
# create_queue(queue_name)
|
69
|
+
# Creates a queue identity given a Queue name
|
70
|
+
#
|
71
|
+
# create_stream_message()
|
72
|
+
# Creates a StreamMessage object
|
73
|
+
#
|
74
|
+
# create_temporary_queue()
|
75
|
+
# Creates a TemporaryQueue object
|
76
|
+
#
|
77
|
+
# create_temporary_topic()
|
78
|
+
# Creates a TemporaryTopic object
|
79
|
+
#
|
80
|
+
# create_text_message()
|
81
|
+
# Creates a TextMessage object
|
82
|
+
#
|
83
|
+
# create_text_message(text)
|
84
|
+
# Creates an initialized TextMessage object
|
85
|
+
#
|
86
|
+
# create_topic(topic_name)
|
87
|
+
# Creates a topic identity given a Topic name
|
88
|
+
#
|
89
|
+
# acknowledge_mode()
|
90
|
+
# Returns the acknowledgement mode of the session
|
91
|
+
#
|
92
|
+
# message_listener()
|
93
|
+
# Returns the session's distinguished message listener (optional).
|
94
|
+
#
|
95
|
+
# transacted?
|
96
|
+
# Indicates whether the session is in transacted mode
|
97
|
+
#
|
98
|
+
# recover()
|
99
|
+
# Stops message delivery in this session, and restarts message delivery with the oldest unacknowledged message
|
100
|
+
#
|
101
|
+
# rollback()
|
102
|
+
# Rolls back any messages done in this transaction and releases any locks currently held
|
103
|
+
#
|
104
|
+
# message_listener=(MessageListener listener)
|
105
|
+
# Sets the session's distinguished message listener (optional)
|
106
|
+
#
|
107
|
+
# unsubscribe(name)
|
108
|
+
# Unsubscribes a durable subscription that has been created by a client
|
109
|
+
#
|
110
|
+
# Interface javax.jms.Session
|
111
|
+
module JMS::Session
|
112
|
+
# Create a new message instance based on the type of the data being supplied
|
113
|
+
# String (:to_str) => TextMessage
|
114
|
+
# Hash (:each_pair) => MapMessage
|
115
|
+
# Duck typing is used to determine the type. If the class responds
|
116
|
+
# to :to_str then it is considered a String. Similarly if it responds to
|
117
|
+
# :each_pair it is considered to be a Hash
|
118
|
+
#
|
119
|
+
# If automated duck typing is not desired, the type of the message can be specified
|
120
|
+
# by setting the parameter 'type' to any one of:
|
121
|
+
# :text => Creates a Text Message
|
122
|
+
# :map => Creates a Map Message
|
123
|
+
# :bytes => Creates a Bytes Message
|
124
|
+
def message(data, type=nil)
|
125
|
+
jms_message = nil
|
126
|
+
type ||= if data.respond_to?(:to_str, false)
|
127
|
+
:text
|
128
|
+
elsif data.respond_to?(:each_pair, false)
|
129
|
+
:map
|
130
|
+
else
|
131
|
+
raise "Unknown data type #{data.class.to_s} in Message"
|
132
|
+
end
|
133
|
+
|
134
|
+
case type
|
135
|
+
when :text
|
136
|
+
jms_message = self.createTextMessage
|
137
|
+
jms_message.text = data.to_str
|
138
|
+
when :map
|
139
|
+
jms_message = self.createMapMessage
|
140
|
+
jms_message.data = data
|
141
|
+
when :bytes
|
142
|
+
jms_message = self.createBytesMessage
|
143
|
+
jms_message.write_bytes(data.to_java_bytes)
|
144
|
+
else
|
145
|
+
raise "Invalid type #{type} requested"
|
146
|
+
end
|
147
|
+
jms_message
|
148
|
+
end
|
149
|
+
|
150
|
+
# Create the destination based on the parameter supplied
|
151
|
+
#
|
152
|
+
# The idea behind this method is to allow the decision as to whether
|
153
|
+
# one is sending to a topic or destination to be transparent to the code.
|
154
|
+
# The supplied parameters can be externalized into say a YAML file
|
155
|
+
# so that today it writes to a queue, later it can be changed to write
|
156
|
+
# to a topic so that multiple parties can receive the same messages.
|
157
|
+
#
|
158
|
+
# Note: For Temporary Queues and Topics, remember to delete them when done
|
159
|
+
# or just use ::destination instead with a block and it will take care
|
160
|
+
# of deleting them for you
|
161
|
+
#
|
162
|
+
# To create a queue:
|
163
|
+
# session.create_destination(:queue_name => 'name of queue')
|
164
|
+
#
|
165
|
+
# To create a temporary queue:
|
166
|
+
# session.create_destination(:queue_name => :temporary)
|
167
|
+
#
|
168
|
+
# To create a queue:
|
169
|
+
# session.create_destination('queue://queue_name')
|
170
|
+
#
|
171
|
+
# To create a topic:
|
172
|
+
# session.create_destination(:topic_name => 'name of queue')
|
173
|
+
#
|
174
|
+
# To create a temporary topic:
|
175
|
+
# session.create_destination(:topic_name => :temporary)
|
176
|
+
#
|
177
|
+
# To create a topic:
|
178
|
+
# session.create_destination('topic://topic_name')
|
179
|
+
#
|
180
|
+
# Create the destination based on the parameter supplied
|
181
|
+
#
|
182
|
+
# Parameters:
|
183
|
+
# :queue_name => String: Name of the Queue to return
|
184
|
+
# Symbol: :temporary => Create temporary queue
|
185
|
+
# Mandatory unless :topic_name is supplied
|
186
|
+
# Or,
|
187
|
+
# :topic_name => String: Name of the Topic to write to or subscribe to
|
188
|
+
# Symbol: :temporary => Create temporary topic
|
189
|
+
# Mandatory unless :queue_name is supplied
|
190
|
+
# Or,
|
191
|
+
# :destination=> Explicit javaxJms::Destination to use
|
192
|
+
#
|
193
|
+
# Returns the result of the supplied block
|
194
|
+
def create_destination(params)
|
195
|
+
# Allow a Java JMS destination object to be passed in
|
196
|
+
return params[:destination] if params[:destination] && params[:destination].java_kind_of?(JMS::Destination)
|
197
|
+
|
198
|
+
queue_name = nil
|
199
|
+
topic_name = nil
|
200
|
+
|
201
|
+
if params.is_a? String
|
202
|
+
queue_name = params['queue://'.length..-1] if params.start_with?('queue://')
|
203
|
+
topic_name = params['topic://'.length..-1] if params.start_with?('topic://')
|
204
|
+
else
|
205
|
+
# :q_name is deprecated
|
206
|
+
queue_name = params[:queue_name] || params[:q_name]
|
207
|
+
topic_name = params[:topic_name]
|
208
|
+
end
|
209
|
+
|
210
|
+
raise "Missing mandatory parameter :queue_name or :topic_name to Session::producer, Session::consumer, or Session::browser" unless queue_name || topic_name
|
211
|
+
|
212
|
+
if queue_name
|
213
|
+
queue_name == :temporary ? create_temporary_queue : create_queue(queue_name)
|
214
|
+
else
|
215
|
+
topic_name == :temporary ? create_temporary_topic : create_topic(topic_name)
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
# Create a queue or topic to send or receive messages from
|
220
|
+
#
|
221
|
+
# A block must be supplied so that if it is a temporary topic or queue
|
222
|
+
# it will be deleted after the proc is complete
|
223
|
+
#
|
224
|
+
# To create a queue:
|
225
|
+
# session.destination(:queue_name => 'name of queue')
|
226
|
+
#
|
227
|
+
# To create a temporary queue:
|
228
|
+
# session.destination(:queue_name => :temporary)
|
229
|
+
#
|
230
|
+
# To create a topic:
|
231
|
+
# session.destination(:topic_name => 'name of queue')
|
232
|
+
#
|
233
|
+
# To create a temporary topic:
|
234
|
+
# session.destination(:topic_name => :temporary)
|
235
|
+
#
|
236
|
+
# Create the destination based on the parameter supplied
|
237
|
+
#
|
238
|
+
# Parameters:
|
239
|
+
# :queue_name => String: Name of the Queue to return
|
240
|
+
# Symbol: :temporary => Create temporary queue
|
241
|
+
# Mandatory unless :topic_name is supplied
|
242
|
+
# Or,
|
243
|
+
# :topic_name => String: Name of the Topic to write to or subscribe to
|
244
|
+
# Symbol: :temporary => Create temporary topic
|
245
|
+
# Mandatory unless :queue_name is supplied
|
246
|
+
# Or,
|
247
|
+
# :destination=> Explicit javaxJms::Destination to use
|
248
|
+
#
|
249
|
+
# Returns the result of the supplied block
|
250
|
+
def destination(params={}, &block)
|
251
|
+
raise "Missing mandatory Block when calling JMS::Session#destination" unless block
|
252
|
+
dest = nil
|
253
|
+
begin
|
254
|
+
dest = create_destination(params)
|
255
|
+
block.call(dest)
|
256
|
+
ensure
|
257
|
+
# Delete Temporary Queue / Topic
|
258
|
+
dest.delete if dest && dest.respond_to?(:delete)
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
# Return the queue matching the queue name supplied
|
263
|
+
# Call the Proc if supplied
|
264
|
+
def queue(queue_name, &block)
|
265
|
+
q = create_queue(queue_name)
|
266
|
+
block.call(q) if block
|
267
|
+
q
|
268
|
+
end
|
269
|
+
|
270
|
+
# Return a temporary queue
|
271
|
+
# The temporary queue is deleted once the block completes
|
272
|
+
# If no block is supplied then it should be deleted by the caller
|
273
|
+
# when no longer needed
|
274
|
+
def temporary_queue(&block)
|
275
|
+
q = create_temporary_queue
|
276
|
+
if block
|
277
|
+
begin
|
278
|
+
block.call(q)
|
279
|
+
ensure
|
280
|
+
# Delete Temporary queue on completion of block
|
281
|
+
q.delete if q
|
282
|
+
q = nil
|
283
|
+
end
|
284
|
+
end
|
285
|
+
q
|
286
|
+
end
|
287
|
+
|
288
|
+
# Return the topic matching the topic name supplied
|
289
|
+
# Call the Proc if supplied
|
290
|
+
def topic(topic_name, &proc)
|
291
|
+
t = create_topic(topic_name)
|
292
|
+
proc.call(t) if proc
|
293
|
+
t
|
294
|
+
end
|
295
|
+
|
296
|
+
# Return a temporary topic
|
297
|
+
# The temporary topic is deleted once the block completes
|
298
|
+
# If no block is supplied then it should be deleted by the caller
|
299
|
+
# when no longer needed
|
300
|
+
def temporary_topic(&block)
|
301
|
+
t = create_temporary_topic
|
302
|
+
if block
|
303
|
+
begin
|
304
|
+
block.call(t)
|
305
|
+
ensure
|
306
|
+
# Delete Temporary topic on completion of block
|
307
|
+
t.delete if t
|
308
|
+
t = nil
|
309
|
+
end
|
310
|
+
end
|
311
|
+
t
|
312
|
+
end
|
313
|
+
|
314
|
+
# Return a producer for the queue name supplied
|
315
|
+
# A producer supports sending messages to a Queue or a Topic
|
316
|
+
#
|
317
|
+
# Call the Proc if supplied, then automatically close the producer
|
318
|
+
#
|
319
|
+
# Parameters:
|
320
|
+
# :queue_name => String: Name of the Queue to return
|
321
|
+
# Symbol: :temporary => Create temporary queue
|
322
|
+
# Mandatory unless :topic_name is supplied
|
323
|
+
# Or,
|
324
|
+
# :topic_name => String: Name of the Topic to write to or subscribe to
|
325
|
+
# Symbol: :temporary => Create temporary topic
|
326
|
+
# Mandatory unless :queue_name is supplied
|
327
|
+
# Or,
|
328
|
+
# :destination=> Explicit JMS::Destination to use
|
329
|
+
def producer(params, &proc)
|
330
|
+
p = self.create_producer(self.create_destination(params))
|
331
|
+
if proc
|
332
|
+
begin
|
333
|
+
proc.call(p)
|
334
|
+
ensure
|
335
|
+
p.close
|
336
|
+
p = nil
|
337
|
+
end
|
338
|
+
end
|
339
|
+
p
|
340
|
+
end
|
341
|
+
|
342
|
+
# Return a consumer for the destination
|
343
|
+
# A consumer can read messages from the queue or topic
|
344
|
+
#
|
345
|
+
# Call the Proc if supplied, then automatically close the consumer
|
346
|
+
#
|
347
|
+
# Parameters:
|
348
|
+
# :queue_name => String: Name of the Queue to return
|
349
|
+
# Symbol: :temporary => Create temporary queue
|
350
|
+
# Mandatory unless :topic_name is supplied
|
351
|
+
# Or,
|
352
|
+
# :topic_name => String: Name of the Topic to write to or subscribe to
|
353
|
+
# Symbol: :temporary => Create temporary topic
|
354
|
+
# Mandatory unless :queue_name is supplied
|
355
|
+
# Or,
|
356
|
+
# :destination=> Explicit javaxJms::Destination to use
|
357
|
+
#
|
358
|
+
# :selector => Filter which messages should be returned from the queue
|
359
|
+
# Default: All messages
|
360
|
+
# :no_local => Determine whether messages published by its own connection
|
361
|
+
# should be delivered to it
|
362
|
+
# Default: false
|
363
|
+
def consumer(params, &proc)
|
364
|
+
destination = create_destination(params)
|
365
|
+
c = nil
|
366
|
+
if params[:no_local]
|
367
|
+
c = create_consumer(destination, params[:selector] || '', params[:no_local])
|
368
|
+
elsif params[:selector]
|
369
|
+
c = create_consumer(destination, params[:selector])
|
370
|
+
else
|
371
|
+
c = create_consumer(destination)
|
372
|
+
end
|
373
|
+
|
374
|
+
if proc
|
375
|
+
begin
|
376
|
+
proc.call(c)
|
377
|
+
ensure
|
378
|
+
c.close
|
379
|
+
c = nil
|
380
|
+
end
|
381
|
+
end
|
382
|
+
c
|
383
|
+
end
|
384
|
+
|
385
|
+
# Consume all messages for the destination
|
386
|
+
# A consumer can read messages from the queue or topic
|
387
|
+
#
|
388
|
+
# Parameters:
|
389
|
+
# :queue_name => String: Name of the Queue to return
|
390
|
+
# Symbol: :temporary => Create temporary queue
|
391
|
+
# Mandatory unless :topic_name is supplied
|
392
|
+
# Or,
|
393
|
+
# :topic_name => String: Name of the Topic to write to or subscribe to
|
394
|
+
# Symbol: :temporary => Create temporary topic
|
395
|
+
# Mandatory unless :queue_name is supplied
|
396
|
+
# Or,
|
397
|
+
# :destination=> Explicit javaxJms::Destination to use
|
398
|
+
#
|
399
|
+
# :selector => Filter which messages should be returned from the queue
|
400
|
+
# Default: All messages
|
401
|
+
# :no_local => Determine whether messages published by its own connection
|
402
|
+
# should be delivered to it
|
403
|
+
# Default: false
|
404
|
+
#
|
405
|
+
# :timeout Follows the rules for MQSeries:
|
406
|
+
# -1 : Wait forever
|
407
|
+
# 0 : Return immediately if no message is available
|
408
|
+
# x : Wait for x milli-seconds for a message to be received from the broker
|
409
|
+
# Note: Messages may still be on the queue, but the broker has not supplied any messages
|
410
|
+
# in the time interval specified
|
411
|
+
# Default: 0
|
412
|
+
#
|
413
|
+
def consume(params, &proc)
|
414
|
+
c = self.consumer(params)
|
415
|
+
begin
|
416
|
+
c.each(params, &proc)
|
417
|
+
ensure
|
418
|
+
c.close
|
419
|
+
end
|
420
|
+
end
|
421
|
+
|
422
|
+
# Return a browser for the destination
|
423
|
+
# A browser can read messages non-destructively from the queue
|
424
|
+
# It cannot browse Topics!
|
425
|
+
#
|
426
|
+
# Call the Proc if supplied, then automatically close the consumer
|
427
|
+
#
|
428
|
+
# Parameters:
|
429
|
+
# :queue_name => String: Name of the Queue to return
|
430
|
+
# Symbol: :temporary => Create temporary queue
|
431
|
+
# Mandatory unless :topic_name is supplied
|
432
|
+
# Or,
|
433
|
+
# :destination=> Explicit javaxJms::Destination to use
|
434
|
+
#
|
435
|
+
# :selector => Filter which messages should be returned from the queue
|
436
|
+
# Default: All messages
|
437
|
+
def browser(params, &proc)
|
438
|
+
raise "Session::browser requires a code block to be executed" unless proc
|
439
|
+
|
440
|
+
destination = create_destination(params)
|
441
|
+
b = nil
|
442
|
+
if params[:selector]
|
443
|
+
b = create_browser(destination, params[:selector])
|
444
|
+
else
|
445
|
+
b = create_browser(destination)
|
446
|
+
end
|
447
|
+
|
448
|
+
if proc
|
449
|
+
begin
|
450
|
+
proc.call(b)
|
451
|
+
ensure
|
452
|
+
b.close
|
453
|
+
b = nil
|
454
|
+
end
|
455
|
+
end
|
456
|
+
b
|
457
|
+
end
|
458
|
+
|
459
|
+
# Browse the specified queue, calling the Proc supplied for each message found
|
460
|
+
#
|
461
|
+
# Parameters:
|
462
|
+
# :queue_name => String: Name of the Queue to return
|
463
|
+
# Symbol: :temporary => Create temporary queue
|
464
|
+
# Mandatory unless :topic_name is supplied
|
465
|
+
# Or,
|
466
|
+
# :destination=> Explicit javaxJms::Destination to use
|
467
|
+
#
|
468
|
+
# :selector => Filter which messages should be returned from the queue
|
469
|
+
# Default: All messages
|
470
|
+
def browse(params={}, &proc)
|
471
|
+
self.browser(params) {|b| b.each(params, &proc)}
|
472
|
+
end
|
473
|
+
end
|