jruby-jms 1.1.0-java
Sign up to get free protection for your applications and to get access to all the features.
- 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
|