jruby-jms 0.10.2 → 0.11.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.
Files changed (70) hide show
  1. data/HISTORY.md +15 -0
  2. data/README.md +27 -28
  3. data/Rakefile +7 -1
  4. data/doc/classes/JMS.html +265 -0
  5. data/doc/classes/JMS/BytesMessage.html +215 -0
  6. data/doc/classes/JMS/Connection.html +1145 -0
  7. data/doc/classes/JMS/MapMessage.html +333 -0
  8. data/doc/classes/JMS/Message.html +1085 -0
  9. data/doc/classes/JMS/MessageConsumer.html +316 -0
  10. data/doc/classes/JMS/MessageListenerImpl.html +262 -0
  11. data/doc/classes/JMS/ObjectMessage.html +170 -0
  12. data/doc/classes/JMS/OracleAQConnectionFactory.html +184 -0
  13. data/doc/classes/JMS/QueueBrowser.html +155 -0
  14. data/doc/classes/JMS/Session.html +947 -0
  15. data/doc/classes/JMS/SessionPool.html +411 -0
  16. data/doc/classes/JMS/TextMessage.html +194 -0
  17. data/doc/created.rid +1 -0
  18. data/doc/files/README_md.html +440 -0
  19. data/doc/files/lib/jms/bytes_message_rb.html +122 -0
  20. data/doc/files/lib/jms/connection_rb.html +140 -0
  21. data/doc/files/lib/jms/imports_rb.html +108 -0
  22. data/doc/files/lib/jms/logging_rb.html +129 -0
  23. data/doc/files/lib/jms/map_message_rb.html +122 -0
  24. data/doc/files/lib/jms/message_consumer_rb.html +122 -0
  25. data/doc/files/lib/jms/message_listener_impl_rb.html +122 -0
  26. data/doc/files/lib/jms/message_rb.html +122 -0
  27. data/doc/files/lib/jms/object_message_rb.html +122 -0
  28. data/doc/files/lib/jms/oracle_a_q_connection_factory_rb.html +122 -0
  29. data/doc/files/lib/jms/queue_browser_rb.html +122 -0
  30. data/doc/files/lib/jms/session_pool_rb.html +108 -0
  31. data/doc/files/lib/jms/session_rb.html +164 -0
  32. data/doc/files/lib/jms/text_message_rb.html +122 -0
  33. data/doc/files/lib/jms_rb.html +131 -0
  34. data/doc/fr_class_index.html +39 -0
  35. data/doc/fr_file_index.html +42 -0
  36. data/doc/fr_method_index.html +120 -0
  37. data/doc/index.html +24 -0
  38. data/doc/rdoc-style.css +208 -0
  39. data/examples/advanced/session_pool.rb +37 -0
  40. data/examples/client-server/replier.rb +29 -0
  41. data/examples/client-server/requestor.rb +40 -0
  42. data/examples/jms.yml +85 -9
  43. data/examples/performance/consumer.rb +6 -8
  44. data/examples/performance/producer.rb +10 -10
  45. data/examples/producer-consumer/browser.rb +24 -0
  46. data/examples/{consumer.rb → producer-consumer/consumer.rb} +5 -4
  47. data/examples/producer-consumer/consumer_async.rb +30 -0
  48. data/examples/{producer.rb → producer-consumer/producer.rb} +5 -3
  49. data/examples/publish-subscribe/publish.rb +24 -0
  50. data/examples/publish-subscribe/subscribe.rb +31 -0
  51. data/lib/jms/bytes_message.rb +52 -0
  52. data/lib/jms/connection.rb +170 -162
  53. data/lib/jms/imports.rb +21 -0
  54. data/lib/jms/logging.rb +17 -1
  55. data/lib/jms/{javax_jms_map_message.rb → map_message.rb} +2 -2
  56. data/lib/jms/message.rb +285 -0
  57. data/lib/jms/{javax_jms_message_consumer.rb → message_consumer.rb} +6 -3
  58. data/lib/jms/{message_listener.rb → message_listener_impl.rb} +3 -3
  59. data/lib/jms/{javax_jms_object_message.rb → object_message.rb} +1 -1
  60. data/lib/jms/oracle_a_q_connection_factory.rb +35 -0
  61. data/lib/jms/{javax_jms_queue_browser.rb → queue_browser.rb} +5 -4
  62. data/lib/jms/{javax_jms_session.rb → session.rb} +23 -25
  63. data/lib/jms/session_pool.rb +148 -0
  64. data/lib/jms/{javax_jms_text_message.rb → text_message.rb} +1 -1
  65. data/test/connection_test.rb +31 -29
  66. data/test/jms.yml +8 -9
  67. data/test/message_test.rb +29 -29
  68. data/test/session_test.rb +39 -39
  69. metadata +62 -22
  70. data/lib/jms/javax_jms_message.rb +0 -264
@@ -1,5 +1,5 @@
1
1
  #
2
- # Sample Consumer:
2
+ # Sample Consumer:
3
3
  # Retrieve all messages from a queue
4
4
  #
5
5
 
@@ -10,18 +10,16 @@ require 'rubygems'
10
10
  require 'yaml'
11
11
  require 'jms'
12
12
 
13
- jms_provider = ARGV[1] || 'actvemq'
13
+ jms_provider = ARGV[0] || 'activemq'
14
14
 
15
15
  # Load Connection parameters from configuration file
16
16
  config = YAML.load_file(File.join(File.dirname(__FILE__), '..', 'jms.yml'))[jms_provider]
17
17
  raise "JMS Provider option:#{jms_provider} not found in jms.yml file" unless config
18
18
 
19
19
  JMS::Connection.session(config) do |session|
20
- session.consumer(:queue_name => 'ExampleQueue') do |consumer|
21
- stats = consumer.each(:statistics => true) do |message|
22
- puts "=================================="
23
- p message
24
- end
25
- puts "STATISTICS :" + stats.inspect
20
+ stats = session.consume(:queue_name => 'ExampleQueue', :statistics => true) do |message|
21
+ # Do nothing in this example with each message
26
22
  end
23
+
24
+ JMS::logger.info "Consumed #{stats[:messages]} messages. Average #{stats[:ms_per_msg]}ms per message"
27
25
  end
@@ -1,6 +1,6 @@
1
1
  #
2
2
  # Sample Producer:
3
- # Write messages to the queue
3
+ # Write multiple messages to the queue
4
4
  #
5
5
 
6
6
  # Allow examples to be run in-place without requiring a gem install
@@ -9,23 +9,23 @@ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../../lib'
9
9
  require 'rubygems'
10
10
  require 'yaml'
11
11
  require 'jms'
12
-
12
+ require 'benchmark'
13
+
13
14
  jms_provider = ARGV[0] || 'activemq'
14
- count = (ARGV[1] || 5).to_i
15
+ count = (ARGV[1] || 10).to_i
15
16
 
16
17
  # Load Connection parameters from configuration file
17
18
  config = YAML.load_file(File.join(File.dirname(__FILE__), '..', 'jms.yml'))[jms_provider]
18
19
  raise "JMS Provider option:#{jms_provider} not found in jms.yml file" unless config
19
20
 
20
21
  JMS::Connection.session(config) do |session|
21
- start_time = Time.now
22
-
23
- session.producer(:queue_name => 'ExampleQueue') do |producer|
24
- count.times do |i|
25
- producer.send(session.message("Hello Producer #{i}"))
22
+ duration = Benchmark.realtime do
23
+ session.producer(:queue_name => 'ExampleQueue') do |producer|
24
+ count.times do |i|
25
+ producer.send(session.message("Hello Producer #{i}"))
26
+ end
26
27
  end
27
28
  end
28
29
 
29
- duration = Time.now - start_time
30
- puts "Delivered #{count} messages in #{duration} seconds at #{count/duration} messages per second"
30
+ JMS::logger.info "Produced #{count} messages. Average #{duration*1000/count}ms per message"
31
31
  end
@@ -0,0 +1,24 @@
1
+ #
2
+ # Sample Browsing Consumer:
3
+ # Browse all messages on a queue without removing them
4
+ #
5
+
6
+ # Allow examples to be run in-place without requiring a gem install
7
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../../lib'
8
+
9
+ require 'rubygems'
10
+ require 'jms'
11
+ require 'yaml'
12
+
13
+ jms_provider = ARGV[0] || 'activemq'
14
+
15
+ # Load Connection parameters from configuration file
16
+ config = YAML.load_file(File.join(File.dirname(__FILE__), '..', 'jms.yml'))[jms_provider]
17
+ raise "JMS Provider option:#{jms_provider} not found in jms.yml file" unless config
18
+
19
+ # Consume all available messages on the queue
20
+ JMS::Connection.session(config) do |session|
21
+ session.browse(:queue_name => 'ExampleQueue', :timeout=>1000) do |message|
22
+ JMS::logger.info message.inspect
23
+ end
24
+ end
@@ -1,10 +1,10 @@
1
1
  #
2
- # Sample Consumer:
2
+ # Sample Consumer:
3
3
  # Retrieve all messages from a queue
4
4
  #
5
5
 
6
6
  # Allow examples to be run in-place without requiring a gem install
7
- $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
7
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../../lib'
8
8
 
9
9
  require 'rubygems'
10
10
  require 'jms'
@@ -13,11 +13,12 @@ require 'yaml'
13
13
  jms_provider = ARGV[0] || 'activemq'
14
14
 
15
15
  # Load Connection parameters from configuration file
16
- config = YAML.load_file(File.join(File.dirname(__FILE__), 'jms.yml'))[jms_provider]
16
+ config = YAML.load_file(File.join(File.dirname(__FILE__), '..', 'jms.yml'))[jms_provider]
17
17
  raise "JMS Provider option:#{jms_provider} not found in jms.yml file" unless config
18
18
 
19
+ # Consume all available messages on the queue
19
20
  JMS::Connection.session(config) do |session|
20
21
  session.consume(:queue_name => 'ExampleQueue', :timeout=>1000) do |message|
21
- p message
22
+ JMS::logger.info message.inspect
22
23
  end
23
24
  end
@@ -0,0 +1,30 @@
1
+ #
2
+ # Sample Asynchronous Consumer:
3
+ # Retrieve all messages from the queue in a separate thread
4
+ #
5
+
6
+ # Allow examples to be run in-place without requiring a gem install
7
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../../lib'
8
+
9
+ require 'rubygems'
10
+ require 'jms'
11
+ require 'yaml'
12
+
13
+ jms_provider = ARGV[0] || 'activemq'
14
+
15
+ # Load Connection parameters from configuration file
16
+ config = YAML.load_file(File.join(File.dirname(__FILE__), '..', 'jms.yml'))[jms_provider]
17
+ raise "JMS Provider option:#{jms_provider} not found in jms.yml file" unless config
18
+
19
+ # Consume all available messages on the queue
20
+ JMS::Connection.start(config) do |connection|
21
+
22
+ # Define Asynchronous code block to be called every time a message is receive
23
+ connection.on_message(:queue_name => 'ExampleQueue') do |message|
24
+ JMS::logger.info message.inspect
25
+ end
26
+
27
+ # Since the on_message handler above is in a separate thread the thread needs
28
+ # to do some other work. For this example it will just sleep for 10 seconds
29
+ sleep 10
30
+ end
@@ -4,7 +4,7 @@
4
4
  #
5
5
 
6
6
  # Allow examples to be run in-place without requiring a gem install
7
- $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
7
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../../lib'
8
8
 
9
9
  require 'rubygems'
10
10
  require 'yaml'
@@ -13,11 +13,13 @@ require 'jms'
13
13
  jms_provider = ARGV[0] || 'activemq'
14
14
 
15
15
  # Load Connection parameters from configuration file
16
- config = YAML.load_file(File.join(File.dirname(__FILE__), 'jms.yml'))[jms_provider]
16
+ config = YAML.load_file(File.join(File.dirname(__FILE__), '..', 'jms.yml'))[jms_provider]
17
17
  raise "JMS Provider option:#{jms_provider} not found in jms.yml file" unless config
18
18
 
19
19
  JMS::Connection.session(config) do |session|
20
20
  session.producer(:queue_name => 'ExampleQueue') do |producer|
21
- producer.send(session.message("Hello World"))
21
+ producer.delivery_mode = JMS::DeliveryMode::NON_PERSISTENT
22
+ producer.send(session.message("Hello World: #{Time.now}"))
23
+ JMS::logger.info "Successfully sent one message to queue ExampleQueue"
22
24
  end
23
25
  end
@@ -0,0 +1,24 @@
1
+ #
2
+ # Sample Publisher:
3
+ # Write messages to a topic
4
+ #
5
+
6
+ # Allow examples to be run in-place without requiring a gem install
7
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../../lib'
8
+
9
+ require 'rubygems'
10
+ require 'yaml'
11
+ require 'jms'
12
+
13
+ jms_provider = ARGV[0] || 'activemq'
14
+
15
+ # Load Connection parameters from configuration file
16
+ config = YAML.load_file(File.join(File.dirname(__FILE__), '..', 'jms.yml'))[jms_provider]
17
+ raise "JMS Provider option:#{jms_provider} not found in jms.yml file" unless config
18
+
19
+ JMS::Connection.session(config) do |session|
20
+ session.producer(:topic_name => 'SampleTopic') do |producer|
21
+ producer.send(session.message("Hello World: #{Time.now}"))
22
+ JMS::logger.info "Successfully published one message to topic SampleTopic"
23
+ end
24
+ end
@@ -0,0 +1,31 @@
1
+ #
2
+ # Sample Topic Subscriber:
3
+ # Retrieve all messages from a topic using a non-durable subscription
4
+ #
5
+ # Try starting multiple copies of this Consumer. All active instances should
6
+ # receive the same messages
7
+ #
8
+ # Since the topic subscription is non-durable, it will only receive new messages.
9
+ # Any messages sent prior to the instance starting will not be received.
10
+ # Also, any messages sent after the instance has stopped will not be received
11
+ # when the instance is re-started, only new messages sent after it started will
12
+ # be received.
13
+
14
+ # Allow examples to be run in-place without requiring a gem install
15
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../../lib'
16
+
17
+ require 'rubygems'
18
+ require 'jms'
19
+ require 'yaml'
20
+
21
+ jms_provider = ARGV[0] || 'activemq'
22
+
23
+ # Load Connection parameters from configuration file
24
+ config = YAML.load_file(File.join(File.dirname(__FILE__), '..', 'jms.yml'))[jms_provider]
25
+ raise "JMS Provider option:#{jms_provider} not found in jms.yml file" unless config
26
+
27
+ JMS::Connection.session(config) do |session|
28
+ session.consume(:topic_name => 'SampleTopic', :timeout=>30000) do |message|
29
+ JMS::logger.info message.inspect
30
+ end
31
+ end
@@ -0,0 +1,52 @@
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.BytesMessage
18
+ module JMS::BytesMessage
19
+ def data
20
+ # Puts the message body in read-only mode and repositions the stream of
21
+ # bytes to the beginning
22
+ self.reset
23
+
24
+ available = self.body_length
25
+
26
+ return nil if available == 0
27
+
28
+ result = ""
29
+ bytes_size = 1024
30
+ bytes = Java::byte[bytes_size].new
31
+
32
+ while (n = available < bytes_size ? available : bytes_size) > 0
33
+ self.read_bytes(bytes, n)
34
+ if n == bytes_size
35
+ result << String.from_java_bytes(bytes)
36
+ else
37
+ result << String.from_java_bytes(bytes)[0..n-1]
38
+ end
39
+ available -= n
40
+ end
41
+ result
42
+ end
43
+
44
+ def data=(val)
45
+ self.write_bytes(val.respond_to?(:to_java_bytes) ? val.to_java_bytes : val)
46
+ end
47
+
48
+ def to_s
49
+ data
50
+ end
51
+
52
+ end
@@ -32,15 +32,15 @@ module JMS
32
32
  # require 'jms'
33
33
  #
34
34
  # JMS::Connection.create_session(
35
- # :queue_manager=>'REID', # Should be :q_mgr_name
36
- # :host_name=>'localhost',
37
- # :channel=>'MY.CLIENT.CHL',
38
- # :port=>1414,
39
- # :factory => com.ibm.mq.jms.MQQueueConnectionFactory,
40
- # :transport_type => com.ibm.mq.jms.JMSC::MQJMS_TP_CLIENT_MQ_TCPIP,
41
- # :username => 'mqm'
35
+ # :factory => 'org.apache.activemq.ActiveMQConnectionFactory',
36
+ # :broker_url => 'tcp://localhost:61616',
37
+ # :require_jars => [
38
+ # '~/Applications/apache-activemq-5.5.0/activemq-all-5.5.0.jar',
39
+ # '~/Applications/apache-activemq-5.5.0/lib/optional/slf4j-log4j12-1.5.11.jar',
40
+ # '~/Applications/apache-activemq-5.5.0/lib/optional/log4j-1.2.14.jar',
41
+ # ]
42
42
  # ) do |session|
43
- # session.consumer(:queue_name=>'TEST', :mode=>:input) do |consumer|
43
+ # session.consumer(:queue_name=>'TEST') do |consumer|
44
44
  # if message = consumer.receive_no_wait
45
45
  # puts "Data Received: #{message.data}"
46
46
  # else
@@ -70,13 +70,16 @@ module JMS
70
70
  end
71
71
  end
72
72
 
73
- # Connect to a JMS Broker, create a session and call the code block passing in the session
73
+ # Connect to a JMS Broker, create and start the session,
74
+ # then call the code block passing in the session.
74
75
  # Both the Session and Connection are closed on termination of the block
75
76
  #
76
77
  # Shortcut convenience method to both connect to the broker and create a session
77
78
  # Useful when only a single session is required in the current thread
78
79
  #
79
80
  # Note: It is important that each thread have its own session to support transactions
81
+ # This method will also start the session immediately so that any
82
+ # consumers using this session will start immediately
80
83
  def self.session(params = {}, &proc)
81
84
  self.start(params) do |connection|
82
85
  connection.session(params, &proc)
@@ -101,22 +104,25 @@ module JMS
101
104
  # TODO make this a class method
102
105
  def fetch_dependencies(jar_list)
103
106
  jar_list.each do |jar|
104
- JMS::logger.info "Loading Jar File:#{jar}"
107
+ JMS::logger.debug "Loading Jar File:#{jar}"
105
108
  begin
106
109
  require jar
107
110
  rescue Exception => exc
108
111
  JMS::logger.error "Failed to Load Jar File:#{jar}. #{exc.to_s}"
109
112
  end
110
113
  end if jar_list
111
-
112
- require 'jms/message_listener'
113
- require 'jms/javax_jms_message'
114
- require 'jms/javax_jms_text_message'
115
- require 'jms/javax_jms_map_message'
116
- require 'jms/javax_jms_object_message'
117
- require 'jms/javax_jms_session'
118
- require 'jms/javax_jms_message_consumer'
119
- require 'jms/javax_jms_queue_browser'
114
+
115
+ require 'jms/imports'
116
+ require 'jms/message_listener_impl'
117
+ require 'jms/message'
118
+ require 'jms/text_message'
119
+ require 'jms/map_message'
120
+ require 'jms/bytes_message'
121
+ require 'jms/object_message'
122
+ require 'jms/session'
123
+ require 'jms/message_consumer'
124
+ require 'jms/queue_browser'
125
+ require 'jms/oracle_a_q_connection_factory'
120
126
  end
121
127
 
122
128
  # Create a connection to the JMS provider
@@ -139,101 +145,42 @@ module JMS
139
145
  # :jndi_context => Mandatory if jndi lookup is being used, contains details
140
146
  # on how to connect to JNDI server etc.
141
147
  #
148
+ # :require_jars => An optional array of Jar file names to load for the specified
149
+ # JMS provider. By using this option it is not necessary
150
+ # to put all the JMS Provider specific jar files into the
151
+ # environment variable CLASSPATH prior to starting JRuby
152
+ #
153
+ # :username => Username to connect to JMS provider with
154
+ # :password => Password to use when to connecting to the JMS provider
155
+ # Note: :password is ignored if :username is not supplied
156
+ #
142
157
  # :factory and :jndi_name are mutually exclusive, both cannot be supplied at the
143
158
  # same time. :factory takes precedence over :jndi_name
144
159
  #
145
160
  # JMS Provider specific properties can be set if the JMS Factory itself
146
- # has setters for those properties. Some known examples:
147
- #
148
- # For HornetQ
149
- # :factory => 'org.hornetq.jms.client.HornetQConnectionFactory',
150
- # :discovery_address => '127.0.0.1',
151
- # :discovery_port => '5445',
152
- # :username => 'guest',
153
- # :password => 'guest'
154
- #
155
- # For HornetQ using JNDI lookup technique
156
- # :jndi_name => '/ConnectionFactory',
157
- # :jndi_context => {
158
- # 'java.naming.factory.initial' => 'org.jnp.interfaces.NamingContextFactory',
159
- # 'java.naming.provider.url' => 'jnp://localhost:1099',
160
- # 'java.naming.factory.url.pkgs' => 'org.jboss.naming:org.jnp.interfaces',
161
- # 'java.naming.security.principal' => 'guest',
162
- # 'java.naming.security.credentials' => 'guest'
163
- # }
164
- #
165
- # On Java 6, HornetQ needs the following jar files on your CLASSPATH:
166
- # hornetq-core-client.jar
167
- # netty.jar
168
- # hornetq-jms-client.jar
169
- # jboss-jms-api.jar
170
- # jnp-client.jar
171
- #
172
- # On Java 5, HornetQ needs the following jar files on your CLASSPATH:
173
- # hornetq-core-client-java5.jar
174
- # netty.jar
175
- # hornetq-jms-client-java5.jar
176
- # jboss-jms-api.jar
177
- # jnp-client.jar
178
- #
179
- # For: WebSphere MQ
180
- # :factory => 'com.ibm.mq.jms.MQQueueConnectionFactory',
181
- # :queue_manager=>'REID',
182
- # :host_name=>'localhost',
183
- # :channel=>'MY.CLIENT.CHL',
184
- # :port=>1414,
185
- # :transport_type => com.ibm.mq.jms.JMSC::MQJMS_TP_CLIENT_MQ_TCPIP,
186
- # :username => 'mqm'
187
- #
188
- # For: Active MQ
189
- # :factory => 'org.apache.activemq.ActiveMQConnectionFactory',
190
- # :broker_url => 'tcp://localhost:61616'
191
- #
192
- # ActiveMQ requires the following jar files on your CLASSPATH
193
- #
194
- # For Oracle AQ 9 Server
195
- # :factory => 'JMS::OracleAQConnectionFactory',
196
- # :url => 'jdbc:oracle:thin:@hostname:1521:instanceid',
197
- # :username => 'aquser',
198
- # :password => 'mypassword'
199
- #
200
- # For JBoss, which uses JNDI lookup technique
201
- # :jndi_name => 'ConnectionFactory',
202
- # :jndi_context => {
203
- # 'java.naming.factory.initial' => 'org.jnp.interfaces.NamingContextFactory',
204
- # 'java.naming.provider.url' => 'jnp://localhost:1099'
205
- # 'java.naming.security.principal' => 'user',
206
- # 'java.naming.security.credentials' => 'pwd'
207
- # }
208
- #
209
- # For Apache Qpid / Redhat Messaging, using Factory class directly
210
- # :factory: org.apache.qpid.client.AMQConnectionFactory
211
- # :broker_url: tcp://localhost:5672
212
- #
213
- # For Apache Qpid / Redhat Messaging, via JNDI lookup
214
- # :jndi_name => 'local',
215
- # :jndi_context => {
216
- # 'java.naming.factory.initial' => 'org.apache.qpid.jndi.PropertiesFileInitialContextFactory',
217
- # 'connectionfactory.local' => "amqp://guest:guest@clientid/testpath?brokerlist='tcp://localhost:5672'"
218
- # }
161
+ # has setters for those properties.
162
+ #
163
+ # For some known examples, see: [Example jms.yml](https://github.com/reidmorrison/jruby-jms/blob/master/examples/jms.yml)
219
164
  #
220
165
  def initialize(params = {})
221
166
  # Used by ::on_message
222
167
  @sessions = []
223
168
  @consumers = []
224
169
 
170
+ options = params.dup
171
+
225
172
  # Load Jar files on demand so that they do not need to be in the CLASSPATH
226
173
  # of JRuby lib directory
227
- fetch_dependencies(params[:require_jars])
174
+ fetch_dependencies(options.delete(:require_jars))
228
175
 
229
176
  connection_factory = nil
230
- factory = params[:factory]
177
+ factory = options.delete(:factory)
231
178
  if factory
232
179
  # If factory is a string, then it is the name of a class, not the class itself
233
180
  factory = eval(factory) if factory.respond_to? :to_str
234
181
  connection_factory = factory.new
235
- elsif jndi_name = params[:jndi_name]
236
- raise "Missing mandatory parameter :jndi_context missing in call to Connection::connect" unless jndi_context = params[:jndi_context]
182
+ elsif jndi_name = options[:jndi_name]
183
+ raise "Missing mandatory parameter :jndi_context missing in call to Connection::connect" unless jndi_context = options[:jndi_context]
237
184
  jndi = javax.naming.InitialContext.new(java.util.Hashtable.new(jndi_context))
238
185
  begin
239
186
  connection_factory = jndi.lookup jndi_name
@@ -243,17 +190,25 @@ module JMS
243
190
  else
244
191
  raise "Missing mandatory parameter :factory or :jndi_name missing in call to Connection::connect"
245
192
  end
193
+ options.delete(:jndi_name)
194
+ options.delete(:jndi_context)
246
195
 
247
196
  JMS::logger.debug "Using Factory: #{connection_factory.java_class}" if connection_factory.respond_to? :java_class
248
- params.each_pair do |key, val|
197
+ options.each_pair do |key, val|
198
+ next if [:username, :password].include?(key)
199
+
249
200
  method = key.to_s+'='
250
201
  if connection_factory.respond_to? method
251
202
  connection_factory.send method, val
252
- JMS::logger.debug " #{key} = #{connection_factory.send key}" if connection_factory.respond_to? key.to_sym
203
+ JMS::logger.debug " #{key} = #{connection_factory.send key.to_sym}" if connection_factory.respond_to? key.to_sym
204
+ else
205
+ JMS::logger.warn "#{connection_factory.java_class} does not understand option: :#{key}=#{val}, ignoring :#{key}" if connection_factory.respond_to? :java_class
253
206
  end
254
207
  end
255
- if params[:username]
256
- @jms_connection = connection_factory.create_connection(params[:username], params[:password])
208
+
209
+ # Check for username and password
210
+ if options[:username]
211
+ @jms_connection = connection_factory.create_connection(options[:username], options[:password])
257
212
  else
258
213
  @jms_connection = connection_factory.create_connection
259
214
  end
@@ -266,7 +221,7 @@ module JMS
266
221
  def start
267
222
  @jms_connection.start
268
223
  end
269
-
224
+
270
225
  # Temporarily stop delivery of incoming messages on this connection
271
226
  # Useful during a hot code update or other changes that need to be completed
272
227
  # without any new messages being processed
@@ -285,8 +240,25 @@ module JMS
285
240
  # Determines whether transactions are supported within this session.
286
241
  # I.e. Whether commit or rollback can be called
287
242
  # Default: false
288
- # :options => any of the javax.jms.Session constants
289
- # Default: javax.jms.Session::AUTO_ACKNOWLEDGE
243
+ # Note: :options below are ignored if this value is set to :true
244
+ #
245
+ # :options => any of the JMS::Session constants:
246
+ # Note: :options are ignored if :transacted => true
247
+ # JMS::Session::AUTO_ACKNOWLEDGE
248
+ # With this acknowledgment mode, the session automatically acknowledges
249
+ # a client's receipt of a message either when the session has successfully
250
+ # returned from a call to receive or when the message listener the session has
251
+ # called to process the message successfully returns.
252
+ # JMS::Session::CLIENT_ACKNOWLEDGE
253
+ # With this acknowledgment mode, the client acknowledges a consumed
254
+ # message by calling the message's acknowledge method.
255
+ # JMS::Session::DUPS_OK_ACKNOWLEDGE
256
+ # This acknowledgment mode instructs the session to lazily acknowledge
257
+ # the delivery of messages.
258
+ # JMS::Session::SESSION_TRANSACTED
259
+ # This value is returned from the method getAcknowledgeMode if the
260
+ # session is transacted.
261
+ # Default: JMS::Session::AUTO_ACKNOWLEDGE
290
262
  #
291
263
  def session(params={}, &proc)
292
264
  raise "Missing mandatory Block when calling JMS::Connection#session" unless proc
@@ -310,28 +282,29 @@ module JMS
310
282
  # Determines whether transactions are supported within this session.
311
283
  # I.e. Whether commit or rollback can be called
312
284
  # Default: false
313
- # Note: :options below is ignored if this value is set to :true
314
- # :options => any of the javax.jms.Session constants:
315
- # Note: :options is ignored of :transacted => true
316
- # javax.jms.Session::AUTO_ACKNOWLEDGE
285
+ # Note: :options below are ignored if this value is set to :true
286
+ #
287
+ # :options => any of the JMS::Session constants:
288
+ # Note: :options are ignored if :transacted => true
289
+ # JMS::Session::AUTO_ACKNOWLEDGE
317
290
  # With this acknowledgment mode, the session automatically acknowledges
318
291
  # a client's receipt of a message either when the session has successfully
319
292
  # returned from a call to receive or when the message listener the session has
320
293
  # called to process the message successfully returns.
321
- # javax.jms.Session::CLIENT_ACKNOWLEDGE
294
+ # JMS::Session::CLIENT_ACKNOWLEDGE
322
295
  # With this acknowledgment mode, the client acknowledges a consumed
323
296
  # message by calling the message's acknowledge method.
324
- # javax.jms.Session::DUPS_OK_ACKNOWLEDGE
297
+ # JMS::Session::DUPS_OK_ACKNOWLEDGE
325
298
  # This acknowledgment mode instructs the session to lazily acknowledge
326
299
  # the delivery of messages.
327
- # javax.jms.Session::SESSION_TRANSACTED
300
+ # JMS::Session::SESSION_TRANSACTED
328
301
  # This value is returned from the method getAcknowledgeMode if the
329
302
  # session is transacted.
330
- # Default: javax.jms.Session::AUTO_ACKNOWLEDGE
303
+ # Default: JMS::Session::AUTO_ACKNOWLEDGE
331
304
  #
332
305
  def create_session(params={})
333
306
  transacted = params[:transacted] || false
334
- options = params[:options] || javax.jms.Session::AUTO_ACKNOWLEDGE
307
+ options = params[:options] || JMS::Session::AUTO_ACKNOWLEDGE
335
308
  @jms_connection.create_session(transacted, options)
336
309
  end
337
310
 
@@ -346,65 +319,62 @@ module JMS
346
319
 
347
320
  @jms_connection.close if @jms_connection
348
321
  end
349
-
322
+
350
323
  # Gets the client identifier for this connection.
351
324
  def client_id
352
325
  @jms_connection.getClientID
353
326
  end
354
-
327
+
355
328
  # Sets the client identifier for this connection.
356
329
  def client_id=(client_id)
357
330
  @jms_connection.setClientID(client_id)
358
331
  end
359
-
332
+
360
333
  # Returns the ExceptionListener object for this connection
361
- # Returned class implements interface javax.jms.ExceptionListener
334
+ # Returned class implements interface JMS::ExceptionListener
362
335
  def exception_listener
363
336
  @jms_connection.getExceptionListener
364
337
  end
365
-
338
+
366
339
  # Sets an exception listener for this connection
367
340
  # See ::on_exception to set a Ruby Listener
368
341
  # Returns: nil
369
342
  def exception_listener=(listener)
370
- setExceptionListener(listener)
343
+ @jms_connection.setExceptionListener(listener)
371
344
  end
372
-
345
+
373
346
  # Whenever an exception occurs the supplied block is called
374
347
  # This is important when Connection::on_message has been used, since
375
348
  # failures to the connection would be lost otherwise
376
- #
377
- # For details on the supplied parameter when the block is called,
349
+ #
350
+ # For details on the supplied parameter when the block is called,
378
351
  # see: http://download.oracle.com/javaee/6/api/javax/jms/JMSException.html
379
- #
352
+ #
380
353
  # Example:
381
- # connection.on_message do |jms_exception|
354
+ # connection.on_exception do |jms_exception|
382
355
  # puts "JMS Exception has occurred: #{jms_exception}"
383
356
  # end
384
357
  #
385
358
  # Returns: nil
386
359
  def on_exception(&block)
387
- setExceptionListener(block)
360
+ @jms_connection.setExceptionListener(block)
388
361
  end
389
-
362
+
390
363
  # Gets the metadata for this connection
391
364
  # see: http://download.oracle.com/javaee/6/api/javax/jms/ConnectionMetaData.html
392
365
  def meta_data
393
366
  @jms_connection.getMetaData
394
367
  end
395
-
368
+
396
369
  # Return a string describing the JMS provider and version
397
370
  def to_s
398
371
  md = @jms_connection.getMetaData
399
372
  "JMS::Connection provider: #{md.getJMSProviderName} v#{md.getProviderVersion}, JMS v#{md.getJMSVersion}"
400
373
  end
401
374
 
402
- # TODO: Return a pretty print version of the current JMS Connection
403
- # def to_s
404
- # end
405
-
406
375
  # Receive messages in a separate thread when they arrive
407
- # Allows messages to be recieved in a separate thread. I.e. Asynchronously
376
+ #
377
+ # Allows messages to be received Asynchronously in a separate thread.
408
378
  # This method will return to the caller before messages are processed.
409
379
  # It is then the callers responsibility to keep the program active so that messages
410
380
  # can then be processed.
@@ -414,19 +384,36 @@ module JMS
414
384
  # Determines whether transactions are supported within this session.
415
385
  # I.e. Whether commit or rollback can be called
416
386
  # Default: false
417
- # :options => any of the javax.jms.Session constants
418
- # Default: javax.jms.Session::AUTO_ACKNOWLEDGE
387
+ # Note: :options below are ignored if this value is set to :true
388
+ #
389
+ # :options => any of the JMS::Session constants:
390
+ # Note: :options are ignored if :transacted => true
391
+ # JMS::Session::AUTO_ACKNOWLEDGE
392
+ # With this acknowledgment mode, the session automatically acknowledges
393
+ # a client's receipt of a message either when the session has successfully
394
+ # returned from a call to receive or when the message listener the session has
395
+ # called to process the message successfully returns.
396
+ # JMS::Session::CLIENT_ACKNOWLEDGE
397
+ # With this acknowledgment mode, the client acknowledges a consumed
398
+ # message by calling the message's acknowledge method.
399
+ # JMS::Session::DUPS_OK_ACKNOWLEDGE
400
+ # This acknowledgment mode instructs the session to lazily acknowledge
401
+ # the delivery of messages.
402
+ # JMS::Session::SESSION_TRANSACTED
403
+ # This value is returned from the method getAcknowledgeMode if the
404
+ # session is transacted.
405
+ # Default: JMS::Session::AUTO_ACKNOWLEDGE
419
406
  #
420
407
  # :session_count : Number of sessions to create, each with their own consumer which
421
- # in turn will call the supplied Proc.
422
- # Note: The supplied Proc must be thread safe since it will be called
408
+ # in turn will call the supplied code block.
409
+ # Note: The supplied block must be thread safe since it will be called
423
410
  # by several threads at the same time.
424
411
  # I.e. Don't change instance variables etc. without the
425
412
  # necessary semaphores etc.
426
413
  # Default: 1
427
414
  #
428
415
  # Consumer Parameters:
429
- # :queue_name => String: Name of the Queue to return
416
+ # :queue_name => String: Name of the Queue to return
430
417
  # Symbol: :temporary => Create temporary queue
431
418
  # Mandatory unless :topic_name is supplied
432
419
  # Or,
@@ -438,8 +425,9 @@ module JMS
438
425
  #
439
426
  # :selector => Filter which messages should be returned from the queue
440
427
  # Default: All messages
428
+ #
441
429
  # :no_local => Determine whether messages published by its own connection
442
- # should be delivered to it
430
+ # should be delivered to the supplied block
443
431
  # Default: false
444
432
  #
445
433
  # :statistics Capture statistics on how many messages have been read
@@ -451,18 +439,15 @@ module JMS
451
439
  # Also, the start time and message count is not reset until MessageConsumer::each
452
440
  # is called again with :statistics => true
453
441
  #
454
- # The statistics gathered are returned when :statistics => true and :async => false
455
- #
456
- # Usage: For transacted sessions (the default) the Proc supplied must return
457
- # either true or false:
442
+ # Usage: For transacted sessions the block supplied must return either true or false:
458
443
  # true => The session is committed
459
444
  # false => The session is rolled back
460
445
  # Any Exception => The session is rolled back
461
446
  #
462
- # Note: Also supply connection::on_exception so that connection failures can be handled
447
+ # Note: Separately invoke Connection#on_exception so that connection failures can be handled
448
+ # since on_message will Not be called if the connection is lost
463
449
  #
464
- #
465
- def on_message(params, &proc)
450
+ def on_message(params, &block)
466
451
  raise "JMS::Connection must be connected prior to calling JMS::Connection::on_message" unless @sessions && @consumers
467
452
 
468
453
  consumer_count = params[:session_count] || 1
@@ -472,40 +457,63 @@ module JMS
472
457
  if session.transacted?
473
458
  consumer.on_message(params) do |message|
474
459
  begin
475
- proc.call(message) ? session.commit : session.rollback
460
+ block.call(message) ? session.commit : session.rollback
476
461
  rescue => exc
477
462
  session.rollback
478
463
  throw exc
479
464
  end
480
465
  end
481
466
  else
482
- consumer.on_message(params, &proc)
467
+ consumer.on_message(params, &block)
483
468
  end
484
469
  @consumers << consumer
485
470
  @sessions << session
486
471
  end
487
472
  end
488
473
 
474
+ # Return the statistics for every active Connection#on_message consumer
475
+ # in an Array
476
+ #
477
+ # For details on the contents of each element in the array, see: Consumer#on_message_statistics
489
478
  def on_message_statistics
490
- @consumers.collect{|consumer| consumer.on_message_statistics}
479
+ @consumers.collect { |consumer| consumer.on_message_statistics }
491
480
  end
492
481
 
493
- end
494
-
495
- # Wrapper to support Oracle AQ
496
- class OracleAQConnectionFactory
497
- attr_accessor :username, :url
498
- attr_writer :password
499
-
500
- # Creates a connection per standard JMS 1.1 techniques from the Oracle AQ JMS Interface
501
- def create_connection
502
- cf = oracle.jms.AQjmsFactory.getConnectionFactory(@url, java.util.Properties.new)
503
- if username
504
- cf.createConnection(@username, @password)
505
- else
506
- cf.createConnection()
507
- end
482
+ # Since a Session can only be used by one thread at a time, we could create
483
+ # a Session for every thread. That could result in excessive unused Sessions.
484
+ # An alternative is to create a pool of sessions that can be shared by
485
+ # multiple threads.
486
+ #
487
+ # Each thread can request a session and then return it once it is no longer
488
+ # needed by that thread. The only way to get a session is to pass a block so that
489
+ # the Session is automatically returned to the pool upon completion of the block.
490
+ #
491
+ # Parameters:
492
+ # see regular session parameters from: JMS::Connection#initialize
493
+ #
494
+ # Additional parameters for controlling the session pool itself
495
+ # :pool_name Name of the pool as it shows up in the logger.
496
+ # Default: 'JMS::SessionPool'
497
+ # :pool_size Maximum Pool Size. Default: 10
498
+ # The pool only grows as needed and will never exceed
499
+ # :pool_size
500
+ # :pool_warn_timeout Number of seconds to wait before logging a warning when a
501
+ # session in the pool is not available. Measured in seconds
502
+ # Default: 5.0
503
+ # :pool_logger Supply a logger that responds to #debug, #info, #warn and #debug?
504
+ # For example: Rails.logger
505
+ # Default: None
506
+ # Example:
507
+ # session_pool = connection.create_session_pool(config)
508
+ #
509
+ # session_pool.session do |session|
510
+ # producer.send(session.message("Hello World"))
511
+ # end
512
+ def create_session_pool(params={})
513
+ require 'jms/session_pool' unless defined? JMS::SessionPool
514
+ JMS::SessionPool.new(self, params)
508
515
  end
516
+
509
517
  end
510
518
 
511
519
  end