jruby-hornetq 0.2.3.alpha → 0.2.5.alpha

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.
@@ -0,0 +1,63 @@
1
+ module HornetQ::Client
2
+
3
+ # For internal use only
4
+ class MessageHandler
5
+ include Java::org.hornetq.api.core.client::MessageHandler
6
+
7
+ # Parameters:
8
+ # :statistics Capture statistics on how many messages have been read
9
+ # true : Capture statistics on the number of messages received
10
+ # and the time it took to process them.
11
+ # The timer starts when the listener instance is created and finishes when either the last message was received,
12
+ # or when Consumer::on_message_statistics is called. In this case on_message_statistics::statistics
13
+ # can be called several times during processing without affecting the end time.
14
+ # The start time and message count is never reset for this instance
15
+ def initialize(parms={}, &proc)
16
+ @proc = proc
17
+
18
+ if parms[:statistics]
19
+ @message_count = 0
20
+ @start_time = Time.now
21
+ end
22
+ end
23
+
24
+ # Method called for every message received on the queue
25
+ # Per the specification, this method will be called sequentially for each message on the queue.
26
+ # This method will not be called again until its prior invocation has completed.
27
+ # Must be onMessage() since on_message() does not work for interface methods that must be implemented
28
+ def onMessage(message)
29
+ begin
30
+ if @message_count
31
+ @message_count += 1
32
+ @last_time = Time.now
33
+ end
34
+ @proc.call message
35
+ rescue SyntaxError, NameError => boom
36
+ HornetQ::logger.error "Unhandled Exception processing Message. Doesn't compile: " + boom
37
+ HornetQ::logger.error "Ignoring poison message:\n#{message.inspect}"
38
+ HornetQ::logger.error boom.backtrace.join("\n")
39
+ rescue StandardError => bang
40
+ HornetQ::logger.error "Unhandled Exception processing Message. Doesn't compile: " + bang
41
+ HornetQ::logger.error "Ignoring poison message:\n#{message.inspect}"
42
+ HornetQ::logger.error boom.backtrace.join("\n")
43
+ rescue => exc
44
+ HornetQ::logger.error "Unhandled Exception processing Message. Exception occurred:\n#{exc}"
45
+ HornetQ::logger.error "Ignoring poison message:\n#{message.inspect}"
46
+ HornetQ::logger.error exc.backtrace.join("\n")
47
+ end
48
+ end
49
+
50
+ # Return Statistics gathered for this listener
51
+ # Note: These statistics are only useful if the queue is pre-loaded with messages
52
+ # since the timer start immediately and stops on the last message received
53
+ def statistics
54
+ raise "First call Consumer::on_message with :statistics=>true before calling MessageConsumer::statistics()" unless @message_count
55
+ duration =(@last_time || Time.now) - @start_time
56
+ {
57
+ :messages => @message_count,
58
+ :duration => duration,
59
+ :messages_per_second => (@message_count/duration).to_i
60
+ }
61
+ end
62
+ end
63
+ end
@@ -1,16 +1,171 @@
1
1
  # Add methods to Session Interface
2
+ # For more information on methods, see:
3
+ # http://hornetq.sourceforge.net/docs/hornetq-2.1.0.Final/api/index.html?org/hornetq/api/core/client/ClientSession.html
2
4
  module Java::org.hornetq.api.core.client::ClientSession
3
5
 
6
+ # Document Methods from Java Docs:
7
+ # create_queue(address, queue_name, durable?)
8
+
9
+ # Creates a ClientConsumer to consume or browse messages matching the filter
10
+ # from the queue with the given name, calls the supplied block, then close the
11
+ # consumer
12
+ #
13
+ # If the parameter is a String, then it must be the queue name to consume
14
+ # messages from. Otherwise, the parameters can be supplied in a Hash
15
+ #
16
+ # The parameters for creating the consumer are as follows:
17
+ # :queue_name => The name of the queue to consume messages from. Mandatory
18
+ # :filter => Only consume messages matching the filter: Default: nil
19
+ # :browse_only => Whether to just browse the queue or consume messages
20
+ # true | false. Default: false
21
+ # :window_size => The consumer window size.
22
+ # :max_rate => The maximum rate to consume messages.
23
+ #
24
+ # Note: If either :window_size or :max_rate is supplied, then BOTH are required
25
+ #
26
+ # Returns the result from the block
27
+ #
28
+ # Example
29
+ # session.consumer('my_queue') do |consumer|
30
+ # msg = consumer.receive_immediate
31
+ # p msg
32
+ # msg.acknowledge
33
+ # end
34
+ #
35
+ # Example
36
+ # # Just browse the messages without consuming them
37
+ # session.consumer(:queue_name => 'my_queue', :browse_only => true) do |consumer|
38
+ # msg = consumer.receive_immediate
39
+ # p msg
40
+ # msg.acknowledge
41
+ # end
42
+ def consumer(params={}, &block)
43
+ consumer = nil
44
+ begin
45
+ consumer = create_consumer_from_params(params)
46
+ block.call(consumer)
47
+ ensure
48
+ consumer.close if consumer
49
+ end
50
+ end
51
+
52
+ # Deprecated
53
+ def create_consumer_from_params(params={})
54
+ queue_name = params.kind_of?(Hash) ? params[:queue_name] : params
55
+ raise("Missing mandatory parameter :queue_name") unless queue_name
56
+
57
+ if params[:max_rate] || params[:window_size]
58
+ self.create_consumer(
59
+ queue_name,
60
+ params[:filter],
61
+ params[:window_size],
62
+ params[:max_rate],
63
+ params[:browse_only].nil? ? false : params[:browse_only])
64
+ else
65
+ self.create_consumer(
66
+ queue_name,
67
+ params[:filter],
68
+ params[:browse_only].nil? ? false : params[:browse_only])
69
+ end
70
+ end
71
+
72
+ # Creates a ClientProducer to send messages, calls the supplied block,
73
+ # then close the consumer
74
+ #
75
+ # If the parameter is a String, then it must be the address to send messages to
76
+ # Otherwise, the parameters can be supplied in a Hash
77
+ #
78
+ # The parameters for creating the consumer are as follows:
79
+ # :address => The address to which to send messages. If not supplied here,
80
+ # then the destination address must be supplied with every message
81
+ # :rate => The producer rate
82
+ #
83
+ # Returns the result from the block
84
+ #
85
+ # Example
86
+ # session.producer('MyAddress') do |producer|
87
+ # msg = session.create_message
88
+ # msg.type = :text
89
+ # producer.send(msg)
90
+ # end
91
+ #
92
+ # Example
93
+ # # Send to a different address with each message
94
+ # session.producer do |producer|
95
+ # msg = session.create_message
96
+ # msg.type = :text
97
+ # producer.send('Another address', msg)
98
+ # end
99
+ def producer(params=nil, &block)
100
+ address = nil
101
+ rate = nil
102
+ if params.kind_of?(Hash)
103
+ address = params[:address]
104
+ rate = params[:rate]
105
+ else
106
+ address = params
107
+ end
108
+
109
+ producer = nil
110
+ begin
111
+ producer = if rate
112
+ self.create_producer(address, rate)
113
+ elsif address
114
+ self.create_producer(address)
115
+ else
116
+ self.create_producer
117
+ end
118
+ block.call(producer)
119
+ ensure
120
+ producer.close if producer
121
+ end
122
+ end
123
+
4
124
  # To be consistent create Requestor from Session
5
125
  def create_requestor(request_address)
6
126
  #Java::org.hornetq.api.core.client::ClientRequestor.new(self, request_address);
7
- HornetQ::Client::Requestor.new(self, request_address)
127
+ HornetQ::Client::RequestorPattern.new(self, request_address)
128
+ end
129
+
130
+ # Creates a RequestorPattern to send a request and to synchronously wait for
131
+ # the reply, call the supplied block, then close the requestor
132
+ # Returns the result from the block
133
+ def requestor(request_address)
134
+ requestor = nil
135
+ begin
136
+ requestor = self.create_requestor(request_address)
137
+ block.call(requestor)
138
+ ensure
139
+ requestor.close if requestor
140
+ end
8
141
  end
9
142
 
10
143
  # Create a server handler for receiving requests and responding with
11
144
  # replies to the supplied address
12
145
  def create_server(input_queue, timeout=0)
13
- HornetQ::Client::Server.new(self, input_queue, timeout)
146
+ HornetQ::Client::ServerPattern.new(self, input_queue, timeout)
147
+ end
148
+
149
+ # Creates a ServerPattern to send messages to consume messages and send
150
+ # replies, call the supplied block, then close the server
151
+ # Returns the result from the block
152
+ def server(input_queue, timeout=0, &block)
153
+ server = nil
154
+ begin
155
+ server = self.create_server(input_queue, timeout)
156
+ block.call(server)
157
+ ensure
158
+ server.close if server
159
+ end
14
160
  end
161
+
162
+ def create_queue_ignore_exists(address, queue, durable)
163
+ begin
164
+ create_queue(address, queue, durable)
165
+ rescue Java::org.hornetq.api.core.HornetQException => e
166
+ raise unless e.cause.code == Java::org.hornetq.api.core.HornetQException::QUEUE_EXISTS
167
+ end
168
+ end
169
+
15
170
  end
16
171
 
@@ -0,0 +1,94 @@
1
+ # Consumer Class
2
+
3
+ # For the HornetQ Java documentation for this class see:
4
+ # http://hornetq.sourceforge.net/docs/hornetq-2.1.0.Final/api/index.html?org/hornetq/api/core/client/ClientConsumer.html
5
+
6
+ class Java::org.hornetq.core.client.impl::ClientConsumerImpl
7
+
8
+ # For each message available to be consumed call the block supplied
9
+ #
10
+ # Returns the statistics gathered when :statistics => true, otherwise nil
11
+ #
12
+ # Parameters:
13
+ # :timeout How to timeout waiting for messages
14
+ # -1 : Wait forever
15
+ # 0 : Return immediately if no message is available (default)
16
+ # x : Wait for x milli-seconds for a message to be received from the server
17
+ # Note: Messages may still be on the queue, but the server has not supplied any messages
18
+ # in the time interval specified
19
+ # Default: 0
20
+ #
21
+ # :statistics Capture statistics on how many messages have been read
22
+ # true : This method will capture statistics on the number of messages received
23
+ # and the time it took to process them.
24
+ # Statistics are cumulative between calls to ::each and will only be
25
+ # reset when ::each is called again with :statistics => true
26
+ def each(parms={}, &proc)
27
+ raise "Consumer::each requires a code block to be executed for each message received" unless proc
28
+
29
+ message_count = nil
30
+ start_time = nil
31
+ timeout = (parms[:timeout] || 0).to_i
32
+
33
+ if parms[:statistics]
34
+ message_count = 0
35
+ start_time = Time.now
36
+ end
37
+
38
+ # Receive messages according to timeout
39
+ while message = self.receive_with_timeout(timeout) do
40
+ proc.call(message)
41
+ message_count += 1 if message_count
42
+ end
43
+
44
+ unless message_count.nil?
45
+ duration = Time.now - start_time
46
+ {:messages => message_count,
47
+ :duration => duration,
48
+ :messages_per_second => (message_count/duration).to_i}
49
+ end
50
+ end
51
+
52
+ # Receive messages in a separate thread when they arrive
53
+ # Allows messages to be received in a separate thread. I.e. Asynchronously
54
+ # This method will return to the caller before messages are processed.
55
+ # It is then the callers responsibility to keep the program active so that messages
56
+ # can then be processed.
57
+ #
58
+ # Parameters:
59
+ # :statistics Capture statistics on how many messages have been read
60
+ # true : This method will capture statistics on the number of messages received
61
+ # and the time it took to process them.
62
+ # The timer starts when each() is called and finishes when either the last message was received,
63
+ # or when Destination::statistics is called. In this case MessageConsumer::statistics
64
+ # can be called several times during processing without affecting the end time.
65
+ # Also, the start time and message count is not reset until MessageConsumer::each
66
+ # is called again with :statistics => true
67
+ #
68
+ # The statistics gathered are returned when :statistics => true and :async => false
69
+ #
70
+ def on_message(parms={}, &proc)
71
+ raise "Consumer::on_message requires a code block to be executed for each message received" unless proc
72
+
73
+ @listener = HornetQ::Client::MessageHandler.new(parms, &proc)
74
+ self.setMessageListener @listener
75
+ end
76
+
77
+ # Return the current statistics for a running ::on_message
78
+ def on_message_statistics
79
+ stats = @listener.statistics if @listener
80
+ raise "First call Consumer::on_message with :statistics=>true before calling Consumer::statistics()" unless stats
81
+ stats
82
+ end
83
+
84
+ private
85
+ def receive_with_timeout(timeout)
86
+ if timeout == -1
87
+ self.receive
88
+ elsif timeout == 0
89
+ self.receive_immediate
90
+ else
91
+ self.receive(timeout)
92
+ end
93
+ end
94
+ end
@@ -32,15 +32,8 @@ class Java::OrgHornetqCoreClientImpl::ClientMessageImpl
32
32
  put_string_property(Java::OrgHornetqCoreClientImpl::ClientMessageImpl::REPLYTO_HEADER_NAME, val)
33
33
  end
34
34
 
35
- # Return the size of the encoded message
36
- # attr_reader :encode_size
37
-
38
35
  # Return the body for this message
39
36
  # TODO: Do remaining message Types
40
- #
41
- # WARNING: This method can only be called ONCE!
42
- # WARNING: Do not call after setting the body otherwise the send will have
43
- # an empty body
44
37
  def body
45
38
  # Allow this buffer to be read multiple times
46
39
  body_buffer.reset_reader_index
@@ -1,7 +1,8 @@
1
1
  module HornetQ::Client
2
2
 
3
- # Send a request to a server and wait for a reply
4
- class Requestor
3
+ # Implements the Requestor Pattern
4
+ # Send a request to a server and wait for a reply
5
+ class RequestorPattern
5
6
  def initialize(session, request_address)
6
7
  @session = session
7
8
  @producer = session.create_producer(request_address)
@@ -1,8 +1,8 @@
1
1
  module HornetQ::Client
2
- # Create a Server for receiving requests and replying
3
- # to arbitrary queues
2
+ # Create a Server following the ServerPattern for receiving requests and
3
+ # replying to arbitrary queues
4
4
  # Create an instance of this class per thread
5
- class Server
5
+ class ServerPattern
6
6
  def initialize(session, request_queue, timeout)
7
7
  @session = session
8
8
  @consumer = session.create_consumer(request_queue)
@@ -49,7 +49,6 @@ module HornetQ::Client
49
49
  s = factory.create_session(session_params)
50
50
  # Start the session since it will be used immediately upon creation
51
51
  s.start
52
- puts "Creating Session"
53
52
  s
54
53
  end
55
54
 
@@ -0,0 +1,46 @@
1
+ module HornetQ
2
+ # Internal use only class for delegating HornetQ logging into the Rails or Ruby
3
+ # loggers
4
+ #
5
+ private
6
+
7
+ # HornetQ requires a factory from which it can create a logger per thread and/or class
8
+ class LogDelegateFactory
9
+ include
10
+
11
+ def createDelegate(klass)
12
+ LogDelegate.new(klass.name)
13
+ end
14
+ end
15
+
16
+ # Delegate HornetQ log calls to Rails, Ruby or custom logger
17
+ class LogDelegate
18
+ include Java::org.hornetq.spi.core.logging::LogDelegate
19
+
20
+ # TODO: Carry class_name over into logging entries depending on implementation
21
+ def initialize(class_name)
22
+ @class_name = class_name
23
+ end
24
+
25
+ # DRY, generate a method for each required log level
26
+ ['debug', 'error', 'fatal', 'info', 'trace', 'warn'].each do |level|
27
+ eval <<-LOG_LEVEL_METHOD
28
+ def #{level}(message)
29
+ @logger.#{level}("[\#{@class_name}] \#{message}") if is#{level.capitalize}Enabled
30
+ end
31
+
32
+ def #{level}(message, t)
33
+ if is#{level.capitalize}Enabled
34
+ @logger.#{level}("[\#{@class_name}] \#{message}. \#{t.to_string}")
35
+ @logger.#{level}(t.stack_trace.to_string)
36
+ end
37
+ end
38
+
39
+ def is#{level.capitalize}Enabled
40
+ @logger.#{level}?
41
+ end
42
+ LOG_LEVEL_METHOD
43
+ end
44
+
45
+ end
46
+ end
@@ -0,0 +1,32 @@
1
+ # Add HornetQ logging capabilities
2
+ module HornetQ
3
+ # Returns the logger being used by both HornetQ and jruby-hornetq
4
+ def self.logger
5
+ @logger ||= (rails_logger || default_logger)
6
+ end
7
+
8
+ # Replace the logger for both HornetQ and jruby-hornetq
9
+ # TODO Directly support Log4J as logger since HornetQ has direct support for Log4J
10
+ def self.logger=(logger)
11
+ @logger = logger
12
+ # Also replace the HornetQ logger
13
+ Java::org.hornetq.core.logging::Logger.setDelegateFactory(HornetQ::LogDelegateFactory.new)
14
+ # TODO org.hornetq.core.logging.Logger.setDelegateFactory(org.hornetq.integration.logging.Log4jLogDelegateFactory.new)
15
+ end
16
+
17
+ private
18
+ def self.rails_logger
19
+ (defined?(Rails) && Rails.respond_to?(:logger) && Rails.logger) ||
20
+ (defined?(RAILS_DEFAULT_LOGGER) && RAILS_DEFAULT_LOGGER.respond_to?(:debug) && RAILS_DEFAULT_LOGGER)
21
+ end
22
+
23
+ # By default we use the HornetQ Logger
24
+ def self.default_logger
25
+ Java::org.hornetq.core.logging::Logger.getLogger(org.hornetq.api.core.client::HornetQClient)
26
+ # require 'logger'
27
+ # l = Logger.new(STDOUT)
28
+ # l.level = Logger::INFO
29
+ # l
30
+ end
31
+
32
+ end