acts_as_executor 1.0.0.beta1

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/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (C) 2011 by Phil Ostler
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
@@ -0,0 +1,50 @@
1
+ =acts_as_executor
2
+ acts_as_executor seamlessly integrates Java's Executor framework with JRuby on Rails, giving an application the ability to interact with executors in a familiar Rails'eque way.
3
+
4
+ ==Features
5
+ * Database persisted, scheduled executor and task configurations
6
+
7
+ ==Getting Started
8
+ Rails 3 Gemfile
9
+ gem "acts_as_executor"
10
+ Install via
11
+ gem install acts_as_executor
12
+ # or
13
+ bundle install
14
+
15
+ ====Generate & Migrate
16
+ rails generate executor <ModelName>
17
+
18
+ e.g.
19
+ rails generate executor Executor
20
+ create app/models/executor.rb
21
+ create app/models/executor_task.rb
22
+ create db/migrate/20110523205511_create_executors.rb
23
+ rake db:migrate
24
+
25
+ ====Seed
26
+ e = Executor.create(:name => "background_processing",
27
+ :kind => ActsAsExecutor::Executor::Kinds::SCHEDULED,
28
+ :size => 4)
29
+ e.tasks.create(:clazz => "HelloWorldTask",
30
+ :arguments => { :message => "This is my argument message" },
31
+ :schedule => ActsAsExecutor::Task::Schedules::FIXED_DELAY,
32
+ :start => 1,
33
+ :every => 5,
34
+ :units => ActsAsExecutor::Common::Units::SECONDS)
35
+
36
+ ====Example Task
37
+ class HelloWorldTask
38
+ include Java::java.lang.Runnable
39
+
40
+ attr_accessor :message
41
+
42
+ def run
43
+ p "Hello World. " + message
44
+ end
45
+ end
46
+
47
+ ==What's New in Release 1.0.0.beta1
48
+ * Automatic startup only on Rails start. e.g. rake tasks don't trigger executor startup
49
+ * Arguments can now be passed to tasks
50
+ * Logging to <tt>Rails.logger</tt>
@@ -0,0 +1,35 @@
1
+ require "acts_as_executor/common/units"
2
+
3
+ require "acts_as_executor/executor/factory"
4
+ require "acts_as_executor/executor/kinds"
5
+
6
+ require "acts_as_executor/executor/model/actions"
7
+ require "acts_as_executor/executor/model/associations"
8
+ require "acts_as_executor/executor/model/attributes"
9
+ require "acts_as_executor/executor/model/base"
10
+ require "acts_as_executor/executor/model/helpers"
11
+ require "acts_as_executor/executor/model/validations"
12
+
13
+ require "acts_as_executor/task/schedules"
14
+
15
+ require "acts_as_executor/task/model/actions"
16
+ require "acts_as_executor/task/model/associations"
17
+ require "acts_as_executor/task/model/base"
18
+ require "acts_as_executor/task/model/validations"
19
+
20
+ require "acts_as_executor/validators/class_exists_validator"
21
+
22
+ ActiveRecord::Base.send :extend, ActsAsExecutor::Executor::Model::Base
23
+ ActiveRecord::Base.send :extend, ActsAsExecutor::Task::Model::Base
24
+
25
+ module ActsAsExecutor
26
+ def self.log
27
+ logger
28
+ end
29
+ def self.logger
30
+ @@logger ||= Rails.logger
31
+ end
32
+ def self.rails_startup?
33
+ File.basename($0) == "rails"
34
+ end
35
+ end
@@ -0,0 +1,15 @@
1
+ module ActsAsExecutor
2
+ module Common
3
+ class Units
4
+ NANOSECONDS = "nanoseconds"
5
+ MICROSECONDS = "microseconds"
6
+ MILLISECONDS = "milliseconds"
7
+ SECONDS = "seconds"
8
+ MINUTES = "minutes"
9
+ HOURS = "hours"
10
+ DAYS = "days"
11
+
12
+ ALL = [ NANOSECONDS, MICROSECONDS, MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS ]
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,18 @@
1
+ module ActsAsExecutor
2
+ module Executor
3
+ class Factory
4
+ def self.create kind, size = nil
5
+ case kind
6
+ when ActsAsExecutor::Executor::Kinds::SCHEDULED
7
+ raise TypeError, "size cannot be nil" unless size
8
+ raise ArgumentError, "size must be larger than 0" unless size.to_i > 0
9
+ return Java::java.util.concurrent.Executors.new_scheduled_thread_pool size.to_i
10
+ when ActsAsExecutor::Executor::Kinds::SINGLE_SCHEDULED
11
+ return Java::java.util.concurrent.Executors.new_single_thread_scheduled_executor
12
+ else
13
+ return nil
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,12 @@
1
+ module ActsAsExecutor
2
+ module Executor
3
+ class Kinds
4
+ SCHEDULED = "scheduled"
5
+ SINGLE_SCHEDULED = "single_scheduled"
6
+
7
+ ALL = [ SCHEDULED, SINGLE_SCHEDULED ]
8
+ ALL_SCHEDULED = [ SCHEDULED, SINGLE_SCHEDULED ]
9
+ REQUIRING_SIZE = [ SCHEDULED ]
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,73 @@
1
+ module ActsAsExecutor
2
+ module Executor
3
+ module Model
4
+ module Actions
5
+ def self.included base
6
+ base.after_find :startup, :if => "ActsAsExecutor.rails_startup?"
7
+ base.after_destroy :shutdown
8
+ end
9
+
10
+ def startup
11
+ unless self.executor
12
+ ActsAsExecutor.log.debug "Executor \"" + name + "\" starting up..."
13
+ self.executor = ActsAsExecutor::Executor::Factory.create kind, size
14
+ ActsAsExecutor.log.info "Executor \"" + name + "\" has completed startup"
15
+
16
+ ActsAsExecutor.log.debug "Executor \"" + name + "\" attaching tasks..."
17
+ tasks.each do |t|
18
+ submit t
19
+ end
20
+ ActsAsExecutor.log.info "Executor \"" + name + "\" has completed attaching tasks"
21
+ end
22
+ end
23
+
24
+ def shutdown
25
+ if self.executor
26
+ ActsAsExecutor.log.debug "Executor \"" + name + "\" shutting down..."
27
+ begin
28
+ self.executor.shutdown
29
+ rescue Java::java.lang.RuntimePermission
30
+ ActsAsExecutor.log.error "Executor \"" + name + "\" has experienced a RuntimePermission error"
31
+ rescue Java::java.lang.SecurityException
32
+ ActsAsExecutor.log.error "Executor \"" + name + "\" has experienced a SecurityException error"
33
+ end
34
+ ActsAsExecutor.log.info "Executor \"" + name + "\" has completed shutdown"
35
+ end
36
+ end
37
+
38
+ def submit task
39
+ begin
40
+ clazz = task.clazz.constantize.new
41
+ rescue NameError
42
+ ActsAsExecutor.log.error "Executor \"" + name + "\" attaching task \"" + task.clazz + "\" could not create class"
43
+ end
44
+
45
+ if task.arguments
46
+ task.arguments.each_pair do |k, v|
47
+ attribute = "#{k}="
48
+ clazz.send attribute, v if clazz.respond_to? attribute
49
+ end
50
+ end
51
+
52
+ begin
53
+ units = Java::java.util.concurrent.TimeUnit.value_of(task.units.upcase)
54
+ case task.schedule
55
+ when ActsAsExecutor::Task::Schedules::ONE_SHOT
56
+ self.executor.schedule clazz, task.start, units
57
+ when ActsAsExecutor::Task::Schedules::FIXED_DELAY
58
+ self.executor.schedule_with_fixed_delay clazz, task.start, task.every, units
59
+ when ActsAsExecutor::Task::Schedules::FIXED_RATE
60
+ self.executor.schedule_at_fixed_rate clazz, task.start, task.every, units
61
+ end
62
+ rescue Java::java.lang.NullPointerException
63
+ ActsAsExecutor.log.error "Executor \"" + name + "\" attaching task \"" + task.clazz + "\" threw a NullPointerException"
64
+ rescue Java::java.lang.IllegalArgumentException
65
+ ActsAsExecutor.log.error "Executor \"" + name + "\" attaching task \"" + task.clazz + "\" threw a IllegalArgumentException"
66
+ rescue Java::java.util.concurrent.RejectedExecutionException
67
+ ActsAsExecutor.log.error "Executor \"" + name + "\" attaching task \"" + task.clazz + "\" threw a RejectedExecutionException"
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,11 @@
1
+ module ActsAsExecutor
2
+ module Executor
3
+ module Model
4
+ module Associations
5
+ def self.included base
6
+ base.has_many :tasks, :class_name => base.table_name.singularize.camelize + "Task", :foreign_key => "executor_id"
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,16 @@
1
+ module ActsAsExecutor
2
+ module Executor
3
+ module Model
4
+ module Attributes
5
+ @@executors = Hash.new
6
+
7
+ def executor
8
+ @@executors[id]
9
+ end
10
+ def executor= executor
11
+ @@executors[id] = executor
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,24 @@
1
+ module ActsAsExecutor
2
+ module Executor
3
+ module Model
4
+ module Base
5
+ def acts_as_executor
6
+ send :include, ActsAsExecutor::Executor::Model::Actions
7
+ send :include, ActsAsExecutor::Executor::Model::Associations
8
+ send :include, ActsAsExecutor::Executor::Model::Attributes
9
+ send :include, ActsAsExecutor::Executor::Model::Helpers
10
+ send :include, ActsAsExecutor::Executor::Model::Validations
11
+
12
+ if ActsAsExecutor.rails_startup?
13
+ all
14
+ at_exit do
15
+ all.each do |e|
16
+ e.shutdown
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,11 @@
1
+ module ActsAsExecutor
2
+ module Executor
3
+ module Model
4
+ module Helpers
5
+ def schedulable?
6
+ ActsAsExecutor::Executor::Kinds::ALL_SCHEDULED.include? kind
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,13 @@
1
+ module ActsAsExecutor
2
+ module Executor
3
+ module Model
4
+ module Validations
5
+ def self.included base
6
+ base.validates :name, :presence => true, :uniqueness => true
7
+ base.validates :kind, :inclusion => { :in => ActsAsExecutor::Executor::Kinds::ALL }
8
+ base.validates :size, :numericality => { :only_integer => true, :greater_than_or_equal_to => 1 }, :if => "ActsAsExecutor::Executor::Kinds::REQUIRING_SIZE.include? kind"
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,11 @@
1
+ module ActsAsExecutor
2
+ module Task
3
+ module Model
4
+ module Actions
5
+ def self.included base
6
+ base.serialize :arguments, Hash
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module ActsAsExecutor
2
+ module Task
3
+ module Model
4
+ module Associations
5
+ def self.included base
6
+ base.belongs_to :executor, :class_name => base.table_name.sub(/_tasks/, "").camelize
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,13 @@
1
+ module ActsAsExecutor
2
+ module Task
3
+ module Model
4
+ module Base
5
+ def acts_as_executor_task
6
+ send :include, ActsAsExecutor::Task::Model::Associations
7
+ send :include, ActsAsExecutor::Task::Model::Actions
8
+ send :include, ActsAsExecutor::Task::Model::Validations
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,16 @@
1
+ module ActsAsExecutor
2
+ module Task
3
+ module Model
4
+ module Validations
5
+ def self.included base
6
+ base.validates :executor_id, :presence => true
7
+ base.validates :clazz, :presence => true, :class_exists => true
8
+ base.validates :schedule, :inclusion => { :in => ActsAsExecutor::Task::Schedules::ALL }, :if => "executor and executor.schedulable?"
9
+ base.validates :start, :numericality => { :only_integer => true, :greater_than_or_equal_to => 0 }, :if => "executor and executor.schedulable?"
10
+ base.validates :every, :numericality => { :only_integer => true, :greater_than_or_equal_to => 1 }, :if => "executor and executor.schedulable? and schedule != ActsAsExecutor::Task::Schedules::ONE_SHOT"
11
+ base.validates :units, :inclusion => { :in => ActsAsExecutor::Common::Units::ALL }, :if => "executor and executor.schedulable?"
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,11 @@
1
+ module ActsAsExecutor
2
+ module Task
3
+ class Schedules
4
+ ONE_SHOT = "one_shot"
5
+ FIXED_DELAY = "fixed_delay"
6
+ FIXED_RATE = "fixed_rate"
7
+
8
+ ALL = [ ONE_SHOT, FIXED_DELAY, FIXED_RATE ]
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,9 @@
1
+ class ClassExistsValidator < ActiveModel::EachValidator
2
+ def validate_each record, attribute, value
3
+ begin
4
+ value.constantize.new
5
+ rescue NameError
6
+ record.errors[attribute] << "does not exist as a Class"
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,3 @@
1
+ module ActsAsExecutor
2
+ VERSION = "1.0.0.beta1"
3
+ end
@@ -0,0 +1,18 @@
1
+ class ExecutorGenerator < Rails::Generators::NamedBase
2
+ include Rails::Generators::Migration
3
+
4
+ source_root File.expand_path("../templates", __FILE__)
5
+
6
+ def models
7
+ template File.join("models", "executor.rb"), File.join("app", "models", file_name + ".rb")
8
+ template File.join("models", "executor_task.rb"), File.join("app", "models", file_name + "_task.rb")
9
+ end
10
+
11
+ def migration
12
+ migration_template File.join("migration", "create_executors.rb"), File.join("db", "migrate", "create_" + table_name + ".rb")
13
+ end
14
+
15
+ def self.next_migration_number dirname
16
+ Time.now.utc.strftime "%Y%m%d%H%M%S"
17
+ end
18
+ end
@@ -0,0 +1,26 @@
1
+ class Create<%= class_name.pluralize %> < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :<%= table_name %> do |t|
4
+ t.string :name
5
+ t.string :kind
6
+ t.integer :size
7
+ t.timestamps
8
+ end
9
+
10
+ create_table :<%= singular_table_name %>_tasks do |t|
11
+ t.integer :executor_id
12
+ t.string :clazz
13
+ t.string :arguments
14
+ t.string :schedule
15
+ t.integer :start
16
+ t.integer :every
17
+ t.string :units
18
+ t.timestamps
19
+ end
20
+ end
21
+
22
+ def self.down
23
+ drop_table :<%= table_name %>
24
+ drop_table :<%= singular_table_name %>_tasks
25
+ end
26
+ end
@@ -0,0 +1,3 @@
1
+ class <%= class_name %> < ActiveRecord::Base
2
+ acts_as_executor
3
+ end
@@ -0,0 +1,3 @@
1
+ class <%= class_name %>Task < ActiveRecord::Base
2
+ acts_as_executor_task
3
+ end
metadata ADDED
@@ -0,0 +1,79 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: acts_as_executor
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: 6
5
+ version: 1.0.0.beta1
6
+ platform: ruby
7
+ authors:
8
+ - Phil Ostler
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-05-24 00:00:00 +01:00
14
+ default_executable:
15
+ dependencies: []
16
+
17
+ description: Seamless integration of Java's Executor framework with JRuby on Rails
18
+ email:
19
+ - philostler@gmail.com
20
+ executables: []
21
+
22
+ extensions: []
23
+
24
+ extra_rdoc_files: []
25
+
26
+ files:
27
+ - lib/acts_as_executor.rb
28
+ - lib/acts_as_executor/version.rb
29
+ - lib/acts_as_executor/common/units.rb
30
+ - lib/acts_as_executor/executor/factory.rb
31
+ - lib/acts_as_executor/executor/kinds.rb
32
+ - lib/acts_as_executor/executor/model/actions.rb
33
+ - lib/acts_as_executor/executor/model/associations.rb
34
+ - lib/acts_as_executor/executor/model/attributes.rb
35
+ - lib/acts_as_executor/executor/model/base.rb
36
+ - lib/acts_as_executor/executor/model/helpers.rb
37
+ - lib/acts_as_executor/executor/model/validations.rb
38
+ - lib/acts_as_executor/task/schedules.rb
39
+ - lib/acts_as_executor/task/model/actions.rb
40
+ - lib/acts_as_executor/task/model/associations.rb
41
+ - lib/acts_as_executor/task/model/base.rb
42
+ - lib/acts_as_executor/task/model/validations.rb
43
+ - lib/acts_as_executor/validators/class_exists_validator.rb
44
+ - lib/generators/executor_generator.rb
45
+ - lib/generators/templates/migration/create_executors.rb
46
+ - lib/generators/templates/models/executor.rb
47
+ - lib/generators/templates/models/executor_task.rb
48
+ - README.rdoc
49
+ - LICENSE
50
+ has_rdoc: true
51
+ homepage: https://github.com/philostler/acts_as_executor
52
+ licenses: []
53
+
54
+ post_install_message:
55
+ rdoc_options: []
56
+
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ none: false
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: "0"
65
+ required_rubygems_version: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ">"
69
+ - !ruby/object:Gem::Version
70
+ version: 1.3.1
71
+ requirements: []
72
+
73
+ rubyforge_project:
74
+ rubygems_version: 1.5.1
75
+ signing_key:
76
+ specification_version: 3
77
+ summary: Java Executor framework integration for Rails
78
+ test_files: []
79
+