acts_as_executor 1.0.0.beta1

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