jruby-jms 0.10.2 → 0.11.0

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