coupler 0.0.1-java
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.gitmodules +3 -0
- data/.rvmrc +1 -0
- data/.vimrc +40 -0
- data/Gemfile +27 -0
- data/Gemfile.lock +71 -0
- data/LICENSE +20 -0
- data/NOTES +6 -0
- data/README.rdoc +18 -0
- data/Rakefile +42 -0
- data/TODO +11 -0
- data/VERSION +1 -0
- data/bin/coupler +7 -0
- data/db/.gitignore +6 -0
- data/db/migrate/001_initial_schema.rb +166 -0
- data/db/migrate/002_stub.rb +4 -0
- data/db/migrate/003_stub.rb +4 -0
- data/db/migrate/004_create_comparisons.rb +28 -0
- data/db/migrate/005_move_database_name.rb +19 -0
- data/db/migrate/006_upgrade_comparisons.rb +34 -0
- data/db/migrate/007_add_which_to_comparisons.rb +23 -0
- data/db/migrate/008_add_result_field_to_transformations.rb +33 -0
- data/db/migrate/009_add_generated_flag_to_fields.rb +13 -0
- data/db/migrate/010_create_imports.rb +24 -0
- data/db/migrate/011_add_primary_key_type.rb +13 -0
- data/db/migrate/012_add_transformed_with_to_resources.rb +13 -0
- data/db/migrate/013_add_run_count_to_scenarios.rb +13 -0
- data/db/migrate/014_add_last_accessed_at_to_some_tables.rb +13 -0
- data/db/migrate/015_add_run_number_to_results.rb +15 -0
- data/db/migrate/016_fix_scenario_run_count.rb +27 -0
- data/db/migrate/017_rename_comparison_columns.rb +14 -0
- data/db/migrate/018_fix_scenario_linkage_type.rb +8 -0
- data/db/migrate/019_add_columns_to_imports.rb +24 -0
- data/db/migrate/020_rename_import_columns.rb +12 -0
- data/db/migrate/021_add_fields_to_connections.rb +15 -0
- data/db/migrate/022_remove_database_name_from_resources.rb +11 -0
- data/features/connections.feature +28 -0
- data/features/matchers.feature +35 -0
- data/features/projects.feature +11 -0
- data/features/resources.feature +62 -0
- data/features/scenarios.feature +45 -0
- data/features/step_definitions/coupler_steps.rb +145 -0
- data/features/step_definitions/matchers_steps.rb +26 -0
- data/features/step_definitions/resources_steps.rb +12 -0
- data/features/step_definitions/scenarios_steps.rb +7 -0
- data/features/step_definitions/transformations_steps.rb +3 -0
- data/features/support/env.rb +128 -0
- data/features/transformations.feature +22 -0
- data/features/wizard.feature +10 -0
- data/gfx/coupler-header.svg +213 -0
- data/gfx/coupler-sidebar.svg +656 -0
- data/gfx/coupler.svg +184 -0
- data/gfx/icon.svg +75 -0
- data/lib/coupler/base.rb +63 -0
- data/lib/coupler/config.rb +128 -0
- data/lib/coupler/data_uploader.rb +20 -0
- data/lib/coupler/database.rb +31 -0
- data/lib/coupler/extensions/connections.rb +57 -0
- data/lib/coupler/extensions/exceptions.rb +58 -0
- data/lib/coupler/extensions/imports.rb +43 -0
- data/lib/coupler/extensions/jobs.rb +21 -0
- data/lib/coupler/extensions/matchers.rb +64 -0
- data/lib/coupler/extensions/projects.rb +62 -0
- data/lib/coupler/extensions/resources.rb +89 -0
- data/lib/coupler/extensions/results.rb +100 -0
- data/lib/coupler/extensions/scenarios.rb +50 -0
- data/lib/coupler/extensions/transformations.rb +70 -0
- data/lib/coupler/extensions/transformers.rb +58 -0
- data/lib/coupler/extensions.rb +16 -0
- data/lib/coupler/helpers.rb +121 -0
- data/lib/coupler/import_buffer.rb +48 -0
- data/lib/coupler/logger.rb +16 -0
- data/lib/coupler/models/common_model.rb +104 -0
- data/lib/coupler/models/comparison.rb +166 -0
- data/lib/coupler/models/connection.rb +59 -0
- data/lib/coupler/models/field.rb +55 -0
- data/lib/coupler/models/import.rb +238 -0
- data/lib/coupler/models/job.rb +42 -0
- data/lib/coupler/models/jobify.rb +17 -0
- data/lib/coupler/models/matcher.rb +36 -0
- data/lib/coupler/models/project.rb +40 -0
- data/lib/coupler/models/resource.rb +287 -0
- data/lib/coupler/models/result.rb +92 -0
- data/lib/coupler/models/scenario/runner.rb +357 -0
- data/lib/coupler/models/scenario.rb +115 -0
- data/lib/coupler/models/transformation.rb +117 -0
- data/lib/coupler/models/transformer/runner.rb +28 -0
- data/lib/coupler/models/transformer.rb +110 -0
- data/lib/coupler/models.rb +30 -0
- data/lib/coupler/runner.rb +76 -0
- data/lib/coupler/scheduler.rb +56 -0
- data/lib/coupler.rb +34 -0
- data/log/.gitignore +1 -0
- data/misc/README +5 -0
- data/misc/jruby-json.license +57 -0
- data/misc/rack-flash.license +22 -0
- data/script/dbconsole.rb +5 -0
- data/src/edu/vanderbilt/coupler/Main.java +116 -0
- data/src/edu/vanderbilt/coupler/jruby.properties +1 -0
- data/tasks/annotations.rake +84 -0
- data/tasks/db.rake +120 -0
- data/tasks/environment.rake +12 -0
- data/tasks/jeweler.rake +43 -0
- data/tasks/package.rake +58 -0
- data/tasks/rdoc.rake +13 -0
- data/tasks/test.rake +63 -0
- data/tasks/vendor.rake +43 -0
- data/test/README.txt +6 -0
- data/test/config.yml +9 -0
- data/test/coupler/models/test_import.rb +221 -0
- data/test/factories.rb +91 -0
- data/test/fixtures/duplicate-keys.csv +5 -0
- data/test/fixtures/no-headers.csv +50 -0
- data/test/fixtures/people.csv +51 -0
- data/test/fixtures/varying-row-size.csv +4 -0
- data/test/helper.rb +156 -0
- data/test/integration/extensions/test_connections.rb +80 -0
- data/test/integration/extensions/test_imports.rb +94 -0
- data/test/integration/extensions/test_jobs.rb +52 -0
- data/test/integration/extensions/test_matchers.rb +134 -0
- data/test/integration/extensions/test_projects.rb +82 -0
- data/test/integration/extensions/test_resources.rb +150 -0
- data/test/integration/extensions/test_results.rb +89 -0
- data/test/integration/extensions/test_scenarios.rb +88 -0
- data/test/integration/extensions/test_transformations.rb +113 -0
- data/test/integration/extensions/test_transformers.rb +80 -0
- data/test/integration/test_field.rb +45 -0
- data/test/integration/test_import.rb +78 -0
- data/test/integration/test_running_scenarios.rb +379 -0
- data/test/integration/test_transformation.rb +56 -0
- data/test/integration/test_transforming.rb +154 -0
- data/test/table_sets.rb +76 -0
- data/test/unit/models/test_common_model.rb +130 -0
- data/test/unit/models/test_comparison.rb +619 -0
- data/test/unit/models/test_connection.rb +115 -0
- data/test/unit/models/test_field.rb +99 -0
- data/test/unit/models/test_import.rb +130 -0
- data/test/unit/models/test_job.rb +115 -0
- data/test/unit/models/test_matcher.rb +82 -0
- data/test/unit/models/test_project.rb +102 -0
- data/test/unit/models/test_resource.rb +564 -0
- data/test/unit/models/test_result.rb +90 -0
- data/test/unit/models/test_scenario.rb +199 -0
- data/test/unit/models/test_transformation.rb +193 -0
- data/test/unit/models/test_transformer.rb +188 -0
- data/test/unit/test_base.rb +60 -0
- data/test/unit/test_data_uploader.rb +27 -0
- data/test/unit/test_database.rb +23 -0
- data/test/unit/test_helpers.rb +58 -0
- data/test/unit/test_logger.rb +10 -0
- data/test/unit/test_models.rb +12 -0
- data/test/unit/test_runner.rb +76 -0
- data/test/unit/test_scheduler.rb +66 -0
- data/uploads/.gitignore +2 -0
- data/vendor/java/.gitignore +5 -0
- data/webroot/public/css/960.css +1 -0
- data/webroot/public/css/dataTables.css +1057 -0
- data/webroot/public/css/jquery-ui.css +572 -0
- data/webroot/public/css/jquery.treeview.css +68 -0
- data/webroot/public/css/reset.css +1 -0
- data/webroot/public/css/style.css +504 -0
- data/webroot/public/css/text.css +1 -0
- data/webroot/public/favicon.ico +0 -0
- data/webroot/public/images/12_col.gif +0 -0
- data/webroot/public/images/16_col.gif +0 -0
- data/webroot/public/images/add.png +0 -0
- data/webroot/public/images/ajax-loader.gif +0 -0
- data/webroot/public/images/cog.png +0 -0
- data/webroot/public/images/coupler.png +0 -0
- data/webroot/public/images/foo.png +0 -0
- data/webroot/public/images/hammer.png +0 -0
- data/webroot/public/images/header.png +0 -0
- data/webroot/public/images/home.gif +0 -0
- data/webroot/public/images/jobs.gif +0 -0
- data/webroot/public/images/sidebar-bottom.png +0 -0
- data/webroot/public/images/sidebar.png +0 -0
- data/webroot/public/images/treeview-default-line.gif +0 -0
- data/webroot/public/images/treeview-default.gif +0 -0
- data/webroot/public/images/ui-anim_basic_16x16.gif +0 -0
- data/webroot/public/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/webroot/public/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/webroot/public/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/webroot/public/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/webroot/public/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/webroot/public/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/webroot/public/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/webroot/public/images/ui-bg_highlight-hard_30_565356_1x100.png +0 -0
- data/webroot/public/images/ui-bg_highlight-hard_75_888588_1x100.png +0 -0
- data/webroot/public/images/ui-bg_highlight-soft_30_6e3b3a_1x100.png +0 -0
- data/webroot/public/images/ui-bg_highlight-soft_35_8e8b8e_1x100.png +0 -0
- data/webroot/public/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/webroot/public/images/ui-icons_222222_256x240.png +0 -0
- data/webroot/public/images/ui-icons_2e83ff_256x240.png +0 -0
- data/webroot/public/images/ui-icons_454545_256x240.png +0 -0
- data/webroot/public/images/ui-icons_888888_256x240.png +0 -0
- data/webroot/public/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/webroot/public/images/ui-icons_ffffff_256x240.png +0 -0
- data/webroot/public/js/ajaxupload.js +673 -0
- data/webroot/public/js/application.js +40 -0
- data/webroot/public/js/jquery-ui.combobox.js +98 -0
- data/webroot/public/js/jquery-ui.js +9867 -0
- data/webroot/public/js/jquery-ui.min.js +559 -0
- data/webroot/public/js/jquery.dataTables.min.js +587 -0
- data/webroot/public/js/jquery.min.js +154 -0
- data/webroot/public/js/jquery.timeago.js +140 -0
- data/webroot/public/js/jquery.tooltip.min.js +19 -0
- data/webroot/public/js/jquery.treeview.min.js +15 -0
- data/webroot/public/js/resource.js +11 -0
- data/webroot/public/js/results.js +56 -0
- data/webroot/public/js/transformations.js +95 -0
- data/webroot/views/connections/index.erb +5 -0
- data/webroot/views/connections/list.erb +34 -0
- data/webroot/views/connections/new.erb +55 -0
- data/webroot/views/connections/show.erb +36 -0
- data/webroot/views/imports/edit.erb +60 -0
- data/webroot/views/imports/form.erb +81 -0
- data/webroot/views/imports/new.erb +89 -0
- data/webroot/views/index.erb +12 -0
- data/webroot/views/jobs/index.erb +7 -0
- data/webroot/views/jobs/list.erb +24 -0
- data/webroot/views/layout.erb +38 -0
- data/webroot/views/matchers/form.erb +250 -0
- data/webroot/views/matchers/list.erb +32 -0
- data/webroot/views/projects/form.erb +14 -0
- data/webroot/views/projects/index.erb +96 -0
- data/webroot/views/projects/show.erb +24 -0
- data/webroot/views/resources/edit.erb +88 -0
- data/webroot/views/resources/index.erb +5 -0
- data/webroot/views/resources/list.erb +27 -0
- data/webroot/views/resources/new.erb +121 -0
- data/webroot/views/resources/show.erb +86 -0
- data/webroot/views/resources/transform.erb +2 -0
- data/webroot/views/results/csv.erb +12 -0
- data/webroot/views/results/details.erb +15 -0
- data/webroot/views/results/index.erb +2 -0
- data/webroot/views/results/list.erb +22 -0
- data/webroot/views/results/record.erb +24 -0
- data/webroot/views/results/show.erb +68 -0
- data/webroot/views/scenarios/index.erb +5 -0
- data/webroot/views/scenarios/list.erb +20 -0
- data/webroot/views/scenarios/new.erb +99 -0
- data/webroot/views/scenarios/run.erb +2 -0
- data/webroot/views/scenarios/show.erb +50 -0
- data/webroot/views/sidebar.erb +106 -0
- data/webroot/views/transformations/create.erb +115 -0
- data/webroot/views/transformations/for.erb +16 -0
- data/webroot/views/transformations/index.erb +2 -0
- data/webroot/views/transformations/list.erb +29 -0
- data/webroot/views/transformations/new.erb +126 -0
- data/webroot/views/transformations/preview.erb +46 -0
- data/webroot/views/transformers/edit.erb +6 -0
- data/webroot/views/transformers/form.erb +58 -0
- data/webroot/views/transformers/index.erb +2 -0
- data/webroot/views/transformers/list.erb +25 -0
- data/webroot/views/transformers/new.erb +5 -0
- data/webroot/views/transformers/preview.erb +23 -0
- data/webroot/views/transformers/show.erb +0 -0
- metadata +558 -0
@@ -0,0 +1,110 @@
|
|
1
|
+
module Coupler
|
2
|
+
module Models
|
3
|
+
class Transformer < Sequel::Model
|
4
|
+
include CommonModel
|
5
|
+
|
6
|
+
plugin :serialization, :marshal, :allowed_types
|
7
|
+
|
8
|
+
TYPES = %w{string integer datetime}
|
9
|
+
EXAMPLES = {
|
10
|
+
'string' => 'Test',
|
11
|
+
'integer' => 123,
|
12
|
+
'datetime' => lambda { Time.now }
|
13
|
+
}
|
14
|
+
|
15
|
+
def accepts_type?(type)
|
16
|
+
allowed_types.is_a?(Array) && allowed_types.include?(type)
|
17
|
+
end
|
18
|
+
|
19
|
+
def transform(data, options)
|
20
|
+
input = data[options[:in]]
|
21
|
+
runner = Runner.new(code, input)
|
22
|
+
output = runner.run
|
23
|
+
data[options[:out]] = output
|
24
|
+
data
|
25
|
+
end
|
26
|
+
|
27
|
+
def preview
|
28
|
+
return nil if allowed_types.nil? || code.nil? || code == ""
|
29
|
+
|
30
|
+
result = {'success' => true}
|
31
|
+
examples = EXAMPLES.reject { |k, v| !allowed_types.include?(k) }
|
32
|
+
examples.each_pair do |type, obj|
|
33
|
+
obj = obj.call if obj.is_a?(Proc)
|
34
|
+
result[type] = { :in => obj }
|
35
|
+
begin
|
36
|
+
transform(result[type], {:in => :in, :out => :out})
|
37
|
+
|
38
|
+
expected_type = result_type == 'same' ? type : result_type
|
39
|
+
actual_type = case result[type][:out]
|
40
|
+
when String then "string"
|
41
|
+
when Fixnum then "integer"
|
42
|
+
when Time, Date, DateTime then "datetime"
|
43
|
+
when NilClass then "null"
|
44
|
+
end
|
45
|
+
|
46
|
+
if actual_type != "null" && expected_type != actual_type
|
47
|
+
raise TypeError, "expected #{expected_type}, got #{actual_type}"
|
48
|
+
end
|
49
|
+
|
50
|
+
rescue Exception => e
|
51
|
+
result[type][:out] = e
|
52
|
+
result['success'] = false
|
53
|
+
end
|
54
|
+
end
|
55
|
+
result
|
56
|
+
end
|
57
|
+
|
58
|
+
def field_changes(*fields)
|
59
|
+
fields.inject({}) do |result, field|
|
60
|
+
result[field.id] = hash = {}
|
61
|
+
if result_type != 'same'
|
62
|
+
hash[:type] = result_type.to_sym
|
63
|
+
|
64
|
+
# FIXME: don't use db_type anymore
|
65
|
+
hash[:db_type] =
|
66
|
+
case result_type
|
67
|
+
when 'integer' then 'int(11)'
|
68
|
+
when 'string' then 'varchar(255)'
|
69
|
+
when 'datetime' then 'datetime'
|
70
|
+
end
|
71
|
+
end
|
72
|
+
result
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
def validate
|
78
|
+
super
|
79
|
+
validates_presence [:name, :allowed_types, :result_type, :code]
|
80
|
+
validates_unique :name
|
81
|
+
validates_includes TYPES + ['same'], :result_type
|
82
|
+
|
83
|
+
if errors.on(:allowed_types).nil?
|
84
|
+
bad = (allowed_types - TYPES).uniq
|
85
|
+
if !bad.empty?
|
86
|
+
errors.add(:allowed_types, "has invalid type(s): #{bad.join(', ')}")
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
if errors.on(:code).nil?
|
91
|
+
io = java.io.ByteArrayInputStream.new(code.to_java_bytes)
|
92
|
+
begin
|
93
|
+
JRuby.runtime.parseInline(io, "line", nil)
|
94
|
+
rescue Exception => e
|
95
|
+
errors.add(:code, "has errors: #{e.to_s}")
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
if errors.empty?
|
100
|
+
result = preview
|
101
|
+
if !(result && result['success'])
|
102
|
+
errors.add(:code, "has errors")
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
require File.join(File.dirname(__FILE__), "transformer", "runner")
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Coupler
|
2
|
+
module Models
|
3
|
+
# NOTE: using autoload here would undoubtedly be more efficient, but
|
4
|
+
# I need to make sure the database connection is instantiated before
|
5
|
+
# loading these classes because of how Sequel::Model works.
|
6
|
+
#%w{connection project resource field transformer transformation scenario matcher job result comparison}.each do |name|
|
7
|
+
#autoload(name.capitalize.to_sym, File.dirname(__FILE__) + "/models/#{name}")
|
8
|
+
#end
|
9
|
+
|
10
|
+
NAMES = [
|
11
|
+
:Connection, :Project, :Resource, :Field, :Transformer,
|
12
|
+
:Transformation, :Scenario, :Matcher, :Job, :Result, :Comparison,
|
13
|
+
:Import
|
14
|
+
]
|
15
|
+
def self.const_missing(name)
|
16
|
+
name = name.to_sym
|
17
|
+
if NAMES.include?(name)
|
18
|
+
Database.instance
|
19
|
+
require File.dirname(__FILE__) + "/models/#{name.to_s.downcase}"
|
20
|
+
const_get(name)
|
21
|
+
else
|
22
|
+
puts "#{name.inspect} wasn't in #{NAMES.inspect}"
|
23
|
+
super
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
require File.dirname(__FILE__) + "/models/common_model"
|
30
|
+
require File.dirname(__FILE__) + "/models/jobify"
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module Coupler
|
2
|
+
class Runner
|
3
|
+
def initialize(argv = ARGV)
|
4
|
+
irb = false
|
5
|
+
OptionParser.new do |opts|
|
6
|
+
opts.on("-p", "--port PORT", "Web server port") do |port|
|
7
|
+
Base.set(:port, port.to_i)
|
8
|
+
end
|
9
|
+
opts.on("--dir DIR", "Directory to use for Coupler's data") do |dir|
|
10
|
+
Base.set(:data_path, dir)
|
11
|
+
end
|
12
|
+
opts.on("-e", "--environment ENVIRONMENT", "Set the environment") do |env|
|
13
|
+
case env
|
14
|
+
when "production", "development", "test"
|
15
|
+
Base.set(:environment, env.to_sym)
|
16
|
+
else
|
17
|
+
raise "Invalid environment (must be production, development, or test)"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
opts.on('-i', '--interactive', "Run an IRB session") do
|
21
|
+
irb = true
|
22
|
+
end
|
23
|
+
end.parse!(argv)
|
24
|
+
|
25
|
+
puts "Migrating database..."
|
26
|
+
Coupler::Database.instance.migrate!
|
27
|
+
|
28
|
+
puts "Starting scheduler..."
|
29
|
+
Coupler::Scheduler.instance.start
|
30
|
+
|
31
|
+
puts "Starting web server..."
|
32
|
+
handler = Rack::Handler.get('mongrel')
|
33
|
+
settings = Coupler::Base.settings
|
34
|
+
|
35
|
+
# See the Rack::Handler::Mongrel.run! method
|
36
|
+
# NOTE: I don't want to join the server immediately, which is why I'm
|
37
|
+
# doing this by hand.
|
38
|
+
@web_server = Mongrel::HttpServer.new(settings.bind, settings.port, 950, 0, 60)
|
39
|
+
@web_server.register('/', handler.new(Coupler::Base))
|
40
|
+
success = false
|
41
|
+
begin
|
42
|
+
@web_thread = @web_server.run
|
43
|
+
success = true
|
44
|
+
rescue Errno::EADDRINUSE => e
|
45
|
+
Scheduler.instance.shutdown
|
46
|
+
puts "Can't start web server, port already in use. Aborting..."
|
47
|
+
end
|
48
|
+
|
49
|
+
if success
|
50
|
+
Coupler::Base.set(:running, true)
|
51
|
+
trap("INT") do
|
52
|
+
shutdown
|
53
|
+
end
|
54
|
+
|
55
|
+
puts <<'EOF'
|
56
|
+
___
|
57
|
+
/\_ \
|
58
|
+
___ ___ __ __ _____\//\ \ __ _ __
|
59
|
+
/'___\ / __`\/\ \/\ \/\ '__`\\ \ \ /'__`\/\`'__\
|
60
|
+
/\ \__//\ \L\ \ \ \_\ \ \ \L\ \\_\ \_/\ __/\ \ \/
|
61
|
+
\ \____\ \____/\ \____/\ \ ,__//\____\ \____\\ \_\
|
62
|
+
\/____/\/___/ \/___/ \ \ \/ \/____/\/____/ \/_/
|
63
|
+
\ \_\
|
64
|
+
\/_/
|
65
|
+
EOF
|
66
|
+
@web_thread.join
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def shutdown
|
71
|
+
puts "Shutting down..."
|
72
|
+
Scheduler.instance.shutdown
|
73
|
+
@web_server.stop
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Coupler
|
2
|
+
class Scheduler
|
3
|
+
include Singleton
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
super
|
7
|
+
@mutex = Mutex.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def schedule_transform_job(resource)
|
11
|
+
Models::Job.create({
|
12
|
+
:name => "transform",
|
13
|
+
:resource => resource,
|
14
|
+
:status => "scheduled"
|
15
|
+
})
|
16
|
+
end
|
17
|
+
|
18
|
+
def schedule_run_scenario_job(scenario)
|
19
|
+
Models::Job.create({
|
20
|
+
:name => "run_scenario",
|
21
|
+
:scenario => scenario,
|
22
|
+
:status => "scheduled"
|
23
|
+
})
|
24
|
+
end
|
25
|
+
|
26
|
+
def run_jobs
|
27
|
+
@mutex.synchronize do
|
28
|
+
count = Models::Job.filter(:status => 'running').count
|
29
|
+
if count == 0
|
30
|
+
job = Models::Job.filter(:status => 'scheduled').order(:created_at).first
|
31
|
+
Thread.new(job) { |j| j.execute } if job
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def start
|
37
|
+
if !is_started?
|
38
|
+
@loop = Thread.new do
|
39
|
+
loop do
|
40
|
+
sleep 30
|
41
|
+
run_jobs
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def shutdown
|
48
|
+
@loop.exit
|
49
|
+
@loop = nil
|
50
|
+
end
|
51
|
+
|
52
|
+
def is_started?
|
53
|
+
!@loop.nil?
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/lib/coupler.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'java'
|
2
|
+
require 'jruby/core_ext'
|
3
|
+
|
4
|
+
require 'fileutils'
|
5
|
+
require 'erb'
|
6
|
+
require 'delegate'
|
7
|
+
require 'singleton'
|
8
|
+
require 'logger'
|
9
|
+
require 'optparse'
|
10
|
+
require 'thwait'
|
11
|
+
require 'digest'
|
12
|
+
require 'rack'
|
13
|
+
require 'rack/mime' # This is an attempt to avoid NameError exceptions
|
14
|
+
require 'sinatra/base'
|
15
|
+
require 'rack/flash'
|
16
|
+
require 'sequel'
|
17
|
+
require 'sequel/extensions/migration'
|
18
|
+
require 'json'
|
19
|
+
require 'fastercsv'
|
20
|
+
require 'carrierwave'
|
21
|
+
require 'mvn:com.h2database:h2'
|
22
|
+
require 'mongrel'
|
23
|
+
require 'jdbc/mysql' # FIXME: lazy load this
|
24
|
+
|
25
|
+
require File.dirname(__FILE__) + "/coupler/logger"
|
26
|
+
require File.dirname(__FILE__) + "/coupler/database"
|
27
|
+
require File.dirname(__FILE__) + "/coupler/scheduler"
|
28
|
+
require File.dirname(__FILE__) + "/coupler/data_uploader"
|
29
|
+
require File.dirname(__FILE__) + "/coupler/import_buffer"
|
30
|
+
require File.dirname(__FILE__) + "/coupler/models"
|
31
|
+
require File.dirname(__FILE__) + "/coupler/extensions"
|
32
|
+
require File.dirname(__FILE__) + "/coupler/helpers"
|
33
|
+
require File.dirname(__FILE__) + "/coupler/runner"
|
34
|
+
require File.dirname(__FILE__) + "/coupler/base"
|
data/log/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
*.log
|
data/misc/README
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
JSON-JRuby is copyrighted free software by Daniel Luz <mernen at gmail dot com>,
|
2
|
+
and is a derivative work of Florian Frank's json library <flori at ping dot de>.
|
3
|
+
You can redistribute it and/or modify it under either the terms of the GPL
|
4
|
+
version 2 (see the file GPL), or the conditions below:
|
5
|
+
|
6
|
+
1. You may make and give away verbatim copies of the source form of the
|
7
|
+
software without restriction, provided that you duplicate all of the
|
8
|
+
original copyright notices and associated disclaimers.
|
9
|
+
|
10
|
+
2. You may modify your copy of the software in any way, provided that
|
11
|
+
you do at least ONE of the following:
|
12
|
+
|
13
|
+
a) place your modifications in the Public Domain or otherwise
|
14
|
+
make them Freely Available, such as by posting said
|
15
|
+
modifications to Usenet or an equivalent medium, or by allowing
|
16
|
+
the author to include your modifications in the software.
|
17
|
+
|
18
|
+
b) use the modified software only within your corporation or
|
19
|
+
organization.
|
20
|
+
|
21
|
+
c) give non-standard binaries non-standard names, with
|
22
|
+
instructions on where to get the original software distribution.
|
23
|
+
|
24
|
+
d) make other distribution arrangements with the author.
|
25
|
+
|
26
|
+
3. You may distribute the software in object code or binary form,
|
27
|
+
provided that you do at least ONE of the following:
|
28
|
+
|
29
|
+
a) distribute the binaries and library files of the software,
|
30
|
+
together with instructions (in the manual page or equivalent)
|
31
|
+
on where to get the original distribution.
|
32
|
+
|
33
|
+
b) accompany the distribution with the machine-readable source of
|
34
|
+
the software.
|
35
|
+
|
36
|
+
c) give non-standard binaries non-standard names, with
|
37
|
+
instructions on where to get the original software distribution.
|
38
|
+
|
39
|
+
d) make other distribution arrangements with the author.
|
40
|
+
|
41
|
+
4. You may modify and include the part of the software into any other
|
42
|
+
software (possibly commercial). But some files in the distribution
|
43
|
+
are not written by the author, so that they are not under these terms.
|
44
|
+
|
45
|
+
For the list of those files and their copying conditions, see the
|
46
|
+
file LEGAL.
|
47
|
+
|
48
|
+
5. The scripts and library files supplied as input to or produced as
|
49
|
+
output from the software do not automatically fall under the
|
50
|
+
copyright of the software, but belong to whomever generated them,
|
51
|
+
and may be sold commercially, and may be aggregated with this
|
52
|
+
software.
|
53
|
+
|
54
|
+
6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
|
55
|
+
IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
56
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
57
|
+
PURPOSE.
|
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2009 Pat Nakajima
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person
|
4
|
+
obtaining a copy of this software and associated documentation
|
5
|
+
files (the "Software"), to deal in the Software without
|
6
|
+
restriction, including without limitation the rights to use,
|
7
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
copies of the Software, and to permit persons to whom the
|
9
|
+
Software is furnished to do so, subject to the following
|
10
|
+
conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
17
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
19
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
20
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
21
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
data/script/dbconsole.rb
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
package edu.vanderbilt.coupler;
|
2
|
+
|
3
|
+
import java.io.IOException;
|
4
|
+
import java.io.InputStream;
|
5
|
+
import java.util.Properties;
|
6
|
+
import java.util.ArrayList;
|
7
|
+
import java.util.List;
|
8
|
+
import java.net.URISyntaxException;
|
9
|
+
import java.net.URL;
|
10
|
+
import java.util.regex.Matcher;
|
11
|
+
import java.util.regex.Pattern;
|
12
|
+
import org.jruby.embed.ScriptingContainer;
|
13
|
+
import org.jruby.Ruby;
|
14
|
+
import org.jruby.RubyArray;
|
15
|
+
import org.jruby.RubyString;
|
16
|
+
|
17
|
+
public class Main {
|
18
|
+
private static final Properties couplerProperties = new Properties();
|
19
|
+
public static final String COUPLER_PROPERTIES = "coupler.properties";
|
20
|
+
public static final String JRUBY_PROPERTIES = "jruby.properties";
|
21
|
+
|
22
|
+
static {
|
23
|
+
InputStream stream = null;
|
24
|
+
try {
|
25
|
+
stream = Main.class.getResourceAsStream(COUPLER_PROPERTIES);
|
26
|
+
if (stream == null) {
|
27
|
+
throw new RuntimeException("Resource not found: " + COUPLER_PROPERTIES);
|
28
|
+
}
|
29
|
+
couplerProperties.load(stream);
|
30
|
+
} catch (IOException ioe) {
|
31
|
+
ioe.printStackTrace();
|
32
|
+
} finally {
|
33
|
+
if (stream != null) {
|
34
|
+
try {
|
35
|
+
stream.close();
|
36
|
+
} catch (IOException e) {
|
37
|
+
// silently ignore
|
38
|
+
}
|
39
|
+
}
|
40
|
+
}
|
41
|
+
}
|
42
|
+
|
43
|
+
private Main(String[] args) {
|
44
|
+
System.out.printf("Coupler version: %s\nBuild date: %s\n\n",
|
45
|
+
couplerProperties.getProperty("coupler.version"),
|
46
|
+
couplerProperties.getProperty("build.timestamp"));
|
47
|
+
|
48
|
+
// Set JRuby runtime properties
|
49
|
+
Properties systemProperties;
|
50
|
+
InputStream stream = null;
|
51
|
+
try {
|
52
|
+
stream = Main.class.getResourceAsStream(JRUBY_PROPERTIES);
|
53
|
+
if (stream == null) {
|
54
|
+
throw new RuntimeException("Resource not found: " + JRUBY_PROPERTIES);
|
55
|
+
}
|
56
|
+
systemProperties = new Properties(System.getProperties());
|
57
|
+
systemProperties.load(stream);
|
58
|
+
System.setProperties(systemProperties);
|
59
|
+
} catch (IOException ioe) {
|
60
|
+
ioe.printStackTrace();
|
61
|
+
} finally {
|
62
|
+
if (stream != null) {
|
63
|
+
try {
|
64
|
+
stream.close();
|
65
|
+
} catch (IOException e) {
|
66
|
+
// silently ignore
|
67
|
+
}
|
68
|
+
}
|
69
|
+
}
|
70
|
+
|
71
|
+
String location = findCouplerPath();
|
72
|
+
List<String> loadPaths = new ArrayList();
|
73
|
+
loadPaths.add(location);
|
74
|
+
|
75
|
+
ScriptingContainer container = new ScriptingContainer();
|
76
|
+
container.setLoadPaths(loadPaths);
|
77
|
+
|
78
|
+
// FIXME: I feel like there's a simpler way of doing this.
|
79
|
+
Ruby ruby = container.getProvider().getRuntime();
|
80
|
+
RubyArray rbArray = ruby.newArray();
|
81
|
+
for (String string : args) {
|
82
|
+
rbArray.append(ruby.newString(string));
|
83
|
+
}
|
84
|
+
container.put("argv", rbArray);
|
85
|
+
|
86
|
+
// SystemExit gets thrown when someone runs the JAR with --help
|
87
|
+
String script =
|
88
|
+
"require 'coupler'\n" +
|
89
|
+
"begin\n" +
|
90
|
+
" Coupler::Runner.new(argv)\n" +
|
91
|
+
"rescue SystemExit\n" +
|
92
|
+
"end";
|
93
|
+
container.runScriptlet(script);
|
94
|
+
}
|
95
|
+
|
96
|
+
private String findCouplerPath() {
|
97
|
+
try {
|
98
|
+
URL resource = getClass().getResource("/META-INF/coupler.home/lib/coupler.rb");
|
99
|
+
String location = resource.toURI().getSchemeSpecificPart();
|
100
|
+
Pattern p = Pattern.compile("coupler\\.rb$");
|
101
|
+
Matcher m = p.matcher(location);
|
102
|
+
while(m.find()) {
|
103
|
+
location = location.substring(0, m.start() - 1);
|
104
|
+
return location;
|
105
|
+
}
|
106
|
+
return null;
|
107
|
+
}
|
108
|
+
catch (URISyntaxException e) {
|
109
|
+
return null;
|
110
|
+
}
|
111
|
+
}
|
112
|
+
|
113
|
+
public static void main(String[] args) {
|
114
|
+
new Main(args);
|
115
|
+
}
|
116
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
jruby.thread.pooling=true
|
@@ -0,0 +1,84 @@
|
|
1
|
+
class SourceAnnotationExtractor
|
2
|
+
class Annotation < Struct.new(:line, :tag, :text)
|
3
|
+
def to_s(options={})
|
4
|
+
s = "[%3d] " % line
|
5
|
+
s << "[#{tag}] " if options[:tag]
|
6
|
+
s << text
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.enumerate(tag, options={})
|
11
|
+
extractor = new(tag)
|
12
|
+
extractor.display(extractor.find, options)
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_reader :tag
|
16
|
+
|
17
|
+
def initialize(tag)
|
18
|
+
@tag = tag
|
19
|
+
end
|
20
|
+
|
21
|
+
def find(dirs=%w(lib test))
|
22
|
+
dirs.inject({}) { |h, dir| h.update(find_in(dir)) }
|
23
|
+
end
|
24
|
+
|
25
|
+
def find_in(dir)
|
26
|
+
results = {}
|
27
|
+
|
28
|
+
Dir.glob("#{dir}/*") do |item|
|
29
|
+
next if File.basename(item)[0] == ?.
|
30
|
+
|
31
|
+
if File.directory?(item)
|
32
|
+
results.update(find_in(item))
|
33
|
+
elsif item =~ /\.(builder|(r(?:b|xml|js)))$/
|
34
|
+
results.update(extract_annotations_from(item, /#\s*(#{tag}):?\s*(.*)$/))
|
35
|
+
elsif item =~ /\.(rhtml|erb)$/
|
36
|
+
results.update(extract_annotations_from(item, /<%\s*#\s*(#{tag}):?\s*(.*?)\s*%>/))
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
results
|
41
|
+
end
|
42
|
+
|
43
|
+
def extract_annotations_from(file, pattern)
|
44
|
+
lineno = 0
|
45
|
+
result = File.readlines(file).inject([]) do |list, line|
|
46
|
+
lineno += 1
|
47
|
+
next list unless line =~ pattern
|
48
|
+
list << Annotation.new(lineno, $1, $2)
|
49
|
+
end
|
50
|
+
result.empty? ? {} : { file => result }
|
51
|
+
end
|
52
|
+
|
53
|
+
def display(results, options={})
|
54
|
+
results.keys.sort.each do |file|
|
55
|
+
puts "#{file}:"
|
56
|
+
results[file].each do |note|
|
57
|
+
puts " * #{note.to_s(options)}"
|
58
|
+
end
|
59
|
+
puts
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
desc "Enumerate all annotations"
|
65
|
+
task :notes do
|
66
|
+
SourceAnnotationExtractor.enumerate "OPTIMIZE|FIXME|TODO", :tag => true
|
67
|
+
end
|
68
|
+
|
69
|
+
namespace :notes do
|
70
|
+
desc "Enumerate all OPTIMIZE annotations"
|
71
|
+
task :optimize do
|
72
|
+
SourceAnnotationExtractor.enumerate "OPTIMIZE"
|
73
|
+
end
|
74
|
+
|
75
|
+
desc "Enumerate all FIXME annotations"
|
76
|
+
task :fixme do
|
77
|
+
SourceAnnotationExtractor.enumerate "FIXME"
|
78
|
+
end
|
79
|
+
|
80
|
+
desc "Enumerate all TODO annotations"
|
81
|
+
task :todo do
|
82
|
+
SourceAnnotationExtractor.enumerate "TODO"
|
83
|
+
end
|
84
|
+
end
|