modern_times 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +24 -12
 - data/Rakefile +2 -2
 - data/VERSION +1 -1
 - data/examples/README +4 -0
 - data/examples/jms.yml +9 -0
 - data/examples/requestor/README +4 -2
 - data/examples/requestor/manager.rb +3 -2
 - data/examples/requestor/request.rb +5 -4
 - data/examples/requestor/reverse_echo_worker.rb +3 -2
 - data/examples/simple/README +7 -4
 - data/examples/simple/bar_worker.rb +4 -1
 - data/examples/simple/baz_worker.rb +4 -3
 - data/examples/simple/manager.rb +3 -2
 - data/examples/simple/publish.rb +6 -5
 - data/lib/modern_times.rb +20 -2
 - data/lib/modern_times/base/supervisor.rb +14 -21
 - data/lib/modern_times/base/supervisor_mbean.rb +4 -6
 - data/lib/modern_times/base/worker.rb +17 -26
 - data/lib/modern_times/jms.rb +23 -0
 - data/lib/modern_times/{hornetq/client.rb → jms/connection.rb} +19 -12
 - data/lib/modern_times/jms/publisher.rb +91 -0
 - data/lib/modern_times/jms/supervisor.rb +19 -0
 - data/lib/modern_times/jms/supervisor_mbean.rb +11 -0
 - data/lib/modern_times/jms/worker.rb +166 -0
 - data/lib/modern_times/jms_requestor.rb +10 -0
 - data/lib/modern_times/jms_requestor/request_handle.rb +33 -0
 - data/lib/modern_times/jms_requestor/requestor.rb +45 -0
 - data/lib/modern_times/jms_requestor/supervisor.rb +45 -0
 - data/lib/modern_times/jms_requestor/supervisor_mbean.rb +21 -0
 - data/lib/modern_times/jms_requestor/worker.rb +78 -0
 - data/lib/modern_times/manager.rb +14 -9
 - data/lib/modern_times/manager_mbean.rb +14 -7
 - data/lib/modern_times/marshal_strategy.rb +47 -0
 - data/lib/modern_times/marshal_strategy/bson.rb +31 -0
 - data/lib/modern_times/marshal_strategy/json.rb +30 -0
 - data/lib/modern_times/marshal_strategy/ruby.rb +20 -0
 - data/lib/modern_times/marshal_strategy/string.rb +19 -0
 - data/lib/modern_times/railsable.rb +17 -74
 - data/test/base_test.rb +248 -0
 - data/test/jms.yml +8 -0
 - data/test/jms_requestor_test.rb +263 -0
 - data/test/jms_test.rb +296 -0
 - data/test/marshal_strategy_test.rb +39 -0
 - metadata +49 -46
 - data/examples/requestor/hornetq.yml +0 -14
 - data/examples/simple/hornetq.yml +0 -14
 - data/lib/modern_times/hornetq.rb +0 -11
 - data/lib/modern_times/hornetq/marshal_strategy.rb +0 -3
 - data/lib/modern_times/hornetq/marshal_strategy/json.rb +0 -17
 - data/lib/modern_times/hornetq/marshal_strategy/ruby.rb +0 -17
 - data/lib/modern_times/hornetq/marshal_strategy/string.rb +0 -17
 - data/lib/modern_times/hornetq/publisher.rb +0 -65
 - data/lib/modern_times/hornetq/supervisor.rb +0 -22
 - data/lib/modern_times/hornetq/supervisor_mbean.rb +0 -12
 - data/lib/modern_times/hornetq/worker.rb +0 -127
 - data/lib/modern_times/hornetq_requestor.rb +0 -9
 - data/lib/modern_times/hornetq_requestor/request_handle.rb +0 -49
 - data/lib/modern_times/hornetq_requestor/requestor.rb +0 -48
 - data/lib/modern_times/hornetq_requestor/worker.rb +0 -29
 - data/lib/modern_times/thread.rb +0 -16
 - data/test/base/worker_test.rb +0 -38
 - data/test/messaging/worker_manager_test.rb +0 -58
 - data/test/messaging/worker_test.rb +0 -58
 - data/test/worker_manager_test.rb +0 -48
 
| 
         @@ -0,0 +1,23 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'modern_times/jms/connection'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'modern_times/jms/publisher'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'modern_times/jms/supervisor_mbean'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'modern_times/jms/supervisor'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'modern_times/jms/worker'
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            module ModernTimes
         
     | 
| 
      
 8 
     | 
    
         
            +
              module JMS
         
     | 
| 
      
 9 
     | 
    
         
            +
                def self.same_destination?(options1, options2)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  if options1[:queue_name]
         
     | 
| 
      
 11 
     | 
    
         
            +
                    return options1[:queue_name]  == options2[:queue_name]
         
     | 
| 
      
 12 
     | 
    
         
            +
                  elsif options1[:topic_name]
         
     | 
| 
      
 13 
     | 
    
         
            +
                    return options1[:topic_name]  == options2[:topic_name]
         
     | 
| 
      
 14 
     | 
    
         
            +
                  elsif options1[:virtual_topic_name]
         
     | 
| 
      
 15 
     | 
    
         
            +
                    return options1[:virtual_topic_name]  == options2[:virtual_topic_name]
         
     | 
| 
      
 16 
     | 
    
         
            +
                  elsif options1[:destination]
         
     | 
| 
      
 17 
     | 
    
         
            +
                    return options1[:destination] == options2[:destination]
         
     | 
| 
      
 18 
     | 
    
         
            +
                  else
         
     | 
| 
      
 19 
     | 
    
         
            +
                    return false
         
     | 
| 
      
 20 
     | 
    
         
            +
                  end
         
     | 
| 
      
 21 
     | 
    
         
            +
                end
         
     | 
| 
      
 22 
     | 
    
         
            +
              end
         
     | 
| 
      
 23 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -1,16 +1,18 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            require ' 
     | 
| 
      
 1 
     | 
    
         
            +
            require 'jms'
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            # Handle Messaging and Queuing
         
     | 
| 
       4 
4 
     | 
    
         
             
            module ModernTimes
         
     | 
| 
       5 
     | 
    
         
            -
              module  
     | 
| 
       6 
     | 
    
         
            -
                module  
     | 
| 
      
 5 
     | 
    
         
            +
              module JMS
         
     | 
| 
      
 6 
     | 
    
         
            +
                module Connection
         
     | 
| 
       7 
7 
     | 
    
         
             
                  # Singleton-ize
         
     | 
| 
       8 
8 
     | 
    
         
             
                  extend self
         
     | 
| 
       9 
9 
     | 
    
         | 
| 
       10 
10 
     | 
    
         
             
                  # Initialize the messaging system and connection pool for this VM
         
     | 
| 
       11 
11 
     | 
    
         
             
                  def init(config)
         
     | 
| 
       12 
12 
     | 
    
         
             
                    @config = config
         
     | 
| 
       13 
     | 
    
         
            -
                    @ 
     | 
| 
      
 13 
     | 
    
         
            +
                    @inited = true
         
     | 
| 
      
 14 
     | 
    
         
            +
                    @connection = ::JMS::Connection.new(config)
         
     | 
| 
      
 15 
     | 
    
         
            +
                    @connection.start
         
     | 
| 
       14 
16 
     | 
    
         
             
                    # Let's not create a session_pool unless we're going to use it
         
     | 
| 
       15 
17 
     | 
    
         
             
                    @session_pool_mutex = Mutex.new
         
     | 
| 
       16 
18 
     | 
    
         | 
| 
         @@ -19,13 +21,13 @@ module ModernTimes 
     | 
|
| 
       19 
21 
     | 
    
         
             
                    end
         
     | 
| 
       20 
22 
     | 
    
         
             
                  end
         
     | 
| 
       21 
23 
     | 
    
         | 
| 
       22 
     | 
    
         
            -
                  def  
     | 
| 
       23 
     | 
    
         
            -
                    @ 
     | 
| 
      
 24 
     | 
    
         
            +
                  def inited?
         
     | 
| 
      
 25 
     | 
    
         
            +
                    @inited
         
     | 
| 
       24 
26 
     | 
    
         
             
                  end
         
     | 
| 
       25 
27 
     | 
    
         | 
| 
       26 
28 
     | 
    
         
             
                  # Create a session targeted for a consumer (producers should use the session_pool)
         
     | 
| 
       27 
29 
     | 
    
         
             
                  def create_consumer_session
         
     | 
| 
       28 
     | 
    
         
            -
                     
     | 
| 
      
 30 
     | 
    
         
            +
                    connection.create_session(@config || {})
         
     | 
| 
       29 
31 
     | 
    
         
             
                  end
         
     | 
| 
       30 
32 
     | 
    
         | 
| 
       31 
33 
     | 
    
         
             
                  def session_pool
         
     | 
| 
         @@ -34,19 +36,24 @@ module ModernTimes 
     | 
|
| 
       34 
36 
     | 
    
         
             
                    @session_pool_mutex.synchronize do
         
     | 
| 
       35 
37 
     | 
    
         
             
                      # if it's been created in between the above call and now, return it
         
     | 
| 
       36 
38 
     | 
    
         
             
                      return @session_pool if @session_pool
         
     | 
| 
       37 
     | 
    
         
            -
                      return @session_pool =  
     | 
| 
      
 39 
     | 
    
         
            +
                      return @session_pool = connection.create_session_pool(@config)
         
     | 
| 
       38 
40 
     | 
    
         
             
                    end
         
     | 
| 
       39 
41 
     | 
    
         
             
                  end
         
     | 
| 
       40 
42 
     | 
    
         | 
| 
       41 
43 
     | 
    
         
             
                  def close
         
     | 
| 
      
 44 
     | 
    
         
            +
                    return if @closed
         
     | 
| 
       42 
45 
     | 
    
         
             
                    ModernTimes.logger.info "Closing #{self.name}"
         
     | 
| 
       43 
46 
     | 
    
         
             
                    @session_pool.close if @session_pool
         
     | 
| 
       44 
     | 
    
         
            -
                     
     | 
| 
      
 47 
     | 
    
         
            +
                    if @connection
         
     | 
| 
      
 48 
     | 
    
         
            +
                      @connection.stop
         
     | 
| 
      
 49 
     | 
    
         
            +
                      @connection.close
         
     | 
| 
      
 50 
     | 
    
         
            +
                    end
         
     | 
| 
      
 51 
     | 
    
         
            +
                    @closed = true
         
     | 
| 
       45 
52 
     | 
    
         
             
                  end
         
     | 
| 
       46 
53 
     | 
    
         | 
| 
       47 
     | 
    
         
            -
                  def  
     | 
| 
       48 
     | 
    
         
            -
                    raise "#{self.name} never had it's init method called" unless @ 
     | 
| 
       49 
     | 
    
         
            -
                    @ 
     | 
| 
      
 54 
     | 
    
         
            +
                  def connection
         
     | 
| 
      
 55 
     | 
    
         
            +
                    raise "#{self.name} never had it's init method called" unless @connection
         
     | 
| 
      
 56 
     | 
    
         
            +
                    @connection
         
     | 
| 
       50 
57 
     | 
    
         
             
                  end
         
     | 
| 
       51 
58 
     | 
    
         
             
                end
         
     | 
| 
       52 
59 
     | 
    
         
             
              end
         
     | 
| 
         @@ -0,0 +1,91 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'jms'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            # Protocol independent class to handle Publishing
         
     | 
| 
      
 4 
     | 
    
         
            +
            module ModernTimes
         
     | 
| 
      
 5 
     | 
    
         
            +
              module JMS
         
     | 
| 
      
 6 
     | 
    
         
            +
                class Publisher
         
     | 
| 
      
 7 
     | 
    
         
            +
                  attr_reader :producer_options, :persistent, :marshaler
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                  # Parameters:
         
     | 
| 
      
 10 
     | 
    
         
            +
                  #   One of the following must be specified
         
     | 
| 
      
 11 
     | 
    
         
            +
                  #     :queue_name => String: Name of the Queue to publish to
         
     | 
| 
      
 12 
     | 
    
         
            +
                  #     :topic_name => String: Name of the Topic to publish to
         
     | 
| 
      
 13 
     | 
    
         
            +
                  #     :virtual_topic_name => String: Name of the Virtual Topic to publish to
         
     | 
| 
      
 14 
     | 
    
         
            +
                  #        (ActiveMQ only, see http://activemq.apache.org/virtual-destinations.html
         
     | 
| 
      
 15 
     | 
    
         
            +
                  #     :destination=> Explicit javax::Jms::Destination to use
         
     | 
| 
      
 16 
     | 
    
         
            +
                  #   Optional:
         
     | 
| 
      
 17 
     | 
    
         
            +
                  #     :persistent => true or false (defaults to false)
         
     | 
| 
      
 18 
     | 
    
         
            +
                  #     :marshal    => Symbol: One of :ruby, :string, or :json
         
     | 
| 
      
 19 
     | 
    
         
            +
                  #                 => Module: Module that defines marshal and unmarshal method
         
     | 
| 
      
 20 
     | 
    
         
            +
                  def initialize(options)
         
     | 
| 
      
 21 
     | 
    
         
            +
                    producer_keys = [:queue_name, :topic_name, :virtual_topic_name, :destination]
         
     | 
| 
      
 22 
     | 
    
         
            +
                    @producer_options = options.reject {|k,v| !producer_keys.include?(k)}
         
     | 
| 
      
 23 
     | 
    
         
            +
                    raise "One of #{producer_keys.join(',')} must be given in #{self.class.name}" if @producer_options.empty?
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                    # Save our @producer_options for destination comparison when doing dummy_publish,
         
     | 
| 
      
 26 
     | 
    
         
            +
                    # but create the real options by translating virtual_topic_name to a real topic_name.
         
     | 
| 
      
 27 
     | 
    
         
            +
                    @real_producer_options = @producer_options.dup
         
     | 
| 
      
 28 
     | 
    
         
            +
                    virtual_topic_name = @real_producer_options.delete(:virtual_topic_name)
         
     | 
| 
      
 29 
     | 
    
         
            +
                    @real_producer_options[:topic_name] = "VirtualTopic.#{virtual_topic_name}" if virtual_topic_name
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                    # If we're in dummy mode, this probably won't be defined
         
     | 
| 
      
 32 
     | 
    
         
            +
                    #@persistent = options[:persistent] ? ::JMS::DeliveryMode::PERSISTENT : ::JMS::DeliveryMode::NON_PERSISTENT
         
     | 
| 
      
 33 
     | 
    
         
            +
                    @persistent = options[:persistent] ? :persistent : :non_persistent
         
     | 
| 
      
 34 
     | 
    
         
            +
                    @marshaler = ModernTimes::MarshalStrategy.find(options[:marshal])
         
     | 
| 
      
 35 
     | 
    
         
            +
                  end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                  # Publish the given object to the address.
         
     | 
| 
      
 38 
     | 
    
         
            +
                  def publish(object, props={})
         
     | 
| 
      
 39 
     | 
    
         
            +
                    message = nil
         
     | 
| 
      
 40 
     | 
    
         
            +
                    Connection.session_pool.producer(@real_producer_options) do |session, producer|
         
     | 
| 
      
 41 
     | 
    
         
            +
                      message = case @marshaler.marshal_type
         
     | 
| 
      
 42 
     | 
    
         
            +
                                  when :text
         
     | 
| 
      
 43 
     | 
    
         
            +
                                    session.create_text_message(@marshaler.marshal(object))
         
     | 
| 
      
 44 
     | 
    
         
            +
                                  when :bytes
         
     | 
| 
      
 45 
     | 
    
         
            +
                                    msg = session.create_bytes_message()
         
     | 
| 
      
 46 
     | 
    
         
            +
                                    msg.data = @marshaler.marshal(object)
         
     | 
| 
      
 47 
     | 
    
         
            +
                                    msg
         
     | 
| 
      
 48 
     | 
    
         
            +
                                  else raise "Invalid marshal type: #{@marshaler.marshal_type}"
         
     | 
| 
      
 49 
     | 
    
         
            +
                                end
         
     | 
| 
      
 50 
     | 
    
         
            +
                      message.jms_delivery_mode_sym = @persistent
         
     | 
| 
      
 51 
     | 
    
         
            +
                      props.each do |key, value|
         
     | 
| 
      
 52 
     | 
    
         
            +
                        message.send("#{key}=", value)
         
     | 
| 
      
 53 
     | 
    
         
            +
                      end
         
     | 
| 
      
 54 
     | 
    
         
            +
                      # TODO: Is send_with_retry possible?
         
     | 
| 
      
 55 
     | 
    
         
            +
                      #producer.send_with_retry(message)
         
     | 
| 
      
 56 
     | 
    
         
            +
                      producer.send(message)
         
     | 
| 
      
 57 
     | 
    
         
            +
                    end
         
     | 
| 
      
 58 
     | 
    
         
            +
                    return message
         
     | 
| 
      
 59 
     | 
    
         
            +
                  end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                  # For non-configured Rails projects, The above publish method will be overridden to
         
     | 
| 
      
 62 
     | 
    
         
            +
                  # call this publish method instead which calls all the JMS workers that
         
     | 
| 
      
 63 
     | 
    
         
            +
                  # operate on the given address.
         
     | 
| 
      
 64 
     | 
    
         
            +
                  def dummy_publish(object)
         
     | 
| 
      
 65 
     | 
    
         
            +
                    @@worker_instances.each do |worker|
         
     | 
| 
      
 66 
     | 
    
         
            +
                      if worker.kind_of?(Worker) && ModernTimes::JMS.same_destination?(@producer_options, worker.class.destination_options)
         
     | 
| 
      
 67 
     | 
    
         
            +
                        ModernTimes.logger.debug "Dummy publishing #{object} to #{worker}"
         
     | 
| 
      
 68 
     | 
    
         
            +
                        worker.perform(object)
         
     | 
| 
      
 69 
     | 
    
         
            +
                      end
         
     | 
| 
      
 70 
     | 
    
         
            +
                    end
         
     | 
| 
      
 71 
     | 
    
         
            +
                  end
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                  def to_s
         
     | 
| 
      
 74 
     | 
    
         
            +
                    "#{self.class.name}:#{@real_producer_options.inspect}"
         
     | 
| 
      
 75 
     | 
    
         
            +
                  end
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
                  def self.setup_dummy_publishing(workers)
         
     | 
| 
      
 78 
     | 
    
         
            +
                    @@worker_instances = workers.map {|worker| worker.new}
         
     | 
| 
      
 79 
     | 
    
         
            +
                    alias_method :real_publish, :publish
         
     | 
| 
      
 80 
     | 
    
         
            +
                    alias_method :publish, :dummy_publish
         
     | 
| 
      
 81 
     | 
    
         
            +
                  end
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
                  # For testing
         
     | 
| 
      
 84 
     | 
    
         
            +
                  def self.clear_dummy_publishing
         
     | 
| 
      
 85 
     | 
    
         
            +
                    alias_method :dummy_publish, :publish
         
     | 
| 
      
 86 
     | 
    
         
            +
                    alias_method :publish, :real_publish
         
     | 
| 
      
 87 
     | 
    
         
            +
                    #remove_method :real_publish
         
     | 
| 
      
 88 
     | 
    
         
            +
                  end
         
     | 
| 
      
 89 
     | 
    
         
            +
                end
         
     | 
| 
      
 90 
     | 
    
         
            +
              end
         
     | 
| 
      
 91 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,19 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module ModernTimes
         
     | 
| 
      
 2 
     | 
    
         
            +
              module JMS
         
     | 
| 
      
 3 
     | 
    
         
            +
                class Supervisor < ModernTimes::Base::Supervisor
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
                  def initialize(manager, worker_name, supervisor_options, worker_options)
         
     | 
| 
      
 6 
     | 
    
         
            +
                    super
         
     | 
| 
      
 7 
     | 
    
         
            +
                  end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                  def message_counts
         
     | 
| 
      
 10 
     | 
    
         
            +
                    workers.map { |w| w.message_count }
         
     | 
| 
      
 11 
     | 
    
         
            +
                  end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                  # Make JMS::SupervisorMBean our mbean
         
     | 
| 
      
 14 
     | 
    
         
            +
                  def create_mbean(domain)
         
     | 
| 
      
 15 
     | 
    
         
            +
                    SupervisorMBean.new(mbean_name(domain), mbean_description, self, {})
         
     | 
| 
      
 16 
     | 
    
         
            +
                  end
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
              end
         
     | 
| 
      
 19 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,11 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module ModernTimes
         
     | 
| 
      
 2 
     | 
    
         
            +
              module JMS
         
     | 
| 
      
 3 
     | 
    
         
            +
                class SupervisorMBean < ModernTimes::Base::SupervisorMBean
         
     | 
| 
      
 4 
     | 
    
         
            +
                  r_attribute :message_counts, :list, 'Message counts for the workers', :message_counts
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                  def message_counts
         
     | 
| 
      
 7 
     | 
    
         
            +
                    java.util.ArrayList.new(supervisor.message_counts)
         
     | 
| 
      
 8 
     | 
    
         
            +
                  end
         
     | 
| 
      
 9 
     | 
    
         
            +
                end
         
     | 
| 
      
 10 
     | 
    
         
            +
              end
         
     | 
| 
      
 11 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,166 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module ModernTimes
         
     | 
| 
      
 2 
     | 
    
         
            +
              module JMS
         
     | 
| 
      
 3 
     | 
    
         
            +
              
         
     | 
| 
      
 4 
     | 
    
         
            +
                # Base Worker Class for any class that will be processing messages from topics or queues
         
     | 
| 
      
 5 
     | 
    
         
            +
                # By default, it will consume messages from a queue with the class name minus the Worker postfix.
         
     | 
| 
      
 6 
     | 
    
         
            +
                # For example, the queue call is unneccessary as it will default to a value of 'Foo' anyways:
         
     | 
| 
      
 7 
     | 
    
         
            +
                #  class FooWorker < ModernTimes::JMS::Worker
         
     | 
| 
      
 8 
     | 
    
         
            +
                #    queue 'Foo'
         
     | 
| 
      
 9 
     | 
    
         
            +
                #    def perform(obj)
         
     | 
| 
      
 10 
     | 
    
         
            +
                #      # Perform work on obj
         
     | 
| 
      
 11 
     | 
    
         
            +
                #    end
         
     | 
| 
      
 12 
     | 
    
         
            +
                #  end
         
     | 
| 
      
 13 
     | 
    
         
            +
                #
         
     | 
| 
      
 14 
     | 
    
         
            +
                # A topic can be specified using virtual_topic as follows (ActiveMQ only).  Multiple separate workers can
         
     | 
| 
      
 15 
     | 
    
         
            +
                # subscribe to the same topic (under ActiveMQ - see http://activemq.apache.org/virtual-destinations.html):
         
     | 
| 
      
 16 
     | 
    
         
            +
                #  class FooWorker < ModernTimes::JMS::Worker
         
     | 
| 
      
 17 
     | 
    
         
            +
                #    virtual_topic 'Zulu'
         
     | 
| 
      
 18 
     | 
    
         
            +
                #    def perform(obj)
         
     | 
| 
      
 19 
     | 
    
         
            +
                #      # Perform work on obj
         
     | 
| 
      
 20 
     | 
    
         
            +
                #    end
         
     | 
| 
      
 21 
     | 
    
         
            +
                #  end
         
     | 
| 
      
 22 
     | 
    
         
            +
                #
         
     | 
| 
      
 23 
     | 
    
         
            +
                # Filters can also be specified within the class:
         
     | 
| 
      
 24 
     | 
    
         
            +
                #  class FooWorker < ModernTimes::JMS::Worker
         
     | 
| 
      
 25 
     | 
    
         
            +
                #    filter 'age > 30'
         
     | 
| 
      
 26 
     | 
    
         
            +
                #    def perform(obj)
         
     | 
| 
      
 27 
     | 
    
         
            +
                #      # Perform work on obj
         
     | 
| 
      
 28 
     | 
    
         
            +
                #    end
         
     | 
| 
      
 29 
     | 
    
         
            +
                #  end
         
     | 
| 
      
 30 
     | 
    
         
            +
                #
         
     | 
| 
      
 31 
     | 
    
         
            +
                #
         
     | 
| 
      
 32 
     | 
    
         
            +
                module Worker
         
     | 
| 
      
 33 
     | 
    
         
            +
                  include ModernTimes::Base::Worker
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                  attr_reader :session, :message, :message_count
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                  module ClassMethods
         
     | 
| 
      
 38 
     | 
    
         
            +
                    def create_supervisor(manager, worker_options)
         
     | 
| 
      
 39 
     | 
    
         
            +
                      Supervisor.new(manager, self, {}, worker_options)
         
     | 
| 
      
 40 
     | 
    
         
            +
                    end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                    def marshal(option)
         
     | 
| 
      
 43 
     | 
    
         
            +
                      @marshaler = ModernTimes::MarshalStrategy.find(option)
         
     | 
| 
      
 44 
     | 
    
         
            +
                    end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                    def destination_options
         
     | 
| 
      
 47 
     | 
    
         
            +
                      options = dest_options.dup
         
     | 
| 
      
 48 
     | 
    
         
            +
                      # Default the queue name to the Worker name if a destinations hasn't been specified
         
     | 
| 
      
 49 
     | 
    
         
            +
                      if options.keys.select {|k| [:virtual_topic_name, :queue_name, :destination].include?(k)}.empty?
         
     | 
| 
      
 50 
     | 
    
         
            +
                        options[:queue_name] = default_name
         
     | 
| 
      
 51 
     | 
    
         
            +
                      end
         
     | 
| 
      
 52 
     | 
    
         
            +
                      return options
         
     | 
| 
      
 53 
     | 
    
         
            +
                    end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                    def virtual_topic(name, opts={})
         
     | 
| 
      
 56 
     | 
    
         
            +
                      # ActiveMQ only
         
     | 
| 
      
 57 
     | 
    
         
            +
                      dest_options[:virtual_topic_name] = name.to_s
         
     | 
| 
      
 58 
     | 
    
         
            +
                    end
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                    def queue(name, opts={})
         
     | 
| 
      
 61 
     | 
    
         
            +
                      dest_options[:queue_name] = name.to_s
         
     | 
| 
      
 62 
     | 
    
         
            +
                    end
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                    def dest_options
         
     | 
| 
      
 65 
     | 
    
         
            +
                      @dest_options ||= {}
         
     | 
| 
      
 66 
     | 
    
         
            +
                    end
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                    def marshaler
         
     | 
| 
      
 69 
     | 
    
         
            +
                      # Default to ruby marshaling, but extenders can override as necessary
         
     | 
| 
      
 70 
     | 
    
         
            +
                      @marshaler ||= ModernTimes::MarshalStrategy::Ruby
         
     | 
| 
      
 71 
     | 
    
         
            +
                    end
         
     | 
| 
      
 72 
     | 
    
         
            +
                  end
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
                  def self.included(base)
         
     | 
| 
      
 75 
     | 
    
         
            +
                    base.extend(ModernTimes::Base::Worker::ClassMethods)
         
     | 
| 
      
 76 
     | 
    
         
            +
                    base.extend(ClassMethods)
         
     | 
| 
      
 77 
     | 
    
         
            +
                  end
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                  def initialize(opts={})
         
     | 
| 
      
 80 
     | 
    
         
            +
                    super
         
     | 
| 
      
 81 
     | 
    
         
            +
                    @status = 'initialized'
         
     | 
| 
      
 82 
     | 
    
         
            +
                    @message_count = 0
         
     | 
| 
      
 83 
     | 
    
         
            +
                  end
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
                  def setup
         
     | 
| 
      
 86 
     | 
    
         
            +
                  end
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
                  def status
         
     | 
| 
      
 89 
     | 
    
         
            +
                    @status || "Processing message #{message_count}"
         
     | 
| 
      
 90 
     | 
    
         
            +
                  end
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
                  def real_destination_options
         
     | 
| 
      
 93 
     | 
    
         
            +
                    options = self.class.destination_options
         
     | 
| 
      
 94 
     | 
    
         
            +
                    virtual_topic_name = options.delete(:virtual_topic_name)
         
     | 
| 
      
 95 
     | 
    
         
            +
                    options[:queue_name] = "Consumer.#{name}.VirtualTopic.#{virtual_topic_name}" if virtual_topic_name
         
     | 
| 
      
 96 
     | 
    
         
            +
                    return options
         
     | 
| 
      
 97 
     | 
    
         
            +
                  end
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
                  def on_message(message)
         
     | 
| 
      
 100 
     | 
    
         
            +
                    @message = message
         
     | 
| 
      
 101 
     | 
    
         
            +
                    object = self.class.marshaler.unmarshal(message.data)
         
     | 
| 
      
 102 
     | 
    
         
            +
                    ModernTimes.logger.debug "#{self}: Received Object: #{object}" if ModernTimes.logger.debug?
         
     | 
| 
      
 103 
     | 
    
         
            +
                    perform(object)
         
     | 
| 
      
 104 
     | 
    
         
            +
                    ModernTimes.logger.debug "#{self}: Finished processing message" if ModernTimes.logger.debug?
         
     | 
| 
      
 105 
     | 
    
         
            +
                    ModernTimes.logger.flush if ModernTimes.logger.respond_to?(:flush)
         
     | 
| 
      
 106 
     | 
    
         
            +
                  rescue Exception => e
         
     | 
| 
      
 107 
     | 
    
         
            +
                    ModernTimes.logger.error "#{self}: Messaging Exception: #{e.inspect}\n#{e.backtrace.inspect}"
         
     | 
| 
      
 108 
     | 
    
         
            +
                  rescue java.lang.Exception => e
         
     | 
| 
      
 109 
     | 
    
         
            +
                    ModernTimes.logger.error "#{self}: Java Messaging Exception: #{e.inspect}\n#{e.backtrace.inspect}"
         
     | 
| 
      
 110 
     | 
    
         
            +
                  end
         
     | 
| 
      
 111 
     | 
    
         
            +
             
     | 
| 
      
 112 
     | 
    
         
            +
                  def perform(object)
         
     | 
| 
      
 113 
     | 
    
         
            +
                    raise "#{self}: Need to override perform method in #{self.class.name} in order to act on #{object}"
         
     | 
| 
      
 114 
     | 
    
         
            +
                  end
         
     | 
| 
      
 115 
     | 
    
         
            +
             
     | 
| 
      
 116 
     | 
    
         
            +
                  def to_s
         
     | 
| 
      
 117 
     | 
    
         
            +
                    "#{real_destination_options.to_a.join('=>')}:#{index}"
         
     | 
| 
      
 118 
     | 
    
         
            +
                  end
         
     | 
| 
      
 119 
     | 
    
         
            +
             
     | 
| 
      
 120 
     | 
    
         
            +
                  # Start the event loop for handling messages off the queue
         
     | 
| 
      
 121 
     | 
    
         
            +
                  def start
         
     | 
| 
      
 122 
     | 
    
         
            +
                    @session = Connection.create_consumer_session
         
     | 
| 
      
 123 
     | 
    
         
            +
                    @consumer = @session.consumer(real_destination_options)
         
     | 
| 
      
 124 
     | 
    
         
            +
                    @session.start
         
     | 
| 
      
 125 
     | 
    
         
            +
             
     | 
| 
      
 126 
     | 
    
         
            +
                    ModernTimes.logger.debug "#{self}: Starting receive loop"
         
     | 
| 
      
 127 
     | 
    
         
            +
                    @status = nil
         
     | 
| 
      
 128 
     | 
    
         
            +
                    while msg = @consumer.receive
         
     | 
| 
      
 129 
     | 
    
         
            +
                      @message_count += 1
         
     | 
| 
      
 130 
     | 
    
         
            +
                      on_message(msg)
         
     | 
| 
      
 131 
     | 
    
         
            +
                      msg.acknowledge
         
     | 
| 
      
 132 
     | 
    
         
            +
                    end
         
     | 
| 
      
 133 
     | 
    
         
            +
                    @status = 'Exited'
         
     | 
| 
      
 134 
     | 
    
         
            +
                    ModernTimes.logger.info "#{self}: Exiting"
         
     | 
| 
      
 135 
     | 
    
         
            +
                  rescue javax.jms.IllegalStateException => e
         
     | 
| 
      
 136 
     | 
    
         
            +
                    #if e.cause.code == Java::org.jms.api.core.JMSException::OBJECT_CLOSED
         
     | 
| 
      
 137 
     | 
    
         
            +
                      # Normal exit
         
     | 
| 
      
 138 
     | 
    
         
            +
                      @status = 'Exited'
         
     | 
| 
      
 139 
     | 
    
         
            +
                      ModernTimes.logger.info "#{self}: Exiting due to close"
         
     | 
| 
      
 140 
     | 
    
         
            +
                    #else
         
     | 
| 
      
 141 
     | 
    
         
            +
                    #  @status = "Exited with JMS exception #{e.message}"
         
     | 
| 
      
 142 
     | 
    
         
            +
                    #  ModernTImes.logger.error "#{self} JMSException: #{e.message}\n#{e.backtrace.join("\n")}"
         
     | 
| 
      
 143 
     | 
    
         
            +
                    #end
         
     | 
| 
      
 144 
     | 
    
         
            +
                  rescue Exception => e
         
     | 
| 
      
 145 
     | 
    
         
            +
                    @status = "Exited with exception #{e.message}"
         
     | 
| 
      
 146 
     | 
    
         
            +
                    ModernTimes.logger.error "#{self}: Exception, thread terminating: #{e.message}\n\t#{e.backtrace.join("\n\t")}"
         
     | 
| 
      
 147 
     | 
    
         
            +
                  rescue java.lang.Exception => e
         
     | 
| 
      
 148 
     | 
    
         
            +
                    @status = "Exited with java exception #{e.message}"
         
     | 
| 
      
 149 
     | 
    
         
            +
                    ModernTimes.logger.error "#{self}: Java exception, thread terminating: #{e.message}\n\t#{e.backtrace.join("\n\t")}"
         
     | 
| 
      
 150 
     | 
    
         
            +
                  end
         
     | 
| 
      
 151 
     | 
    
         
            +
             
     | 
| 
      
 152 
     | 
    
         
            +
                  def stop
         
     | 
| 
      
 153 
     | 
    
         
            +
                    @consumer.close if @consumer
         
     | 
| 
      
 154 
     | 
    
         
            +
                    @session.close if @session
         
     | 
| 
      
 155 
     | 
    
         
            +
                  end
         
     | 
| 
      
 156 
     | 
    
         
            +
             
     | 
| 
      
 157 
     | 
    
         
            +
                  #########
         
     | 
| 
      
 158 
     | 
    
         
            +
                  protected
         
     | 
| 
      
 159 
     | 
    
         
            +
                  #########
         
     | 
| 
      
 160 
     | 
    
         
            +
             
     | 
| 
      
 161 
     | 
    
         
            +
                  # Create session information and allow extenders to initialize anything necessary prior to the event loop
         
     | 
| 
      
 162 
     | 
    
         
            +
                  def session_init
         
     | 
| 
      
 163 
     | 
    
         
            +
                  end
         
     | 
| 
      
 164 
     | 
    
         
            +
                end
         
     | 
| 
      
 165 
     | 
    
         
            +
              end
         
     | 
| 
      
 166 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,10 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'modern_times/jms_requestor/request_handle'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'modern_times/jms_requestor/requestor'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'modern_times/jms_requestor/supervisor_mbean'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'modern_times/jms_requestor/supervisor'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'modern_times/jms_requestor/worker'
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            module ModernTimes
         
     | 
| 
      
 8 
     | 
    
         
            +
              module JMSRequestor
         
     | 
| 
      
 9 
     | 
    
         
            +
              end
         
     | 
| 
      
 10 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,33 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'timeout'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module ModernTimes
         
     | 
| 
      
 4 
     | 
    
         
            +
              module JMSRequestor
         
     | 
| 
      
 5 
     | 
    
         
            +
                class RequestHandle
         
     | 
| 
      
 6 
     | 
    
         
            +
                  def initialize(requestor, message, start, timeout)
         
     | 
| 
      
 7 
     | 
    
         
            +
                    @requestor   = requestor
         
     | 
| 
      
 8 
     | 
    
         
            +
                    @reply_queue = requestor.reply_queue
         
     | 
| 
      
 9 
     | 
    
         
            +
                    @message     = message
         
     | 
| 
      
 10 
     | 
    
         
            +
                    @start       = start
         
     | 
| 
      
 11 
     | 
    
         
            +
                    @timeout     = timeout
         
     | 
| 
      
 12 
     | 
    
         
            +
                  end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                  def read_response
         
     | 
| 
      
 15 
     | 
    
         
            +
                    response = nil
         
     | 
| 
      
 16 
     | 
    
         
            +
                    opts = { :destination => @reply_queue, :selector => "JMSCorrelationID = '#{@message.jms_message_id}'" }
         
     | 
| 
      
 17 
     | 
    
         
            +
                    #opts = { :destination => @reply_queue }
         
     | 
| 
      
 18 
     | 
    
         
            +
                    #opts = {:queue_name => 'foobarzulu'}
         
     | 
| 
      
 19 
     | 
    
         
            +
                    ModernTimes::JMS::Connection.session_pool.consumer(opts) do |session, consumer|
         
     | 
| 
      
 20 
     | 
    
         
            +
                      leftover_timeout = ((@start + @timeout - Time.now) * 1000).to_i
         
     | 
| 
      
 21 
     | 
    
         
            +
                      if leftover_timeout > 100
         
     | 
| 
      
 22 
     | 
    
         
            +
                        response = consumer.receive(leftover_timeout)
         
     | 
| 
      
 23 
     | 
    
         
            +
                      else
         
     | 
| 
      
 24 
     | 
    
         
            +
                        #response = consumer.receive_no_wait
         
     | 
| 
      
 25 
     | 
    
         
            +
                        response = consumer.receive(100)
         
     | 
| 
      
 26 
     | 
    
         
            +
                      end
         
     | 
| 
      
 27 
     | 
    
         
            +
                    end
         
     | 
| 
      
 28 
     | 
    
         
            +
                    raise Timeout::Error, "Timeout waiting for for response from message #{@message.jms_message_id} on queue #{@reply_queue}" unless response
         
     | 
| 
      
 29 
     | 
    
         
            +
                    return @requestor.marshaler.unmarshal(response.data)
         
     | 
| 
      
 30 
     | 
    
         
            +
                  end
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
              end
         
     | 
| 
      
 33 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,45 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module ModernTimes
         
     | 
| 
      
 2 
     | 
    
         
            +
              module JMSRequestor
         
     | 
| 
      
 3 
     | 
    
         
            +
                class Requestor < ModernTimes::JMS::Publisher
         
     | 
| 
      
 4 
     | 
    
         
            +
                  attr_reader :reply_queue
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                  def initialize(options)
         
     | 
| 
      
 7 
     | 
    
         
            +
                    super
         
     | 
| 
      
 8 
     | 
    
         
            +
                    ModernTimes::JMS::Connection.session_pool.session do |session|
         
     | 
| 
      
 9 
     | 
    
         
            +
                      @reply_queue = session.create_destination(:queue_name => :temporary)
         
     | 
| 
      
 10 
     | 
    
         
            +
                    end
         
     | 
| 
      
 11 
     | 
    
         
            +
                  end
         
     | 
| 
      
 12 
     | 
    
         
            +
                  
         
     | 
| 
      
 13 
     | 
    
         
            +
                  def request(object, timeout)
         
     | 
| 
      
 14 
     | 
    
         
            +
                    start = Time.now
         
     | 
| 
      
 15 
     | 
    
         
            +
                    message = publish(object, :jms_reply_to => @reply_queue)
         
     | 
| 
      
 16 
     | 
    
         
            +
                    return RequestHandle.new(self, message, start, timeout)
         
     | 
| 
      
 17 
     | 
    
         
            +
                  end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                  # For non-configured Rails projects, The above request method will be overridden to
         
     | 
| 
      
 20 
     | 
    
         
            +
                  # call this request method instead which calls all the JMS workers that
         
     | 
| 
      
 21 
     | 
    
         
            +
                  # operate on the given address.
         
     | 
| 
      
 22 
     | 
    
         
            +
                  def dummy_request(object, timeout)
         
     | 
| 
      
 23 
     | 
    
         
            +
                    @@worker_instances.each do |worker|
         
     | 
| 
      
 24 
     | 
    
         
            +
                      if worker.kind_of?(Worker) && ModernTimes::JMS.same_destination?(producer_options, worker.destination_options)
         
     | 
| 
      
 25 
     | 
    
         
            +
                        ModernTimes.logger.debug "Dummy requesting #{object} to #{worker}"
         
     | 
| 
      
 26 
     | 
    
         
            +
                        return new OpenStruct(:read_response => worker.request(object))
         
     | 
| 
      
 27 
     | 
    
         
            +
                      end
         
     | 
| 
      
 28 
     | 
    
         
            +
                    end
         
     | 
| 
      
 29 
     | 
    
         
            +
                    raise "No worker to handle #{address} request of #{object}"
         
     | 
| 
      
 30 
     | 
    
         
            +
                  end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                  def self.setup_dummy_requesting(workers)
         
     | 
| 
      
 33 
     | 
    
         
            +
                    @@worker_instances = workers.map {|worker| worker.new}
         
     | 
| 
      
 34 
     | 
    
         
            +
                    alias_method :real_request, :request
         
     | 
| 
      
 35 
     | 
    
         
            +
                    alias_method :request, :dummy_request
         
     | 
| 
      
 36 
     | 
    
         
            +
                  end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                  # For testing
         
     | 
| 
      
 39 
     | 
    
         
            +
                  def self.clear_dummy_requesting
         
     | 
| 
      
 40 
     | 
    
         
            +
                    alias_method :dummy_request, :request
         
     | 
| 
      
 41 
     | 
    
         
            +
                    alias_method :request, :real_request
         
     | 
| 
      
 42 
     | 
    
         
            +
                  end
         
     | 
| 
      
 43 
     | 
    
         
            +
                end
         
     | 
| 
      
 44 
     | 
    
         
            +
              end
         
     | 
| 
      
 45 
     | 
    
         
            +
            end
         
     |