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,45 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module ModernTimes
         
     | 
| 
      
 2 
     | 
    
         
            +
              module JMSRequestor
         
     | 
| 
      
 3 
     | 
    
         
            +
                class Supervisor < ModernTimes::JMS::Supervisor
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
                  def initialize(manager, worker_name, supervisor_options, worker_options)
         
     | 
| 
      
 6 
     | 
    
         
            +
                    super
         
     | 
| 
      
 7 
     | 
    
         
            +
                  end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                  def average_response_time
         
     | 
| 
      
 10 
     | 
    
         
            +
                    count = 0
         
     | 
| 
      
 11 
     | 
    
         
            +
                    total = 0.0
         
     | 
| 
      
 12 
     | 
    
         
            +
                    workers.each do |w|
         
     | 
| 
      
 13 
     | 
    
         
            +
                      pair = w.total_time
         
     | 
| 
      
 14 
     | 
    
         
            +
                      count += pair.first
         
     | 
| 
      
 15 
     | 
    
         
            +
                      total += pair.last
         
     | 
| 
      
 16 
     | 
    
         
            +
                    end
         
     | 
| 
      
 17 
     | 
    
         
            +
                    return 0.0 if count == 0
         
     | 
| 
      
 18 
     | 
    
         
            +
                    return total / count
         
     | 
| 
      
 19 
     | 
    
         
            +
                  end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                  def min_response_time
         
     | 
| 
      
 22 
     | 
    
         
            +
                    min_time = nil
         
     | 
| 
      
 23 
     | 
    
         
            +
                    workers.each do |w|
         
     | 
| 
      
 24 
     | 
    
         
            +
                      wmin_time = w.min_time
         
     | 
| 
      
 25 
     | 
    
         
            +
                      min_time = wmin_time if wmin_time && (!min_time || wmin_time < min_time)
         
     | 
| 
      
 26 
     | 
    
         
            +
                    end
         
     | 
| 
      
 27 
     | 
    
         
            +
                    return min_time || 0.0
         
     | 
| 
      
 28 
     | 
    
         
            +
                  end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                  def max_response_time
         
     | 
| 
      
 31 
     | 
    
         
            +
                    max_time = 0.0
         
     | 
| 
      
 32 
     | 
    
         
            +
                    workers.each do |w|
         
     | 
| 
      
 33 
     | 
    
         
            +
                      wmax_time = w.max_time
         
     | 
| 
      
 34 
     | 
    
         
            +
                      max_time = wmax_time if wmax_time > max_time
         
     | 
| 
      
 35 
     | 
    
         
            +
                    end
         
     | 
| 
      
 36 
     | 
    
         
            +
                    return max_time
         
     | 
| 
      
 37 
     | 
    
         
            +
                  end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                  # Make JMSRequestor::SupervisorMBean our mbean
         
     | 
| 
      
 40 
     | 
    
         
            +
                  def create_mbean(domain)
         
     | 
| 
      
 41 
     | 
    
         
            +
                    SupervisorMBean.new(mbean_name(domain), mbean_description, self, {})
         
     | 
| 
      
 42 
     | 
    
         
            +
                  end
         
     | 
| 
      
 43 
     | 
    
         
            +
                end
         
     | 
| 
      
 44 
     | 
    
         
            +
              end
         
     | 
| 
      
 45 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,21 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module ModernTimes
         
     | 
| 
      
 2 
     | 
    
         
            +
              module JMSRequestor
         
     | 
| 
      
 3 
     | 
    
         
            +
                class SupervisorMBean < ModernTimes::JMS::SupervisorMBean
         
     | 
| 
      
 4 
     | 
    
         
            +
                  r_attribute :average_response_time, :float, 'Average response time', :average_response_time
         
     | 
| 
      
 5 
     | 
    
         
            +
                  r_attribute :min_response_time,     :float, 'Minimum response time', :min_response_time
         
     | 
| 
      
 6 
     | 
    
         
            +
                  r_attribute :max_response_time,     :float, 'Maximum response time', :max_response_time
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  def average_response_time
         
     | 
| 
      
 9 
     | 
    
         
            +
                    supervisor.average_response_time
         
     | 
| 
      
 10 
     | 
    
         
            +
                  end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                  def min_response_time
         
     | 
| 
      
 13 
     | 
    
         
            +
                    supervisor.min_response_time
         
     | 
| 
      
 14 
     | 
    
         
            +
                  end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                  def max_response_time
         
     | 
| 
      
 17 
     | 
    
         
            +
                    supervisor.max_response_time
         
     | 
| 
      
 18 
     | 
    
         
            +
                  end
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
              end
         
     | 
| 
      
 21 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,78 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module ModernTimes
         
     | 
| 
      
 2 
     | 
    
         
            +
              module JMSRequestor
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
                # Base Worker Class for any class that will be processing messages from queues
         
     | 
| 
      
 5 
     | 
    
         
            +
                module Worker
         
     | 
| 
      
 6 
     | 
    
         
            +
                  include ModernTimes::JMS::Worker
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  module ClassMethods
         
     | 
| 
      
 9 
     | 
    
         
            +
                    def create_supervisor(manager, worker_options)
         
     | 
| 
      
 10 
     | 
    
         
            +
                      Supervisor.new(manager, self, {}, worker_options)
         
     | 
| 
      
 11 
     | 
    
         
            +
                    end
         
     | 
| 
      
 12 
     | 
    
         
            +
                  end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                  def self.included(base)
         
     | 
| 
      
 15 
     | 
    
         
            +
                    # The price we pay for including rather than extending
         
     | 
| 
      
 16 
     | 
    
         
            +
                    base.extend(ModernTimes::Base::Worker::ClassMethods)
         
     | 
| 
      
 17 
     | 
    
         
            +
                    base.extend(ModernTimes::JMS::Worker::ClassMethods)
         
     | 
| 
      
 18 
     | 
    
         
            +
                    base.extend(ClassMethods)
         
     | 
| 
      
 19 
     | 
    
         
            +
                  end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                  def initialize(opts={})
         
     | 
| 
      
 22 
     | 
    
         
            +
                    super
         
     | 
| 
      
 23 
     | 
    
         
            +
                    @time_mutex = Mutex.new
         
     | 
| 
      
 24 
     | 
    
         
            +
                    @count      = 0
         
     | 
| 
      
 25 
     | 
    
         
            +
                    @min_time   = nil
         
     | 
| 
      
 26 
     | 
    
         
            +
                    @max_time   = 0.0
         
     | 
| 
      
 27 
     | 
    
         
            +
                    @total_time = 0.0
         
     | 
| 
      
 28 
     | 
    
         
            +
                  end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                  def perform(object)
         
     | 
| 
      
 31 
     | 
    
         
            +
                    start_time = Time.now
         
     | 
| 
      
 32 
     | 
    
         
            +
                    response = request(object)
         
     | 
| 
      
 33 
     | 
    
         
            +
                    response_time = Time.now - start_time
         
     | 
| 
      
 34 
     | 
    
         
            +
                    session.producer(:destination => message.reply_to) do |producer|
         
     | 
| 
      
 35 
     | 
    
         
            +
                      reply_message = session.message(self.class.marshaler.marshal(response))
         
     | 
| 
      
 36 
     | 
    
         
            +
                      reply_message.jms_correlation_id = message.jms_message_id
         
     | 
| 
      
 37 
     | 
    
         
            +
                      #producer.send_with_retry(reply_message)
         
     | 
| 
      
 38 
     | 
    
         
            +
                      producer.send(reply_message)
         
     | 
| 
      
 39 
     | 
    
         
            +
                    end
         
     | 
| 
      
 40 
     | 
    
         
            +
                    @time_mutex.synchronize do
         
     | 
| 
      
 41 
     | 
    
         
            +
                      @count      += 1
         
     | 
| 
      
 42 
     | 
    
         
            +
                      @total_time += response_time
         
     | 
| 
      
 43 
     | 
    
         
            +
                      @min_time    = response_time if !@min_time || response_time < @min_time
         
     | 
| 
      
 44 
     | 
    
         
            +
                      @max_time    = response_time if response_time > @max_time
         
     | 
| 
      
 45 
     | 
    
         
            +
                    end
         
     | 
| 
      
 46 
     | 
    
         
            +
                  end
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                  def total_time
         
     | 
| 
      
 49 
     | 
    
         
            +
                    @time_mutex.synchronize do
         
     | 
| 
      
 50 
     | 
    
         
            +
                      retval = [@count, @total_time]
         
     | 
| 
      
 51 
     | 
    
         
            +
                      @count = 0
         
     | 
| 
      
 52 
     | 
    
         
            +
                      @total_time = 0.0
         
     | 
| 
      
 53 
     | 
    
         
            +
                      return retval
         
     | 
| 
      
 54 
     | 
    
         
            +
                    end
         
     | 
| 
      
 55 
     | 
    
         
            +
                  end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                  def min_time
         
     | 
| 
      
 58 
     | 
    
         
            +
                    @time_mutex.synchronize do
         
     | 
| 
      
 59 
     | 
    
         
            +
                      val = @min_time
         
     | 
| 
      
 60 
     | 
    
         
            +
                      @min_time = nil
         
     | 
| 
      
 61 
     | 
    
         
            +
                      return val
         
     | 
| 
      
 62 
     | 
    
         
            +
                    end
         
     | 
| 
      
 63 
     | 
    
         
            +
                  end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                  def max_time
         
     | 
| 
      
 66 
     | 
    
         
            +
                    @time_mutex.synchronize do
         
     | 
| 
      
 67 
     | 
    
         
            +
                      val = @max_time
         
     | 
| 
      
 68 
     | 
    
         
            +
                      @max_time = 0.0
         
     | 
| 
      
 69 
     | 
    
         
            +
                      return val
         
     | 
| 
      
 70 
     | 
    
         
            +
                    end
         
     | 
| 
      
 71 
     | 
    
         
            +
                  end
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                  def request(object)
         
     | 
| 
      
 74 
     | 
    
         
            +
                    raise "#{self}: Need to override request method in #{self.class.name} in order to act on #{object}"
         
     | 
| 
      
 75 
     | 
    
         
            +
                  end
         
     | 
| 
      
 76 
     | 
    
         
            +
                end
         
     | 
| 
      
 77 
     | 
    
         
            +
              end
         
     | 
| 
      
 78 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/modern_times/manager.rb
    CHANGED
    
    | 
         @@ -1,46 +1,51 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'yaml'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
       1 
3 
     | 
    
         
             
            module ModernTimes
         
     | 
| 
       2 
4 
     | 
    
         
             
              class Manager
         
     | 
| 
       3 
5 
     | 
    
         
             
                attr_accessor :allowed_workers
         
     | 
| 
      
 6 
     | 
    
         
            +
                attr_reader   :supervisors
         
     | 
| 
       4 
7 
     | 
    
         | 
| 
       5 
8 
     | 
    
         
             
                def initialize(config={})
         
     | 
| 
       6 
9 
     | 
    
         
             
                  @stopped = false
         
     | 
| 
       7 
10 
     | 
    
         
             
                  @config = config
         
     | 
| 
       8 
     | 
    
         
            -
                  @domain = config[:domain] ||  
     | 
| 
      
 11 
     | 
    
         
            +
                  @domain = config[:domain] || ModernTimes::DEFAULT_DOMAIN
         
     | 
| 
       9 
12 
     | 
    
         
             
                  @supervisors = []
         
     | 
| 
       10 
13 
     | 
    
         
             
                  @jmx_server = JMX::MBeanServer.new
         
     | 
| 
       11 
     | 
    
         
            -
                  bean = ManagerMBean.new( 
     | 
| 
       12 
     | 
    
         
            -
                  @jmx_server.register_mbean(bean,  
     | 
| 
      
 14 
     | 
    
         
            +
                  bean = ManagerMBean.new(@domain, self)
         
     | 
| 
      
 15 
     | 
    
         
            +
                  @jmx_server.register_mbean(bean, ModernTimes.manager_mbean_object_name(@domain))
         
     | 
| 
       13 
16 
     | 
    
         
             
                  self.persist_file = config[:persist_file]
         
     | 
| 
       14 
17 
     | 
    
         
             
                end
         
     | 
| 
       15 
18 
     | 
    
         | 
| 
       16 
     | 
    
         
            -
                def add(worker_klass, num_workers, worker_options)
         
     | 
| 
      
 19 
     | 
    
         
            +
                def add(worker_klass, num_workers, worker_options={})
         
     | 
| 
       17 
20 
     | 
    
         
             
                  ModernTimes.logger.info "Starting #{worker_klass} with #{num_workers} workers with options #{worker_options.inspect}"
         
     | 
| 
       18 
21 
     | 
    
         
             
                  unless worker_klass.kind_of?(Class)
         
     | 
| 
       19 
22 
     | 
    
         
             
                    begin
         
     | 
| 
       20 
23 
     | 
    
         
             
                      worker_klass = Object.const_get(worker_klass.to_s)
         
     | 
| 
       21 
24 
     | 
    
         
             
                    rescue
         
     | 
| 
       22 
     | 
    
         
            -
                      raise ModernTimes::Exception 
     | 
| 
      
 25 
     | 
    
         
            +
                      raise ModernTimes::Exception, "Invalid class: #{worker_klass}"
         
     | 
| 
       23 
26 
     | 
    
         
             
                    end
         
     | 
| 
       24 
27 
     | 
    
         
             
                  end
         
     | 
| 
       25 
28 
     | 
    
         
             
                  if @allowed_workers && !@allowed_workers.include?(worker_klass)
         
     | 
| 
       26 
     | 
    
         
            -
                    raise ModernTimes::Exception 
     | 
| 
      
 29 
     | 
    
         
            +
                    raise ModernTimes::Exception, "Error: #{worker_klass.name} is not an allowed worker"
         
     | 
| 
       27 
30 
     | 
    
         
             
                  end
         
     | 
| 
       28 
31 
     | 
    
         
             
                  supervisor = worker_klass.create_supervisor(self, worker_options)
         
     | 
| 
       29 
32 
     | 
    
         
             
                  mbean = supervisor.create_mbean(@domain)
         
     | 
| 
       30 
33 
     | 
    
         
             
                  @supervisors << supervisor
         
     | 
| 
       31 
34 
     | 
    
         
             
                  supervisor.worker_count = num_workers
         
     | 
| 
       32 
35 
     | 
    
         
             
                  @jmx_server.register_mbean(mbean, "#{@domain}:worker=#{supervisor.name},type=Worker")
         
     | 
| 
       33 
     | 
    
         
            -
                  ModernTimes.logger.info "Started #{worker_klass.name} with #{num_workers} workers"
         
     | 
| 
      
 36 
     | 
    
         
            +
                  ModernTimes.logger.info "Started #{worker_klass.name} named #{supervisor.name} with #{num_workers} workers"
         
     | 
| 
       34 
37 
     | 
    
         
             
                rescue Exception => e
         
     | 
| 
       35 
     | 
    
         
            -
                  ModernTimes.logger.error "Exception trying to add #{worker_klass 
     | 
| 
      
 38 
     | 
    
         
            +
                  ModernTimes.logger.error "Exception trying to add #{worker_klass}: #{e.message}\n\t#{e.backtrace.join("\n\t")}"
         
     | 
| 
      
 39 
     | 
    
         
            +
                  raise
         
     | 
| 
       36 
40 
     | 
    
         
             
                rescue java.lang.Exception => e
         
     | 
| 
       37 
41 
     | 
    
         
             
                  ModernTimes.logger.error "Java exception trying to add #{worker_klass.name}: #{e.message}\n\t#{e.backtrace.join("\n\t")}"
         
     | 
| 
      
 42 
     | 
    
         
            +
                  raise
         
     | 
| 
       38 
43 
     | 
    
         
             
                end
         
     | 
| 
       39 
44 
     | 
    
         | 
| 
      
 45 
     | 
    
         
            +
                # TODO: Get rid of this or prevent worker thread creation until it's been called?
         
     | 
| 
       40 
46 
     | 
    
         
             
                def start
         
     | 
| 
       41 
47 
     | 
    
         
             
                  return if @started
         
     | 
| 
       42 
48 
     | 
    
         
             
                  @started = true
         
     | 
| 
       43 
     | 
    
         
            -
             
     | 
| 
       44 
49 
     | 
    
         
             
                end
         
     | 
| 
       45 
50 
     | 
    
         | 
| 
       46 
51 
     | 
    
         
             
                def stop
         
     | 
| 
         @@ -5,8 +5,8 @@ module ModernTimes 
     | 
|
| 
       5 
5 
     | 
    
         
             
                attr_reader :manager
         
     | 
| 
       6 
6 
     | 
    
         
             
                r_attribute :allowed_workers, :list, 'Allowed workers'
         
     | 
| 
       7 
7 
     | 
    
         | 
| 
       8 
     | 
    
         
            -
                def initialize( 
     | 
| 
       9 
     | 
    
         
            -
                  super( 
     | 
| 
      
 8 
     | 
    
         
            +
                def initialize(domain, manager)
         
     | 
| 
      
 9 
     | 
    
         
            +
                  super(ModernTimes.manager_mbean_name(domain), 'Manager')
         
     | 
| 
       10 
10 
     | 
    
         
             
                  @manager = manager
         
     | 
| 
       11 
11 
     | 
    
         
             
                end
         
     | 
| 
       12 
12 
     | 
    
         | 
| 
         @@ -17,12 +17,19 @@ module ModernTimes 
     | 
|
| 
       17 
17 
     | 
    
         
             
                end
         
     | 
| 
       18 
18 
     | 
    
         | 
| 
       19 
19 
     | 
    
         
             
                operation 'Start worker'
         
     | 
| 
       20 
     | 
    
         
            -
                parameter :string,  
     | 
| 
       21 
     | 
    
         
            -
                parameter :int, 
     | 
| 
      
 20 
     | 
    
         
            +
                parameter :string, 'worker',  'The worker class to start'
         
     | 
| 
      
 21 
     | 
    
         
            +
                parameter :int,    'count',   'Number of workers'
         
     | 
| 
      
 22 
     | 
    
         
            +
                parameter :string, 'options', 'Hash of options in json format (optional)'
         
     | 
| 
       22 
23 
     | 
    
         
             
                returns :string
         
     | 
| 
       23 
     | 
    
         
            -
                def start_worker(worker, count)
         
     | 
| 
       24 
     | 
    
         
            -
                  ModernTimes.logger.debug "Attempting to start #{worker} with count=#{count}"
         
     | 
| 
       25 
     | 
    
         
            -
                   
     | 
| 
      
 24 
     | 
    
         
            +
                def start_worker(worker, count, options)
         
     | 
| 
      
 25 
     | 
    
         
            +
                  ModernTimes.logger.debug "Attempting to start #{worker} with count=#{count} and options=#{options}"
         
     | 
| 
      
 26 
     | 
    
         
            +
                  opts = {}
         
     | 
| 
      
 27 
     | 
    
         
            +
                  unless options.empty?
         
     | 
| 
      
 28 
     | 
    
         
            +
                    require 'json'
         
     | 
| 
      
 29 
     | 
    
         
            +
                    opts_string_keys = ::JSON::Parser.new(options).parse
         
     | 
| 
      
 30 
     | 
    
         
            +
                    opts_string_keys.each { |k,v| opts[k.to_sym] = v }
         
     | 
| 
      
 31 
     | 
    
         
            +
                  end
         
     | 
| 
      
 32 
     | 
    
         
            +
                  manager.add(worker, count, opts)
         
     | 
| 
       26 
33 
     | 
    
         
             
                  return 'Successfuly started'
         
     | 
| 
       27 
34 
     | 
    
         
             
                rescue Exception => e
         
     | 
| 
       28 
35 
     | 
    
         
             
                  ModernTimes.logger.error "Exception starting worker #{worker}: {e.message}\n\t#{e.backtrace.join("\n\t")}"
         
     | 
| 
         @@ -0,0 +1,47 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'modern_times/marshal_strategy/bson'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'modern_times/marshal_strategy/json'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'modern_times/marshal_strategy/ruby'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'modern_times/marshal_strategy/string'
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            # Defines some default marshaling strategies for use in marshaling/unmarshaling objects
         
     | 
| 
      
 7 
     | 
    
         
            +
            # written and read via jms.  Implementing classes must define the following methods:
         
     | 
| 
      
 8 
     | 
    
         
            +
            #
         
     | 
| 
      
 9 
     | 
    
         
            +
            #   # Return symbol
         
     | 
| 
      
 10 
     | 
    
         
            +
            #   #  :text  if session.create_text_message should be used to generate the JMS message
         
     | 
| 
      
 11 
     | 
    
         
            +
            #   #  :bytes if session.create_bytes_message should be used to generate the JMS message
         
     | 
| 
      
 12 
     | 
    
         
            +
            #   def marshal_type
         
     | 
| 
      
 13 
     | 
    
         
            +
            #     # Return either :text or :bytes
         
     | 
| 
      
 14 
     | 
    
         
            +
            #     :text
         
     | 
| 
      
 15 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 16 
     | 
    
         
            +
            #
         
     | 
| 
      
 17 
     | 
    
         
            +
            #   # Defines the conversion to wire format by the publisher of the message
         
     | 
| 
      
 18 
     | 
    
         
            +
            #   def marshal(object)
         
     | 
| 
      
 19 
     | 
    
         
            +
            #     # Operate on object and convert to message format
         
     | 
| 
      
 20 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 21 
     | 
    
         
            +
            #
         
     | 
| 
      
 22 
     | 
    
         
            +
            #   # Defines the conversion from wire format by the consumer of the message
         
     | 
| 
      
 23 
     | 
    
         
            +
            #   def unmarshal(msg)
         
     | 
| 
      
 24 
     | 
    
         
            +
            #     # Operate on message to convert it from wire protocol back to object format
         
     | 
| 
      
 25 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
            module ModernTimes
         
     | 
| 
      
 28 
     | 
    
         
            +
              module MarshalStrategy
         
     | 
| 
      
 29 
     | 
    
         
            +
                def self.find(marshal_option)
         
     | 
| 
      
 30 
     | 
    
         
            +
                  if marshal_option.nil?
         
     | 
| 
      
 31 
     | 
    
         
            +
                    return Ruby
         
     | 
| 
      
 32 
     | 
    
         
            +
                  elsif marshal_option.kind_of? Symbol
         
     | 
| 
      
 33 
     | 
    
         
            +
                    return case marshal_option
         
     | 
| 
      
 34 
     | 
    
         
            +
                             when :ruby   then Ruby
         
     | 
| 
      
 35 
     | 
    
         
            +
                             when :string then String
         
     | 
| 
      
 36 
     | 
    
         
            +
                             when :json   then JSON
         
     | 
| 
      
 37 
     | 
    
         
            +
                             when :bson   then BSON
         
     | 
| 
      
 38 
     | 
    
         
            +
                             else raise "Invalid marshal strategy: #{options[:marshal]}"
         
     | 
| 
      
 39 
     | 
    
         
            +
                           end
         
     | 
| 
      
 40 
     | 
    
         
            +
                  elsif marshal_option.respond_to?(:marshal_type)
         
     | 
| 
      
 41 
     | 
    
         
            +
                    return marshal_option
         
     | 
| 
      
 42 
     | 
    
         
            +
                  else
         
     | 
| 
      
 43 
     | 
    
         
            +
                    raise "Invalid marshal strategy: #{marshal_option}"
         
     | 
| 
      
 44 
     | 
    
         
            +
                  end
         
     | 
| 
      
 45 
     | 
    
         
            +
                end
         
     | 
| 
      
 46 
     | 
    
         
            +
              end
         
     | 
| 
      
 47 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,31 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module ModernTimes
         
     | 
| 
      
 2 
     | 
    
         
            +
              module MarshalStrategy
         
     | 
| 
      
 3 
     | 
    
         
            +
                module BSON
         
     | 
| 
      
 4 
     | 
    
         
            +
                  extend self
         
     | 
| 
      
 5 
     | 
    
         
            +
                  
         
     | 
| 
      
 6 
     | 
    
         
            +
                  def marshal_type
         
     | 
| 
      
 7 
     | 
    
         
            +
                    :bytes
         
     | 
| 
      
 8 
     | 
    
         
            +
                  end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 11 
     | 
    
         
            +
                    require 'bson'
         
     | 
| 
      
 12 
     | 
    
         
            +
                    def marshal(object)
         
     | 
| 
      
 13 
     | 
    
         
            +
                      ::BSON.serialize(object).to_s
         
     | 
| 
      
 14 
     | 
    
         
            +
                    end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                    def unmarshal(msg)
         
     | 
| 
      
 17 
     | 
    
         
            +
                      ::BSON.deserialize(msg)
         
     | 
| 
      
 18 
     | 
    
         
            +
                    end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                  rescue LoadError => e
         
     | 
| 
      
 21 
     | 
    
         
            +
                    def marshal(object)
         
     | 
| 
      
 22 
     | 
    
         
            +
                      raise 'Error: BSON marshaling specified but bson gem has not been installed'
         
     | 
| 
      
 23 
     | 
    
         
            +
                    end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                    def unmarshal(msg)
         
     | 
| 
      
 26 
     | 
    
         
            +
                      raise 'Error: BSON marshaling specified but bson gem has not been installed'
         
     | 
| 
      
 27 
     | 
    
         
            +
                    end
         
     | 
| 
      
 28 
     | 
    
         
            +
                  end
         
     | 
| 
      
 29 
     | 
    
         
            +
                end
         
     | 
| 
      
 30 
     | 
    
         
            +
              end
         
     | 
| 
      
 31 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,30 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module ModernTimes
         
     | 
| 
      
 2 
     | 
    
         
            +
              module MarshalStrategy
         
     | 
| 
      
 3 
     | 
    
         
            +
                module JSON
         
     | 
| 
      
 4 
     | 
    
         
            +
                  extend self
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                  def marshal_type
         
     | 
| 
      
 7 
     | 
    
         
            +
                    :text
         
     | 
| 
      
 8 
     | 
    
         
            +
                  end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 11 
     | 
    
         
            +
                    require 'json'
         
     | 
| 
      
 12 
     | 
    
         
            +
                    def marshal(object)
         
     | 
| 
      
 13 
     | 
    
         
            +
                      object.to_json
         
     | 
| 
      
 14 
     | 
    
         
            +
                    end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                    def unmarshal(msg)
         
     | 
| 
      
 17 
     | 
    
         
            +
                      ::JSON::Parser.new(msg).parse
         
     | 
| 
      
 18 
     | 
    
         
            +
                    end
         
     | 
| 
      
 19 
     | 
    
         
            +
                  rescue LoadError => e
         
     | 
| 
      
 20 
     | 
    
         
            +
                    def marshal(object)
         
     | 
| 
      
 21 
     | 
    
         
            +
                      raise 'Error: JSON marshaling specified but json gem has not been installed'
         
     | 
| 
      
 22 
     | 
    
         
            +
                    end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                    def unmarshal(msg)
         
     | 
| 
      
 25 
     | 
    
         
            +
                      raise 'Error: JSON marshaling specified but json gem has not been installed'
         
     | 
| 
      
 26 
     | 
    
         
            +
                    end
         
     | 
| 
      
 27 
     | 
    
         
            +
                  end
         
     | 
| 
      
 28 
     | 
    
         
            +
                end
         
     | 
| 
      
 29 
     | 
    
         
            +
              end
         
     | 
| 
      
 30 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,20 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module ModernTimes
         
     | 
| 
      
 2 
     | 
    
         
            +
              module MarshalStrategy
         
     | 
| 
      
 3 
     | 
    
         
            +
                module Ruby
         
     | 
| 
      
 4 
     | 
    
         
            +
                  extend self
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                  def marshal_type
         
     | 
| 
      
 7 
     | 
    
         
            +
                    :bytes
         
     | 
| 
      
 8 
     | 
    
         
            +
                  end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  def marshal(object)
         
     | 
| 
      
 11 
     | 
    
         
            +
                    ::Marshal.dump(object)
         
     | 
| 
      
 12 
     | 
    
         
            +
                  end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                  def unmarshal(msg)
         
     | 
| 
      
 15 
     | 
    
         
            +
                    msg = ::String.from_java_bytes(msg) unless msg.kind_of?(::String)
         
     | 
| 
      
 16 
     | 
    
         
            +
                    ::Marshal.load(msg)
         
     | 
| 
      
 17 
     | 
    
         
            +
                  end
         
     | 
| 
      
 18 
     | 
    
         
            +
                end
         
     | 
| 
      
 19 
     | 
    
         
            +
              end
         
     | 
| 
      
 20 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -1,20 +1,22 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            module ModernTimes
         
     | 
| 
       2 
2 
     | 
    
         
             
              module Railsable
         
     | 
| 
       3 
3 
     | 
    
         
             
                def init_rails
         
     | 
| 
       4 
     | 
    
         
            -
                  if cfg = YAML.load_file(File.join(Rails.root, "config", " 
     | 
| 
      
 4 
     | 
    
         
            +
                  if @cfg = YAML.load_file(File.join(Rails.root, "config", "jms.yml"))[Rails.env]
         
     | 
| 
       5 
5 
     | 
    
         
             
                    ModernTimes.logger.info "Messaging Enabled"
         
     | 
| 
       6 
     | 
    
         
            -
                    ModernTimes:: 
     | 
| 
       7 
     | 
    
         
            -
                    @ 
     | 
| 
      
 6 
     | 
    
         
            +
                    ModernTimes::JMS::Connection.init(@cfg)
         
     | 
| 
      
 7 
     | 
    
         
            +
                    @is_jms_enabled = true
         
     | 
| 
       8 
8 
     | 
    
         | 
| 
       9 
     | 
    
         
            -
                    # Need to start the  
     | 
| 
       10 
     | 
    
         
            -
                     
     | 
| 
       11 
     | 
    
         
            -
             
     | 
| 
      
 9 
     | 
    
         
            +
                    # Need to start the JMS Server in this VM
         
     | 
| 
      
 10 
     | 
    
         
            +
                    # TODO: Still want to support this?
         
     | 
| 
      
 11 
     | 
    
         
            +
                    if false
         
     | 
| 
      
 12 
     | 
    
         
            +
                    #if ModernTimes::JMS::Connection.invm?
         
     | 
| 
      
 13 
     | 
    
         
            +
                      @server = ::JMS::Server.create_server('vm://127.0.0.1')
         
     | 
| 
       12 
14 
     | 
    
         
             
                      @server.start
         
     | 
| 
       13 
15 
     | 
    
         | 
| 
       14 
16 
     | 
    
         
             
                      # Handle messages within this process
         
     | 
| 
       15 
17 
     | 
    
         
             
                      @manager = ModernTimes::Manager.new
         
     | 
| 
       16 
18 
     | 
    
         
             
                      # TODO: Formatting of configured workers in invm state with name and options
         
     | 
| 
       17 
     | 
    
         
            -
                      if worker_cfg = cfg[:workers]
         
     | 
| 
      
 19 
     | 
    
         
            +
                      if worker_cfg = @cfg[:workers]
         
     | 
| 
       18 
20 
     | 
    
         
             
                        worker_cfg.each do |klass, count|
         
     | 
| 
       19 
21 
     | 
    
         
             
                          @manager.add(klass, count, {})
         
     | 
| 
       20 
22 
     | 
    
         
             
                        end
         
     | 
| 
         @@ -38,20 +40,19 @@ module ModernTimes 
     | 
|
| 
       38 
40 
     | 
    
         | 
| 
       39 
41 
     | 
    
         
             
                  else
         
     | 
| 
       40 
42 
     | 
    
         
             
                    Rails.logger.info "Messaging disabled"
         
     | 
| 
       41 
     | 
    
         
            -
                    @ 
     | 
| 
       42 
     | 
    
         
            -
                    ModernTimes:: 
     | 
| 
      
 43 
     | 
    
         
            +
                    @is_jms_enabled = false
         
     | 
| 
      
 44 
     | 
    
         
            +
                    ModernTimes::JMS::Publisher.setup_dummy_publishing(rails_workers)
         
     | 
| 
      
 45 
     | 
    
         
            +
                    ModernTimes::JMSRequestor::Requestor.setup_dummy_publishing(rails_workers)
         
     | 
| 
       43 
46 
     | 
    
         
             
                  end
         
     | 
| 
       44 
47 
     | 
    
         
             
                end
         
     | 
| 
       45 
48 
     | 
    
         | 
| 
       46 
49 
     | 
    
         
             
                def create_rails_manager
         
     | 
| 
       47 
     | 
    
         
            -
                   
     | 
| 
       48 
     | 
    
         
            -
                  raise  
     | 
| 
       49 
     | 
    
         
            -
                  ModernTimes::HornetQ::Client.init(cfg)
         
     | 
| 
       50 
     | 
    
         
            -
             
     | 
| 
      
 50 
     | 
    
         
            +
                  raise 'init_rails has not been called, modify your config/environment.rb to include this call' if @is_jms_enabled.nil?
         
     | 
| 
      
 51 
     | 
    
         
            +
                  raise 'Messaging is not enabled, modify your config/jms.yml file' unless @is_jms_enabled
         
     | 
| 
       51 
52 
     | 
    
         
             
                  manager = ModernTimes::Manager.new
         
     | 
| 
       52 
53 
     | 
    
         
             
                  manager.stop_on_signal
         
     | 
| 
       53 
54 
     | 
    
         
             
                  manager.allowed_workers = rails_workers
         
     | 
| 
       54 
     | 
    
         
            -
                  manager.persist_file = cfg[:persist_file] || File.join(Rails.root, "log", "modern_times.persist")
         
     | 
| 
      
 55 
     | 
    
         
            +
                  manager.persist_file = @cfg[:persist_file] || File.join(Rails.root, "log", "modern_times.persist")
         
     | 
| 
       55 
56 
     | 
    
         
             
                  return manager
         
     | 
| 
       56 
57 
     | 
    
         
             
                end
         
     | 
| 
       57 
58 
     | 
    
         | 
| 
         @@ -68,66 +69,8 @@ module ModernTimes 
     | 
|
| 
       68 
69 
     | 
    
         
             
                  #raise "No worker config file #{file}" unless File.exist?(file)
         
     | 
| 
       69 
70 
     | 
    
         
             
                end
         
     | 
| 
       70 
71 
     | 
    
         | 
| 
       71 
     | 
    
         
            -
                def  
     | 
| 
       72 
     | 
    
         
            -
                  @ 
     | 
| 
      
 72 
     | 
    
         
            +
                def jms_enabled?
         
     | 
| 
      
 73 
     | 
    
         
            +
                  @is_jms_enabled
         
     | 
| 
       73 
74 
     | 
    
         
             
                end
         
     | 
| 
       74 
75 
     | 
    
         
             
              end
         
     | 
| 
       75 
76 
     | 
    
         
             
            end
         
     | 
| 
       76 
     | 
    
         
            -
             
     | 
| 
       77 
     | 
    
         
            -
             
     | 
| 
       78 
     | 
    
         
            -
            ## Protocol independent class to handle Messaging and Queuing
         
     | 
| 
       79 
     | 
    
         
            -
            #module Messaging
         
     | 
| 
       80 
     | 
    
         
            -
            #  class Client
         
     | 
| 
       81 
     | 
    
         
            -
            #
         
     | 
| 
       82 
     | 
    
         
            -
            #    # Publish to the specified address
         
     | 
| 
       83 
     | 
    
         
            -
            #    #   If the supplied object is kind_of? String, then a string is published
         
     | 
| 
       84 
     | 
    
         
            -
            #    #   Otherwise the Ruby Object is unmarshaled and sent as a Binary message
         
     | 
| 
       85 
     | 
    
         
            -
            #
         
     | 
| 
       86 
     | 
    
         
            -
            #    # Asynchronously invoke the supplied method
         
     | 
| 
       87 
     | 
    
         
            -
            #    #
         
     | 
| 
       88 
     | 
    
         
            -
            #    # Example:
         
     | 
| 
       89 
     | 
    
         
            -
            #    #   Messaging::Client.async(Dashboard, :update_dashboard_for_inquiry, xml_response)
         
     | 
| 
       90 
     | 
    
         
            -
            #    def self.async(klass, method, *param)
         
     | 
| 
       91 
     | 
    
         
            -
            #      @@session_pool.producer(self.async_address) do |session, producer|
         
     | 
| 
       92 
     | 
    
         
            -
            #        request = AsyncRequest.new
         
     | 
| 
       93 
     | 
    
         
            -
            #        request.klass = if klass.kind_of?(String)
         
     | 
| 
       94 
     | 
    
         
            -
            #          klass
         
     | 
| 
       95 
     | 
    
         
            -
            #        elsif klass.kind_of?(Symbol)
         
     | 
| 
       96 
     | 
    
         
            -
            #          klass.to_s
         
     | 
| 
       97 
     | 
    
         
            -
            #        else
         
     | 
| 
       98 
     | 
    
         
            -
            #          klass.name.to_s
         
     | 
| 
       99 
     | 
    
         
            -
            #        end
         
     | 
| 
       100 
     | 
    
         
            -
            #        request.method = method
         
     | 
| 
       101 
     | 
    
         
            -
            #        request.params = *param
         
     | 
| 
       102 
     | 
    
         
            -
            #        message = session.create_message(4,false) #HornetQ::Client::Message::BYTES_TYPE
         
     | 
| 
       103 
     | 
    
         
            -
            #        message['format'] = 'ruby'
         
     | 
| 
       104 
     | 
    
         
            -
            #        message.body = Marshal.dump(request)
         
     | 
| 
       105 
     | 
    
         
            -
            #        producer.send(message)
         
     | 
| 
       106 
     | 
    
         
            -
            #      end
         
     | 
| 
       107 
     | 
    
         
            -
            #    end
         
     | 
| 
       108 
     | 
    
         
            -
            #
         
     | 
| 
       109 
     | 
    
         
            -
            #    private
         
     | 
| 
       110 
     | 
    
         
            -
            #    # Call the specified class passing in the required parameters
         
     | 
| 
       111 
     | 
    
         
            -
            #    # If the method matches a class method, it is called, otherwise
         
     | 
| 
       112 
     | 
    
         
            -
            #    # an instance of the class is created and the method is called
         
     | 
| 
       113 
     | 
    
         
            -
            #    # on the new instance
         
     | 
| 
       114 
     | 
    
         
            -
            #    #
         
     | 
| 
       115 
     | 
    
         
            -
            #    # Note: Instance methods are more expensive because the class is instantiated
         
     | 
| 
       116 
     | 
    
         
            -
            #    #       for every call
         
     | 
| 
       117 
     | 
    
         
            -
            #    def self.async_on_message(request)
         
     | 
| 
       118 
     | 
    
         
            -
            #      klass = request.klass.constantize
         
     | 
| 
       119 
     | 
    
         
            -
            #      method = request.method.to_sym
         
     | 
| 
       120 
     | 
    
         
            -
            #      if klass.respond_to?(method, false)
         
     | 
| 
       121 
     | 
    
         
            -
            #        klass.send(method, *request.params)
         
     | 
| 
       122 
     | 
    
         
            -
            #      else
         
     | 
| 
       123 
     | 
    
         
            -
            #        klass.new.send(method, *request.params)
         
     | 
| 
       124 
     | 
    
         
            -
            #      end
         
     | 
| 
       125 
     | 
    
         
            -
            #    end
         
     | 
| 
       126 
     | 
    
         
            -
            #
         
     | 
| 
       127 
     | 
    
         
            -
            #    # Passed as the request message, used to hold all required parameters
         
     | 
| 
       128 
     | 
    
         
            -
            #    class AsyncRequest
         
     | 
| 
       129 
     | 
    
         
            -
            #      attr_accessor :klass, :method, :params
         
     | 
| 
       130 
     | 
    
         
            -
            #    end
         
     | 
| 
       131 
     | 
    
         
            -
            #
         
     | 
| 
       132 
     | 
    
         
            -
            #  end
         
     | 
| 
       133 
     | 
    
         
            -
            #end
         
     |