jruby-jms 0.9.0
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 +13 -0
- data/LICENSE.txt +201 -0
- data/README.md +276 -0
- data/Rakefile +22 -0
- data/examples/consumer.rb +23 -0
- data/examples/jms.yml +22 -0
- data/examples/log4j.properties +31 -0
- data/examples/performance/consumer.rb +27 -0
- data/examples/performance/producer.rb +31 -0
- data/examples/producer.rb +23 -0
- data/lib/jms.rb +25 -0
- data/lib/jms/connection.rb +480 -0
- data/lib/jms/javax_jms_map_message.rb +91 -0
- data/lib/jms/javax_jms_message.rb +264 -0
- data/lib/jms/javax_jms_message_consumer.rb +114 -0
- data/lib/jms/javax_jms_object_message.rb +26 -0
- data/lib/jms/javax_jms_queue_browser.rb +27 -0
- data/lib/jms/javax_jms_session.rb +285 -0
- data/lib/jms/javax_jms_text_message.rb +31 -0
- metadata +74 -0
@@ -0,0 +1,91 @@
|
|
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.MapMessage
|
18
|
+
module javax.jms::MapMessage
|
19
|
+
# Since each is defined, add support for: inject, map, include?, and find_all?
|
20
|
+
# <=> also allows support for: min, max, and sort
|
21
|
+
include Enumerable
|
22
|
+
|
23
|
+
# Return Map Message as a hash
|
24
|
+
def to_h
|
25
|
+
h = {}
|
26
|
+
each_pair {|key, value| h[key] = value}
|
27
|
+
h
|
28
|
+
end
|
29
|
+
|
30
|
+
# Return Map Message as a hash
|
31
|
+
def data
|
32
|
+
to_h
|
33
|
+
end
|
34
|
+
|
35
|
+
# Copy values from supplied hash into this MapMessage
|
36
|
+
# Converts Ruby types to Java native Data types as follows:
|
37
|
+
# Fixnum => long
|
38
|
+
# Float => double
|
39
|
+
# Bignum => long
|
40
|
+
# true => boolean
|
41
|
+
# false => boolean
|
42
|
+
# nil => null
|
43
|
+
# Otherwise it calls ::to_s on the supplied data type
|
44
|
+
def data=(data)
|
45
|
+
data.each_pair do |key,val|
|
46
|
+
case
|
47
|
+
when val.class == Fixnum # 1
|
48
|
+
setLong(key.to_s,val)
|
49
|
+
when val.class == Float #1.1
|
50
|
+
setDouble(key.to_s,val)
|
51
|
+
when val.class == Bignum # 11111111111111111
|
52
|
+
setLong(key.to_s,val)
|
53
|
+
when (val.class == TrueClass) || (val.class == FalseClass)
|
54
|
+
setBoolean(key.to_s,val)
|
55
|
+
when val.class == NilClass
|
56
|
+
setObject(key.to_s,val)
|
57
|
+
else
|
58
|
+
setString(key.to_s,val.to_s)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# Return each name value pair
|
64
|
+
def each(&proc)
|
65
|
+
# When key and value are expected separately. Should actually be calling each_pair anyway
|
66
|
+
if proc.arity == 2
|
67
|
+
each_pair(proc)
|
68
|
+
else
|
69
|
+
enum = getMapNames
|
70
|
+
while enum.has_more_elements
|
71
|
+
key = enum.next_element
|
72
|
+
proc.call [key, getObject(key)]
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Return each name value pair
|
78
|
+
def each_pair(&proc)
|
79
|
+
enum = getMapNames
|
80
|
+
while enum.has_more_elements
|
81
|
+
key = enum.next_element
|
82
|
+
proc.call key, getObject(key)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Does map include specified key
|
87
|
+
def include?(key)
|
88
|
+
# Ensure a Ruby true is returned
|
89
|
+
item_exists key == true
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,264 @@
|
|
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 Interface with Ruby methods
|
18
|
+
#
|
19
|
+
# A Message is the item that can be put on a queue, or obtained from a queue.
|
20
|
+
#
|
21
|
+
# A Message consists of 3 major parts:
|
22
|
+
# - Header
|
23
|
+
# Accessible as attributes of the Message class
|
24
|
+
# - Properties
|
25
|
+
# Accessible via [] and []= methods
|
26
|
+
# - Data
|
27
|
+
# The actual data portion of the message
|
28
|
+
# See the specific message types for details on how to access the data
|
29
|
+
# portion of the message
|
30
|
+
#
|
31
|
+
# For further help on javax.jms.Message
|
32
|
+
# http://download.oracle.com/javaee/6/api/index.html?javax/jms/Message.html
|
33
|
+
#
|
34
|
+
# Interface javax.jms.Message
|
35
|
+
module javax.jms::Message
|
36
|
+
|
37
|
+
# Methods directly exposed from the Java class:
|
38
|
+
|
39
|
+
# call-seq:
|
40
|
+
# acknowledge
|
41
|
+
#
|
42
|
+
# Acknowledges all consumed messages of the session of this consumed message
|
43
|
+
#
|
44
|
+
|
45
|
+
# call-seq:
|
46
|
+
# clear_body
|
47
|
+
#
|
48
|
+
# Clears out the message body
|
49
|
+
#
|
50
|
+
|
51
|
+
# call-seq:
|
52
|
+
# clear_properties
|
53
|
+
#
|
54
|
+
# Clears out the properties of this message
|
55
|
+
#
|
56
|
+
|
57
|
+
# Header Fields - Attributes of the message
|
58
|
+
|
59
|
+
# Return the JMS Delivery Mode as a symbol
|
60
|
+
# :peristent
|
61
|
+
# :non_peristent
|
62
|
+
# other: Value from javax.jms.DeliveryMode
|
63
|
+
def jms_delivery_mode
|
64
|
+
case getJMSDeliveryMode
|
65
|
+
when javax.jms.DeliveryMode::PERSISTENT
|
66
|
+
:peristent
|
67
|
+
when javax.jms.DeliveryMode::NON_PERSISTENT
|
68
|
+
:non_peristent
|
69
|
+
else
|
70
|
+
getJMSDeliveryMode
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Set the JMS Delivery Mode
|
75
|
+
# Valid values for mode
|
76
|
+
# :peristent
|
77
|
+
# :non_peristent
|
78
|
+
# other: Any constant from javax.jms.DeliveryMode
|
79
|
+
def jms_delivery_mode=(mode)
|
80
|
+
val = case mode
|
81
|
+
when :peristent
|
82
|
+
javax.jms.DeliveryMode::PERSISTENT
|
83
|
+
when :non_peristent
|
84
|
+
javax.jms.DeliveryMode::NON_PERSISTENT
|
85
|
+
else
|
86
|
+
mode
|
87
|
+
end
|
88
|
+
self.setJMSDeliveryMode(val)
|
89
|
+
end
|
90
|
+
|
91
|
+
# Is the message persistent?
|
92
|
+
def persistent?
|
93
|
+
getJMSDeliveryMode == javax.jms.DeliveryMode::PERSISTENT
|
94
|
+
end
|
95
|
+
|
96
|
+
# Returns the Message correlation ID as a String
|
97
|
+
# The resulting string may contain nulls
|
98
|
+
def jms_correlation_id
|
99
|
+
String.from_java_bytes(getJMSCorrelationIDAsBytes) if getJMSCorrelationIDAsBytes
|
100
|
+
end
|
101
|
+
|
102
|
+
# Set the Message correlation ID
|
103
|
+
# correlation_id: String
|
104
|
+
# Also supports embedded nulls within the correlation id
|
105
|
+
def jms_correlation_id=(correlation_id)
|
106
|
+
setJMSCorrelationIDAsBytes(correlation_id.nil? ? nil : correlation_id.to_java_bytes)
|
107
|
+
end
|
108
|
+
|
109
|
+
# Returns the Message Destination
|
110
|
+
# Instance of javax.jms.Destination
|
111
|
+
def jms_destination
|
112
|
+
getJMSDestination
|
113
|
+
end
|
114
|
+
|
115
|
+
# Set the Message Destination
|
116
|
+
# jms_destination: Must be an instance of javax.jms.Destination
|
117
|
+
def jms_destination=(destination)
|
118
|
+
setJMSDestination(destination)
|
119
|
+
end
|
120
|
+
|
121
|
+
# Return the message expiration value as an Integer
|
122
|
+
def jms_expiration
|
123
|
+
getJMSExpiration
|
124
|
+
end
|
125
|
+
|
126
|
+
# Set the Message expiration value
|
127
|
+
# expiration: Integer
|
128
|
+
def jms_expiration=(expiration)
|
129
|
+
setJMSExpiration(expiration)
|
130
|
+
end
|
131
|
+
|
132
|
+
# Returns the Message ID as a String
|
133
|
+
# The resulting string may contain embedded nulls
|
134
|
+
def jms_message_id
|
135
|
+
getJMSMessageID
|
136
|
+
end
|
137
|
+
|
138
|
+
# Set the Message correlation ID
|
139
|
+
# message_id: String
|
140
|
+
# Also supports nulls within the message id
|
141
|
+
def jms_message_id=(message_id)
|
142
|
+
setJMSMessageID(message_id)
|
143
|
+
end
|
144
|
+
|
145
|
+
# Returns the Message Priority level as an Integer
|
146
|
+
def jms_priority
|
147
|
+
getJMSPriority
|
148
|
+
end
|
149
|
+
|
150
|
+
# Set the Message priority level
|
151
|
+
# priority: Integer
|
152
|
+
def jms_priority=(priority)
|
153
|
+
setJMSPriority(priority)
|
154
|
+
end
|
155
|
+
|
156
|
+
# Indicates whether the Message was redelivered?
|
157
|
+
def jms_redelivered?
|
158
|
+
getJMSRedelivered
|
159
|
+
end
|
160
|
+
|
161
|
+
# Set whether the Message was redelivered
|
162
|
+
# bool: Boolean
|
163
|
+
def jms_redelivered=(bool)
|
164
|
+
setJMSPriority(bool)
|
165
|
+
end
|
166
|
+
|
167
|
+
# Returns the Message reply to Destination
|
168
|
+
# Instance of javax.jms.Destination
|
169
|
+
def jms_reply_to
|
170
|
+
getJMSReplyTo
|
171
|
+
end
|
172
|
+
|
173
|
+
# Set the Message reply to Destination
|
174
|
+
# reply_to: Must be an instance of javax.jms.Destination
|
175
|
+
def jms_reply_to=(reply_to)
|
176
|
+
setJMSReplyTo(reply_to)
|
177
|
+
end
|
178
|
+
|
179
|
+
# Returns the Message timestamp as Java Timestamp Integer
|
180
|
+
#TODO Return Ruby Time object?
|
181
|
+
def jms_timestamp
|
182
|
+
getJMSTimestamp
|
183
|
+
end
|
184
|
+
|
185
|
+
# Set the Message reply to Destination
|
186
|
+
# timestamp: Must be an Java Timestamp Integer
|
187
|
+
#TODO Support Ruby Time
|
188
|
+
def jms_timestamp=(timestamp)
|
189
|
+
setJMSTimestamp(timestamp)
|
190
|
+
end
|
191
|
+
|
192
|
+
# Returns the Message type supplied by the client when the message was sent
|
193
|
+
def jms_type
|
194
|
+
getJMSType
|
195
|
+
end
|
196
|
+
|
197
|
+
# Sets the Message type
|
198
|
+
# type: String
|
199
|
+
def jms_type=(type)
|
200
|
+
setJMSType(type)
|
201
|
+
end
|
202
|
+
|
203
|
+
# Return the attributes (header fields) of the message as a Hash
|
204
|
+
def attributes
|
205
|
+
{
|
206
|
+
:jms_correlation_id => jms_correlation_id,
|
207
|
+
:jms_delivery_mode => jms_delivery_mode,
|
208
|
+
:jms_destination => jms_destination,
|
209
|
+
:jms_expiration => jms_expiration,
|
210
|
+
:jms_message_id => jms_message_id,
|
211
|
+
:jms_priority => jms_priority,
|
212
|
+
:jms_redelivered => jms_redelivered?,
|
213
|
+
:jms_reply_to => jms_reply_to,
|
214
|
+
:jms_timestamp => jms_timestamp,
|
215
|
+
:jms_type => jms_type,
|
216
|
+
}
|
217
|
+
end
|
218
|
+
|
219
|
+
# Methods for manipulating the message properties
|
220
|
+
|
221
|
+
# Get the value of a property
|
222
|
+
def [](key)
|
223
|
+
getObjectProperty key.to_s
|
224
|
+
end
|
225
|
+
|
226
|
+
# Set a property
|
227
|
+
def []=(key, value)
|
228
|
+
setObjectProperty(key.to_s, value)
|
229
|
+
end
|
230
|
+
|
231
|
+
# Does message include specified property?
|
232
|
+
def include?(key)
|
233
|
+
# Ensure a Ruby true is returned
|
234
|
+
property_exists key == true
|
235
|
+
end
|
236
|
+
|
237
|
+
# Return Properties as a hash
|
238
|
+
def properties
|
239
|
+
h = {}
|
240
|
+
properties_each_pair {|k,v| h[k]=v}
|
241
|
+
h
|
242
|
+
end
|
243
|
+
|
244
|
+
# Set Properties from an existing hash
|
245
|
+
def properties=(h)
|
246
|
+
clear_properties
|
247
|
+
h.each_pair {|k,v| setObjectProperty(k.to_s, v)}
|
248
|
+
h
|
249
|
+
end
|
250
|
+
|
251
|
+
# Return each name value pair
|
252
|
+
def properties_each_pair(&proc)
|
253
|
+
enum = getPropertyNames
|
254
|
+
while enum.has_more_elements
|
255
|
+
key = enum.next_element
|
256
|
+
proc.call key, getObjectProperty(key)
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
def inspect
|
261
|
+
"#{self.class.name}: #{data}\nAttributes: #{attributes.inspect}\nProperties: #{properties.inspect}"
|
262
|
+
end
|
263
|
+
|
264
|
+
end
|
@@ -0,0 +1,114 @@
|
|
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 javax.jms::MessageConsumer
|
18
|
+
# Obtain a message from the Destination or Topic
|
19
|
+
# In JMS terms, the message is received from the Destination
|
20
|
+
# :timeout follows the rules for MQSeries:
|
21
|
+
# -1 : Wait forever
|
22
|
+
# 0 : Return immediately if no message is available
|
23
|
+
# x : Wait for x milli-seconds for a message to be received from the broker
|
24
|
+
# Note: Messages may still be on the queue, but the broker has not supplied any messages
|
25
|
+
# in the time interval specified
|
26
|
+
# Default: 0
|
27
|
+
def get(parms={})
|
28
|
+
timeout = parms[:timeout] || 0
|
29
|
+
if timeout == -1
|
30
|
+
self.receive
|
31
|
+
elsif timeout == 0
|
32
|
+
self.receiveNoWait
|
33
|
+
else
|
34
|
+
self.receive(timeout)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# For each message available to be consumed call the Proc supplied
|
39
|
+
# Returns the statistics gathered when :statistics => true, otherwise nil
|
40
|
+
#
|
41
|
+
# Parameters:
|
42
|
+
# :timeout How to timeout waiting for messages on the Queue or Topic
|
43
|
+
# -1 : Wait forever
|
44
|
+
# 0 : Return immediately if no message is available
|
45
|
+
# x : Wait for x milli-seconds for a message to be received from the broker
|
46
|
+
# Note: Messages may still be on the queue, but the broker has not supplied any messages
|
47
|
+
# in the time interval specified
|
48
|
+
# Default: 0
|
49
|
+
#
|
50
|
+
# :statistics Capture statistics on how many messages have been read
|
51
|
+
# true : This method will capture statistics on the number of messages received
|
52
|
+
# and the time it took to process them.
|
53
|
+
# The statistics can be reset by calling MessageConsumer::each again
|
54
|
+
# with :statistics => true
|
55
|
+
#
|
56
|
+
# The statistics gathered are returned when :statistics => true and :async => false
|
57
|
+
def each(parms={}, &proc)
|
58
|
+
raise "Destination::each requires a code block to be executed for each message received" unless proc
|
59
|
+
|
60
|
+
message_count = nil
|
61
|
+
start_time = nil
|
62
|
+
|
63
|
+
if parms[:statistics]
|
64
|
+
message_count = 0
|
65
|
+
start_time = Time.now
|
66
|
+
end
|
67
|
+
|
68
|
+
# Receive messages according to timeout
|
69
|
+
while message = self.get(parms) do
|
70
|
+
proc.call(message)
|
71
|
+
message_count += 1 if message_count
|
72
|
+
end
|
73
|
+
|
74
|
+
unless message_count.nil?
|
75
|
+
duration = Time.now - start_time
|
76
|
+
{:messages => message_count,
|
77
|
+
:duration => duration,
|
78
|
+
:messages_per_second => (message_count/duration).to_i}
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Receive messages in a separate thread when they arrive
|
83
|
+
# Allows messages to be recieved in a separate thread. I.e. Asynchronously
|
84
|
+
# This method will return to the caller before messages are processed.
|
85
|
+
# It is then the callers responsibility to keep the program active so that messages
|
86
|
+
# can then be processed.
|
87
|
+
#
|
88
|
+
# Parameters:
|
89
|
+
# :statistics Capture statistics on how many messages have been read
|
90
|
+
# true : This method will capture statistics on the number of messages received
|
91
|
+
# and the time it took to process them.
|
92
|
+
# The timer starts when each() is called and finishes when either the last message was received,
|
93
|
+
# or when Destination::statistics is called. In this case MessageConsumer::statistics
|
94
|
+
# can be called several times during processing without affecting the end time.
|
95
|
+
# Also, the start time and message count is not reset until MessageConsumer::each
|
96
|
+
# is called again with :statistics => true
|
97
|
+
#
|
98
|
+
# The statistics gathered are returned when :statistics => true and :async => false
|
99
|
+
#
|
100
|
+
def on_message(parms={}, &proc)
|
101
|
+
raise "MessageConsumer::on_message requires a code block to be executed for each message received" unless proc
|
102
|
+
|
103
|
+
@listener = JMS::MessageListener.new(parms,&proc)
|
104
|
+
self.setMessageListener @listener
|
105
|
+
end
|
106
|
+
|
107
|
+
# Return the current statistics for a running MessageConsumer::on_message
|
108
|
+
def on_message_statistics
|
109
|
+
stats = @listener.statistics if @listener
|
110
|
+
raise "First call MessageConsumer::on_message with :statistics=>true before calling MessageConsumer::statistics()" unless stats
|
111
|
+
stats
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|