coupler 0.0.1-java

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.
Files changed (258) hide show
  1. data/.document +5 -0
  2. data/.gitmodules +3 -0
  3. data/.rvmrc +1 -0
  4. data/.vimrc +40 -0
  5. data/Gemfile +27 -0
  6. data/Gemfile.lock +71 -0
  7. data/LICENSE +20 -0
  8. data/NOTES +6 -0
  9. data/README.rdoc +18 -0
  10. data/Rakefile +42 -0
  11. data/TODO +11 -0
  12. data/VERSION +1 -0
  13. data/bin/coupler +7 -0
  14. data/db/.gitignore +6 -0
  15. data/db/migrate/001_initial_schema.rb +166 -0
  16. data/db/migrate/002_stub.rb +4 -0
  17. data/db/migrate/003_stub.rb +4 -0
  18. data/db/migrate/004_create_comparisons.rb +28 -0
  19. data/db/migrate/005_move_database_name.rb +19 -0
  20. data/db/migrate/006_upgrade_comparisons.rb +34 -0
  21. data/db/migrate/007_add_which_to_comparisons.rb +23 -0
  22. data/db/migrate/008_add_result_field_to_transformations.rb +33 -0
  23. data/db/migrate/009_add_generated_flag_to_fields.rb +13 -0
  24. data/db/migrate/010_create_imports.rb +24 -0
  25. data/db/migrate/011_add_primary_key_type.rb +13 -0
  26. data/db/migrate/012_add_transformed_with_to_resources.rb +13 -0
  27. data/db/migrate/013_add_run_count_to_scenarios.rb +13 -0
  28. data/db/migrate/014_add_last_accessed_at_to_some_tables.rb +13 -0
  29. data/db/migrate/015_add_run_number_to_results.rb +15 -0
  30. data/db/migrate/016_fix_scenario_run_count.rb +27 -0
  31. data/db/migrate/017_rename_comparison_columns.rb +14 -0
  32. data/db/migrate/018_fix_scenario_linkage_type.rb +8 -0
  33. data/db/migrate/019_add_columns_to_imports.rb +24 -0
  34. data/db/migrate/020_rename_import_columns.rb +12 -0
  35. data/db/migrate/021_add_fields_to_connections.rb +15 -0
  36. data/db/migrate/022_remove_database_name_from_resources.rb +11 -0
  37. data/features/connections.feature +28 -0
  38. data/features/matchers.feature +35 -0
  39. data/features/projects.feature +11 -0
  40. data/features/resources.feature +62 -0
  41. data/features/scenarios.feature +45 -0
  42. data/features/step_definitions/coupler_steps.rb +145 -0
  43. data/features/step_definitions/matchers_steps.rb +26 -0
  44. data/features/step_definitions/resources_steps.rb +12 -0
  45. data/features/step_definitions/scenarios_steps.rb +7 -0
  46. data/features/step_definitions/transformations_steps.rb +3 -0
  47. data/features/support/env.rb +128 -0
  48. data/features/transformations.feature +22 -0
  49. data/features/wizard.feature +10 -0
  50. data/gfx/coupler-header.svg +213 -0
  51. data/gfx/coupler-sidebar.svg +656 -0
  52. data/gfx/coupler.svg +184 -0
  53. data/gfx/icon.svg +75 -0
  54. data/lib/coupler/base.rb +63 -0
  55. data/lib/coupler/config.rb +128 -0
  56. data/lib/coupler/data_uploader.rb +20 -0
  57. data/lib/coupler/database.rb +31 -0
  58. data/lib/coupler/extensions/connections.rb +57 -0
  59. data/lib/coupler/extensions/exceptions.rb +58 -0
  60. data/lib/coupler/extensions/imports.rb +43 -0
  61. data/lib/coupler/extensions/jobs.rb +21 -0
  62. data/lib/coupler/extensions/matchers.rb +64 -0
  63. data/lib/coupler/extensions/projects.rb +62 -0
  64. data/lib/coupler/extensions/resources.rb +89 -0
  65. data/lib/coupler/extensions/results.rb +100 -0
  66. data/lib/coupler/extensions/scenarios.rb +50 -0
  67. data/lib/coupler/extensions/transformations.rb +70 -0
  68. data/lib/coupler/extensions/transformers.rb +58 -0
  69. data/lib/coupler/extensions.rb +16 -0
  70. data/lib/coupler/helpers.rb +121 -0
  71. data/lib/coupler/import_buffer.rb +48 -0
  72. data/lib/coupler/logger.rb +16 -0
  73. data/lib/coupler/models/common_model.rb +104 -0
  74. data/lib/coupler/models/comparison.rb +166 -0
  75. data/lib/coupler/models/connection.rb +59 -0
  76. data/lib/coupler/models/field.rb +55 -0
  77. data/lib/coupler/models/import.rb +238 -0
  78. data/lib/coupler/models/job.rb +42 -0
  79. data/lib/coupler/models/jobify.rb +17 -0
  80. data/lib/coupler/models/matcher.rb +36 -0
  81. data/lib/coupler/models/project.rb +40 -0
  82. data/lib/coupler/models/resource.rb +287 -0
  83. data/lib/coupler/models/result.rb +92 -0
  84. data/lib/coupler/models/scenario/runner.rb +357 -0
  85. data/lib/coupler/models/scenario.rb +115 -0
  86. data/lib/coupler/models/transformation.rb +117 -0
  87. data/lib/coupler/models/transformer/runner.rb +28 -0
  88. data/lib/coupler/models/transformer.rb +110 -0
  89. data/lib/coupler/models.rb +30 -0
  90. data/lib/coupler/runner.rb +76 -0
  91. data/lib/coupler/scheduler.rb +56 -0
  92. data/lib/coupler.rb +34 -0
  93. data/log/.gitignore +1 -0
  94. data/misc/README +5 -0
  95. data/misc/jruby-json.license +57 -0
  96. data/misc/rack-flash.license +22 -0
  97. data/script/dbconsole.rb +5 -0
  98. data/src/edu/vanderbilt/coupler/Main.java +116 -0
  99. data/src/edu/vanderbilt/coupler/jruby.properties +1 -0
  100. data/tasks/annotations.rake +84 -0
  101. data/tasks/db.rake +120 -0
  102. data/tasks/environment.rake +12 -0
  103. data/tasks/jeweler.rake +43 -0
  104. data/tasks/package.rake +58 -0
  105. data/tasks/rdoc.rake +13 -0
  106. data/tasks/test.rake +63 -0
  107. data/tasks/vendor.rake +43 -0
  108. data/test/README.txt +6 -0
  109. data/test/config.yml +9 -0
  110. data/test/coupler/models/test_import.rb +221 -0
  111. data/test/factories.rb +91 -0
  112. data/test/fixtures/duplicate-keys.csv +5 -0
  113. data/test/fixtures/no-headers.csv +50 -0
  114. data/test/fixtures/people.csv +51 -0
  115. data/test/fixtures/varying-row-size.csv +4 -0
  116. data/test/helper.rb +156 -0
  117. data/test/integration/extensions/test_connections.rb +80 -0
  118. data/test/integration/extensions/test_imports.rb +94 -0
  119. data/test/integration/extensions/test_jobs.rb +52 -0
  120. data/test/integration/extensions/test_matchers.rb +134 -0
  121. data/test/integration/extensions/test_projects.rb +82 -0
  122. data/test/integration/extensions/test_resources.rb +150 -0
  123. data/test/integration/extensions/test_results.rb +89 -0
  124. data/test/integration/extensions/test_scenarios.rb +88 -0
  125. data/test/integration/extensions/test_transformations.rb +113 -0
  126. data/test/integration/extensions/test_transformers.rb +80 -0
  127. data/test/integration/test_field.rb +45 -0
  128. data/test/integration/test_import.rb +78 -0
  129. data/test/integration/test_running_scenarios.rb +379 -0
  130. data/test/integration/test_transformation.rb +56 -0
  131. data/test/integration/test_transforming.rb +154 -0
  132. data/test/table_sets.rb +76 -0
  133. data/test/unit/models/test_common_model.rb +130 -0
  134. data/test/unit/models/test_comparison.rb +619 -0
  135. data/test/unit/models/test_connection.rb +115 -0
  136. data/test/unit/models/test_field.rb +99 -0
  137. data/test/unit/models/test_import.rb +130 -0
  138. data/test/unit/models/test_job.rb +115 -0
  139. data/test/unit/models/test_matcher.rb +82 -0
  140. data/test/unit/models/test_project.rb +102 -0
  141. data/test/unit/models/test_resource.rb +564 -0
  142. data/test/unit/models/test_result.rb +90 -0
  143. data/test/unit/models/test_scenario.rb +199 -0
  144. data/test/unit/models/test_transformation.rb +193 -0
  145. data/test/unit/models/test_transformer.rb +188 -0
  146. data/test/unit/test_base.rb +60 -0
  147. data/test/unit/test_data_uploader.rb +27 -0
  148. data/test/unit/test_database.rb +23 -0
  149. data/test/unit/test_helpers.rb +58 -0
  150. data/test/unit/test_logger.rb +10 -0
  151. data/test/unit/test_models.rb +12 -0
  152. data/test/unit/test_runner.rb +76 -0
  153. data/test/unit/test_scheduler.rb +66 -0
  154. data/uploads/.gitignore +2 -0
  155. data/vendor/java/.gitignore +5 -0
  156. data/webroot/public/css/960.css +1 -0
  157. data/webroot/public/css/dataTables.css +1057 -0
  158. data/webroot/public/css/jquery-ui.css +572 -0
  159. data/webroot/public/css/jquery.treeview.css +68 -0
  160. data/webroot/public/css/reset.css +1 -0
  161. data/webroot/public/css/style.css +504 -0
  162. data/webroot/public/css/text.css +1 -0
  163. data/webroot/public/favicon.ico +0 -0
  164. data/webroot/public/images/12_col.gif +0 -0
  165. data/webroot/public/images/16_col.gif +0 -0
  166. data/webroot/public/images/add.png +0 -0
  167. data/webroot/public/images/ajax-loader.gif +0 -0
  168. data/webroot/public/images/cog.png +0 -0
  169. data/webroot/public/images/coupler.png +0 -0
  170. data/webroot/public/images/foo.png +0 -0
  171. data/webroot/public/images/hammer.png +0 -0
  172. data/webroot/public/images/header.png +0 -0
  173. data/webroot/public/images/home.gif +0 -0
  174. data/webroot/public/images/jobs.gif +0 -0
  175. data/webroot/public/images/sidebar-bottom.png +0 -0
  176. data/webroot/public/images/sidebar.png +0 -0
  177. data/webroot/public/images/treeview-default-line.gif +0 -0
  178. data/webroot/public/images/treeview-default.gif +0 -0
  179. data/webroot/public/images/ui-anim_basic_16x16.gif +0 -0
  180. data/webroot/public/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  181. data/webroot/public/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  182. data/webroot/public/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  183. data/webroot/public/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  184. data/webroot/public/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  185. data/webroot/public/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  186. data/webroot/public/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  187. data/webroot/public/images/ui-bg_highlight-hard_30_565356_1x100.png +0 -0
  188. data/webroot/public/images/ui-bg_highlight-hard_75_888588_1x100.png +0 -0
  189. data/webroot/public/images/ui-bg_highlight-soft_30_6e3b3a_1x100.png +0 -0
  190. data/webroot/public/images/ui-bg_highlight-soft_35_8e8b8e_1x100.png +0 -0
  191. data/webroot/public/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  192. data/webroot/public/images/ui-icons_222222_256x240.png +0 -0
  193. data/webroot/public/images/ui-icons_2e83ff_256x240.png +0 -0
  194. data/webroot/public/images/ui-icons_454545_256x240.png +0 -0
  195. data/webroot/public/images/ui-icons_888888_256x240.png +0 -0
  196. data/webroot/public/images/ui-icons_cd0a0a_256x240.png +0 -0
  197. data/webroot/public/images/ui-icons_ffffff_256x240.png +0 -0
  198. data/webroot/public/js/ajaxupload.js +673 -0
  199. data/webroot/public/js/application.js +40 -0
  200. data/webroot/public/js/jquery-ui.combobox.js +98 -0
  201. data/webroot/public/js/jquery-ui.js +9867 -0
  202. data/webroot/public/js/jquery-ui.min.js +559 -0
  203. data/webroot/public/js/jquery.dataTables.min.js +587 -0
  204. data/webroot/public/js/jquery.min.js +154 -0
  205. data/webroot/public/js/jquery.timeago.js +140 -0
  206. data/webroot/public/js/jquery.tooltip.min.js +19 -0
  207. data/webroot/public/js/jquery.treeview.min.js +15 -0
  208. data/webroot/public/js/resource.js +11 -0
  209. data/webroot/public/js/results.js +56 -0
  210. data/webroot/public/js/transformations.js +95 -0
  211. data/webroot/views/connections/index.erb +5 -0
  212. data/webroot/views/connections/list.erb +34 -0
  213. data/webroot/views/connections/new.erb +55 -0
  214. data/webroot/views/connections/show.erb +36 -0
  215. data/webroot/views/imports/edit.erb +60 -0
  216. data/webroot/views/imports/form.erb +81 -0
  217. data/webroot/views/imports/new.erb +89 -0
  218. data/webroot/views/index.erb +12 -0
  219. data/webroot/views/jobs/index.erb +7 -0
  220. data/webroot/views/jobs/list.erb +24 -0
  221. data/webroot/views/layout.erb +38 -0
  222. data/webroot/views/matchers/form.erb +250 -0
  223. data/webroot/views/matchers/list.erb +32 -0
  224. data/webroot/views/projects/form.erb +14 -0
  225. data/webroot/views/projects/index.erb +96 -0
  226. data/webroot/views/projects/show.erb +24 -0
  227. data/webroot/views/resources/edit.erb +88 -0
  228. data/webroot/views/resources/index.erb +5 -0
  229. data/webroot/views/resources/list.erb +27 -0
  230. data/webroot/views/resources/new.erb +121 -0
  231. data/webroot/views/resources/show.erb +86 -0
  232. data/webroot/views/resources/transform.erb +2 -0
  233. data/webroot/views/results/csv.erb +12 -0
  234. data/webroot/views/results/details.erb +15 -0
  235. data/webroot/views/results/index.erb +2 -0
  236. data/webroot/views/results/list.erb +22 -0
  237. data/webroot/views/results/record.erb +24 -0
  238. data/webroot/views/results/show.erb +68 -0
  239. data/webroot/views/scenarios/index.erb +5 -0
  240. data/webroot/views/scenarios/list.erb +20 -0
  241. data/webroot/views/scenarios/new.erb +99 -0
  242. data/webroot/views/scenarios/run.erb +2 -0
  243. data/webroot/views/scenarios/show.erb +50 -0
  244. data/webroot/views/sidebar.erb +106 -0
  245. data/webroot/views/transformations/create.erb +115 -0
  246. data/webroot/views/transformations/for.erb +16 -0
  247. data/webroot/views/transformations/index.erb +2 -0
  248. data/webroot/views/transformations/list.erb +29 -0
  249. data/webroot/views/transformations/new.erb +126 -0
  250. data/webroot/views/transformations/preview.erb +46 -0
  251. data/webroot/views/transformers/edit.erb +6 -0
  252. data/webroot/views/transformers/form.erb +58 -0
  253. data/webroot/views/transformers/index.erb +2 -0
  254. data/webroot/views/transformers/list.erb +25 -0
  255. data/webroot/views/transformers/new.erb +5 -0
  256. data/webroot/views/transformers/preview.erb +23 -0
  257. data/webroot/views/transformers/show.erb +0 -0
  258. 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,5 @@
1
+ There was no license distributed with rack-flash. I found it here:
2
+ http://nakajima.github.com/rack-flash/
3
+
4
+ Same thing for json-jruby. Found it here:
5
+ http://github.com/mernen/json-jruby/raw/master/COPYING
@@ -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.
@@ -0,0 +1,5 @@
1
+ require 'rubygems'
2
+ require 'lib/coupler'
3
+
4
+ server = Coupler::Server.instance
5
+ server.console || puts("Coupler's database server isn't running. Start it with `rake db:console'")
@@ -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