Module: TrinidadScheduler

Defined in:
lib/trinidad_scheduler_extension/app_job.rb,
lib/trinidad_scheduler_extension/version.rb,
lib/trinidad_scheduler_extension/job_detail.rb,
lib/trinidad_scheduler_extension/job_factory.rb,
lib/trinidad_scheduler_extension/scheduled_job.rb,
lib/trinidad_scheduler_extension/scheduler_listener.rb,
lib/trinidad_scheduler_extension/trinidad_scheduler.rb

Defined Under Namespace

Modules: AppJob, ScheduledJob Classes: GlobalListener, JobDetail, JobFactory, WebAppListener

Constant Summary collapse

VERSION =
"0.1.2"
CONFIG_HOME =
File.expand_path(File.dirname(__FILE__) + "/config")
JAR_HOME =
File.expand_path(File.dirname(__FILE__) + "/jars")

Class Method Summary collapse

Class Method Details

.[](context) ⇒ org.quartz.impl.StdScheduler

Bracket accessor defined to retreive the scheduler for a context if no scheduler is attached to the context then one is created and attached at time of access and returned

Parameters:

  • context (ServletContext)

Returns:

  • (org.quartz.impl.StdScheduler)


70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/trinidad_scheduler_extension/trinidad_scheduler.rb', line 70

def self.[](context)
  if !scheduler_exists?(context)
    self.trinidad_scheduler_init_log4j
    self[context] = self.quartz_scheduler(context, context.get_attribute(options_name(context)))
  end
  
  scheduler = context.get_attribute(scheduler_name(context)) 
  
  if !scheduler.is_started && servlet_started?(context)
    scheduler.start
    scheduler.resume_all
  end
  
  return scheduler
end

.[]=(context, scheduler) ⇒ Object

Bracket assignment operator, will attach the scheduler passed to the context in the brackets

Parameters:

  • context (ServletContext)
  • scheduler (org.quartz.impl.StdScheduler)


90
91
92
# File 'lib/trinidad_scheduler_extension/trinidad_scheduler.rb', line 90

def self.[]=(context, scheduler)
  context.set_attribute(scheduler_name(context), scheduler)
end

.context_path(path) ⇒ Object

Standardizing the naming of the variables that are stored on the context



14
15
16
# File 'lib/trinidad_scheduler_extension/trinidad_scheduler.rb', line 14

def self.context_path(path)
  path.gsub("/", "") == "" ? "Default" : path.gsub("/", "").capitalize
end

.Cron(cron_expression) ⇒ Class

Method to return an inheritable class for scheduling a CronTrigger Job the class that inherits from this method will have it’s instance run method executed based on the cron_expression

Examples:

Schedule an INFO log message every 5 seconds

class TestJob < TrinidadScheduler.Cron "0/5 * * * * ?"
  def run
    _logger.info "I am inside this block" #=> prints "I am inside this block" every 5 seconds
  end
end

Parameters:

  • cron_expression (String)

    the Cron Expression that defines the CronTrigger for the job class

Returns:

  • (Class)

    a new Class that is run by the CronTrigger that is defined



55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/trinidad_scheduler_extension/app_job.rb', line 55

def self.Cron(cron_expression)
  Class.new do
    meta_def(:cron){ cron_expression }
    
    def self.inherited(subclass) 
      meta_def :trigger do
        org.quartz.CronTrigger.new("#{subclass}" + ".trigger", "#{subclass}", self.cron)
      end

      subclass.send(:include, TrinidadScheduler::AppJob)
    end
  end  
end

.DateInterval(opts = {}) ⇒ Class

Method to return an inheritable class for scheduling a DateIntervalTrigger Job the class that inherits from this method will have it’s instance run method executed based on the options passed

Examples:

Schedule an INFO log message every 5 seconds starting now and ending after 4 minutes

class TestJob < TrinidadScheduler.DateInterval :start => Time.now, :end => Time.now + 240, :unit => :second, :interval => 5
  def run
    _logger.info "I am inside this block" #=> prints "I am inside this block" every 5 seconds
  end
end

Parameters:

  • opts (Hash) (defaults to: {})

    the options for the DateIntervalTrigger

Options Hash (opts):

  • :start (java.util.Date, Time)

    the starting time of the trigger

  • :end (java.util.Date, Time)

    the ending time of the trigger

  • :unit (Symbol, String)

    the defined unit (:day, :second, :year, :month, :week)

  • :interval (Integer)

    the number of units between runs

Returns:

  • (Class)

    a new anonymous Class that is the parent of the Class run by the SimpleTrigger that is defined



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/trinidad_scheduler_extension/app_job.rb', line 126

def self.DateInterval(opts={})    
  opts[:start] ||= java.util.Date.new(Time.now.to_i*1000)
  opts[:start] = java.util.Date.new(opts[:start].to_i*1000) if opts[:start].class == Time
  
  opts[:end] ||= java.util.Date.new((Time.now + 10.years).to_i*1000)
  opts[:end] = java.util.Date.new(opts[:end].to_i*1000) if opts[:end].class == Time
  
  opts[:unit] ||= :day
  opts[:unit] = org.quartz.DateIntervalTrigger::IntervalUnit.value_of(opts[:unit].to_s.upcase)

  opts[:interval] ||= 1
  
  Class.new do
    meta_def(:opts){ opts }

    def self.inherited(subclass) 
      meta_def :trigger do
        org.quartz.DateIntervalTrigger.new("#{subclass}" + ".trigger", "#{subclass}", 
                                           self.opts[:start], self.opts[:end], 
                                           self.opts[:unit], self.opts[:interval])        
      end
      
      subclass.send(:include, TrinidadScheduler::AppJob)
    end
  end  
end

.options_name(context) ⇒ Object



57
58
59
# File 'lib/trinidad_scheduler_extension/trinidad_scheduler.rb', line 57

def self.options_name(context)
  "TrinidadScheduler::#{context_path(context.context_path)}::SchedulerOptions"
end

.quartz_properties(opts = {}) ⇒ Object

Properties stream for initializing a scheduler Currently restricts schedulers to RAMJobStore and SimpleThreadPool



113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/trinidad_scheduler_extension/trinidad_scheduler.rb', line 113

def self.quartz_properties(opts={})
  prop_string = java.lang.String.new("
    org.quartz.scheduler.rmi.export = false
    org.quartz.scheduler.rmi.proxy = false
    org.quartz.scheduler.wrapJobExecutionInUserTransaction = #{opts[:wrapped]}
    org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
    org.quartz.threadPool.threadCount = #{opts[:thread_count]}
    org.quartz.threadPool.threadPriority = #{opts[:thread_priority]}
    org.quartz.threadPool.threadNamePrefix = WorkerThread::#{opts[:name]}
    org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true
    org.quartz.jobStore.misfireThreshold = 60000
    org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore")
  
  qp = java.util.Properties.new 
  qp.load(java.io.ByteArrayInputStream.new(prop_string.getBytes()))
  qp.set_property("org.quartz.scheduler.instanceName", "Quartz::#{opts[:name]}::Application")
  return qp
end

.quartz_scheduler(context, opts = {}) ⇒ Object

Method to build and return Quartz schedulers

Parameters:

  • context (ServletContext)
  • opts, (Hash)

    the options to configure the scheduler with



98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/trinidad_scheduler_extension/trinidad_scheduler.rb', line 98

def self.quartz_scheduler(context, opts={})
  options = {:wrapped => false, :thread_count => 10, :thread_priority => 5}
  options.merge!(opts)
  options[:name] = context_path(context.context_path)
  
  scheduler_factory = org.quartz.impl.StdSchedulerFactory.new
  scheduler_factory.initialize(quartz_properties(options))
  scheduler = scheduler_factory.get_scheduler
  scheduler.set_job_factory(TrinidadScheduler::JobFactory.new)
  scheduler.pause_all
  return scheduler
end

.run_later(opts = {:delay=>3}, &blk) ⇒ Object

Method to schedule a block of code to run in another Thread after execution proceeds in the current Thread after the job runs it removes itself from the job scheduler

Examples:

Running run_later with default 3 second delay

TrinidadScheduler.run_later do
  _logger.info "I am inside this block" #=> prints "I am inside this block" 
end

Running run_later with 20 second delay

TrinidadScheduler.run_later(:delay => 20) do
  _logger.info "I am inside this block" #=> prints "I am inside this block" 
end  

Parameters:

  • opts (Hash) (defaults to: {:delay=>3})

    the options for the process to be run

  • the (Block)

    block that will be run in a separate Thread after the delay

Options Hash (opts):

  • :delay (Integer)

    the number of seconds delay before the block is triggered



32
33
34
35
36
37
38
39
40
41
# File 'lib/trinidad_scheduler_extension/app_job.rb', line 32

def self.run_later(opts={:delay=>3}, &blk)
  Class.new(TrinidadScheduler.Simple :start => (Time.now + opts[:delay])) do 
    meta_def(:job_detail_name){ Time.now.to_i.to_s << Time.now.usec.to_s }
    meta_def(:run_proc){ blk }
    
    def run
      self.class.run_proc.call
    end  
  end
end

.scheduler_exists?(context) ⇒ Boolean

Assists in lazily evaluating if a scheduler is needed for a context

Parameters:

  • context (ServletContext)

Returns:

  • (Boolean)


22
23
24
# File 'lib/trinidad_scheduler_extension/trinidad_scheduler.rb', line 22

def self.scheduler_exists?(context)
  !!context.get_attribute(scheduler_name(context))
end

.scheduler_name(context) ⇒ Object



61
62
63
# File 'lib/trinidad_scheduler_extension/trinidad_scheduler.rb', line 61

def self.scheduler_name(context)
  "TrinidadScheduler::#{context_path(context.context_path)}::Scheduler"
end

.servlet_started?(context) ⇒ Boolean

Tomcat event callbacks are good for static systems but JRuby allows dynamic definition of classes and function so I am storing a variable on the servlet context that allow the extension to check if the servlet has been started during lazy evaluation of the need for a scheduler and/or starting the scheduler

Parameters:

  • context (ServletContext)

Returns:

  • (Boolean)


32
33
34
# File 'lib/trinidad_scheduler_extension/trinidad_scheduler.rb', line 32

def self.servlet_started?(context)
  !!context.get_attribute(started_name(context))
end

.set_servlet_started(context) ⇒ Object

Helper to centralize the operations on the servlet contexts, sets the servlet started variable when the context is started, reguardless of whether a scheduler exists or not

Parameters:

  • context (ServletContext)


40
41
42
# File 'lib/trinidad_scheduler_extension/trinidad_scheduler.rb', line 40

def self.set_servlet_started(context)
  context.set_attribute(started_name(context), true)
end

.Simple(opts = {}) ⇒ Class

Method to return an inheritable class for scheduling a SimpleTrigger Job the class that inherits from this method will have it’s instance run method executed based on the options passed

Examples:

Schedule an INFO log message every 5 seconds starting now, setting the end is not necessary in this context, but it done

class TestJob < TrinidadScheduler.Simple :start => Time.now, :end => Time.now + 240, :repeat 3, :interval => 5000
  def run
    _logger.info "I am inside this block" #=> prints "I am inside this block" every 5 seconds
  end
end

Parameters:

  • opts (Hash) (defaults to: {})

    the options for the SimpleTrigger

Options Hash (opts):

  • :start (java.util.Date, Time)

    the starting time of the trigger

  • :end (java.util.Date, Time)

    the ending time of the trigger

  • :repeat (Integer)

    the number of times to repeat the job (defaults to 0)

  • :interval (Integer)

    the number of milliseconds between runs

Returns:

  • (Class)

    a new anonymous Class that is the parent of the Class run by the SimpleTrigger that is defined



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/trinidad_scheduler_extension/app_job.rb', line 85

def self.Simple(opts={})    
  opts[:start] ||= java.util.Date.new(Time.now.to_i*1000)
  opts[:start] = java.util.Date.new(opts[:start].to_i*1000) if opts[:start].class == Time
  
  opts[:end] ||= java.util.Date.new((Time.now + 10.years).to_i*1000)
  opts[:end] = java.util.Date.new(opts[:end].to_i*1000) if opts[:end].class == Time
  
  opts[:repeat] ||= 0
  opts[:interval] ||= 0
  
  Class.new do
    meta_def(:opts){ opts }

    def self.inherited(subclass)
      meta_def :trigger do
        org.quartz.SimpleTrigger.new("#{subclass}" + ".trigger", "#{subclass}", 
                                     self.opts[:start], self.opts[:end], 
                                     self.opts[:repeat], self.opts[:interval])
      end 
      
      subclass.send(:include, TrinidadScheduler::AppJob)
    end
  end  
end

.started_name(context) ⇒ Object

Centralized definition of where variables will be stored on the ServletContext



53
54
55
# File 'lib/trinidad_scheduler_extension/trinidad_scheduler.rb', line 53

def self.started_name(context)
  "TrinidadScheduler::#{context_path(context.context_path)}::ServletStarted"
end

.store_scheduler_options(context, options) ⇒ Object

Helper method that attaches the configuration options from the Trinidad config file to the ServletContext

Parameters:

  • context (ServletContext)
  • options (Hash)


48
49
50
# File 'lib/trinidad_scheduler_extension/trinidad_scheduler.rb', line 48

def self.store_scheduler_options(context, options)
  context.set_attribute(options_name(context), options)
end

.trinidad_scheduler_init_log4jObject

Sets log4j properties if not established by Application Servers TrinidadScheduler is really lazy so this is only set when a scheduler is needed



7
8
9
10
11
# File 'lib/trinidad_scheduler_extension/trinidad_scheduler.rb', line 7

def self.trinidad_scheduler_init_log4j
  if java.lang.System.get_property('log4j.configuration').nil? 
    java.lang.System.set_property('log4j.configuration', java.io.File.new("#{CONFIG_HOME}/log4j.properties").to_url.to_s)
  end
end