jruby-hornetq 0.2.3.alpha → 0.2.5.alpha

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