coupler 0.0.1-java

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