t2-web 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES ADDED
@@ -0,0 +1,18 @@
1
+ = Changes log for the Taverna via the Web Gem
2
+
3
+ == Version 0.0.5
4
+ * Updated to new myexperiment-rest API
5
+
6
+ == Version 0.0.4
7
+ * Improved the UI (added logos, tooltips, changed colours).
8
+ * Made some code abstractions
9
+
10
+ == Version 0.0.3
11
+ * Improved the UI (changed divs with frames).
12
+
13
+ == Version 0.0.2
14
+ * Added upload functionality option for each input.
15
+
16
+ == Version 0.0.1
17
+ * Works. Very basic functionality and UI.
18
+
data/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+ == t2-web
2
+
3
+ The MIT License
4
+
5
+ Copyright (c) 2010 - Netherlands Bioinformatics Centre
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ of this software and associated documentation files (the "Software"), to deal
9
+ in the Software without restriction, including without limitation the rights
10
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ copies of the Software, and to permit persons to whom the Software is
12
+ furnished to do so, subject to the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be included in
15
+ all copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
+ THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,41 @@
1
+ = t2-web interface generator
2
+
3
+
4
+ Authors:: Konstantinos Karasavvas
5
+ Gem Version:: 0.0.5
6
+ Contact:: mailto:kostas.karasavvas@nbic.nl
7
+ Licence:: MIT (See LICENCE or http://www.opensource.org/licenses/mit-license)
8
+ Copyright:: (c) 2010 Netherlands Bioinformatics Centre, The Netherlands
9
+
10
+
11
+ == Synopsis
12
+
13
+ This web application accepts a myExperiment workflow identifier and constructs
14
+ a web form to allow end-users to configure and execute that workflow via a web
15
+ browser with no other dependencies.. The web form interface is as good as the
16
+ description provided in the workflow itself in myExperiment.
17
+
18
+
19
+ == Installation
20
+
21
+ [sudo] gem install t2-web
22
+
23
+
24
+ == Usage
25
+
26
+ t2_webapp
27
+
28
+ Runs the web application at port 9494 and waits for incoming requests.
29
+
30
+
31
+
32
+ == References
33
+
34
+ Taverna to Web Form Generator:: https://trac.nbic.nl/elabfactory/wiki/t2web
35
+ Taverna2:: http://www.taverna.org.uk
36
+ myExperiment:: http://www.myexperiment.org
37
+
38
+
39
+ == Semantic Versioning
40
+
41
+ This module uses semantic versioning concepts from http://semver.org/.
@@ -0,0 +1,54 @@
1
+ #
2
+ # To change this template, choose Tools | Templates
3
+ # and open the template in the editor.
4
+
5
+
6
+ require 'rubygems'
7
+ require 'rake'
8
+ require 'rake/clean'
9
+ require 'rake/testtask'
10
+ require 'rubygems/package_task'
11
+ require 'rdoc/task'
12
+
13
+ spec = Gem::Specification.new do |s|
14
+ s.name = 't2-web'
15
+ s.version = '0.0.5'
16
+ s.extra_rdoc_files = ['README', 'LICENSE', 'CHANGES']
17
+ s.summary = 'WS (with libs) that generates a Web UI form for a Taverna2 workflow and then enacts it to a T2 server.'
18
+ s.description = s.summary
19
+ s.author = 'Kostas Karasavvas'
20
+ s.email = 'kostas.karasavvas@nbic.nl'
21
+ s.executables = ['t2_webapp.rb']
22
+ s.files = %w(LICENSE README CHANGES Rakefile) + Dir.glob("{bin,lib,spec,public,views}/**/*")
23
+ s.require_path = "lib"
24
+ s.bindir = "bin"
25
+ s.add_dependency 'sinatra', '~> 1.2.6'
26
+ s.add_dependency 'haml', '~> 3.1.2'
27
+ s.add_dependency 'rest-client', '~> 1.6.3'
28
+ s.add_dependency 't2-server', '~> 0.6.1'
29
+ s.add_dependency 'myexperiment-rest', '~> 0.3.0'
30
+ end
31
+
32
+ Gem::PackageTask.new(spec) do |p|
33
+ p.gem_spec = spec
34
+ p.need_tar = true
35
+ p.need_zip = true
36
+ end
37
+
38
+ RDoc::Task.new do |rdoc|
39
+ files =['README', 'LICENSE', 'CHANGES', 'lib/**/*.rb']
40
+ rdoc.rdoc_files.add(files)
41
+ rdoc.main = "README" # page to start on
42
+ rdoc.title = "web-t2 Docs"
43
+ rdoc.rdoc_dir = 'doc/rdoc' # rdoc output folder
44
+ rdoc.options << '--line-numbers'
45
+ end
46
+
47
+ Rake::TestTask.new do |t|
48
+ t.test_files = FileList['test/**/*.rb']
49
+ end
50
+
51
+ # make gem and copy to test deployment server
52
+ task :copy_to_server => :gem do
53
+ `scp pkg/#{spec.name}-#{spec.version}.gem kostas@mybiobank.org:/home/kostas`
54
+ end
@@ -0,0 +1,295 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems' if RUBY_VERSION < '1.9'
4
+ require 'sinatra'
5
+ require 'haml'
6
+ require 'open-uri'
7
+ require 'rest-client'
8
+ require 't2-server'
9
+ require 'myexperiment-rest'
10
+ require 'cgi'
11
+ #require "web-t2" TODO: move whole of WebT2App in lib
12
+
13
+
14
+ class WebT2App < Sinatra::Base
15
+
16
+ WEB_APP_NAME = "t2web"
17
+ # TODO: const for TMP_UPLOAD_PATH ? - need to read from config file?
18
+
19
+ set :port, 9494
20
+ set :views, File.dirname(__FILE__) + '/../views'
21
+ set :public, File.dirname(__FILE__) + '/../public'
22
+
23
+ # can be used from routes and views (haml)
24
+ helpers do
25
+
26
+ # Used before we sent the workflow inputs to the taverna server. Just converts
27
+ # double quotations to single ones. That is because the t2-server library
28
+ # is confused with double quotes and apparently it is not easy to fix.
29
+ def t2_library_sanitize(string)
30
+ ex = string.gsub('"', "'")
31
+ end
32
+
33
+ #
34
+ # Deletes last new line of file if it exists! It is needed for t2 workflows that
35
+ # do not sanitize properly, i.e. via a user-provided beanshell script
36
+ #
37
+ def chomp_last_newline(file)
38
+
39
+ if File.file?(file) and File.size(file) > 1
40
+ f = open(file, "rb+")
41
+ f.seek(-1, File::SEEK_END)
42
+ f.truncate(File.size(file) - 1) if f.read(1) == "\n"
43
+ f.close
44
+ end
45
+
46
+ end
47
+
48
+ # Construct the complete or partial URL as MyExperimentRest lib expects it
49
+ # TODO: Maybe update myExperimentREST lib to accept only wid and wkf_version
50
+ # Minor for now
51
+ def get_url_from_wid(wid, wkf_version)
52
+ if wkf_version == "default"
53
+ "/workflows/#{wid}"
54
+ else
55
+ "/workflows/#{wid}?version=#{wkf_version}"
56
+ end
57
+ end
58
+
59
+
60
+ # Generates the contents of the header frame
61
+ def generate_header_frame(my_exp_wkf, my_exp_usr)
62
+ <<END
63
+ <html>
64
+ <head><link href='/css/form.css' rel='stylesheet'/></head>
65
+ <body>
66
+ #{generate_header_table(my_exp_wkf, my_exp_usr)}
67
+ </body>
68
+ </html>
69
+ END
70
+ end
71
+
72
+
73
+ # Generates the contents of the header frame
74
+ def generate_header_table(my_exp_wkf, my_exp_usr)
75
+ <<END
76
+ <div id='header'>
77
+ <table class='header'>
78
+ <tr>
79
+ <td>
80
+ <img alt='NBIC logo' src='/images/nbic_logo.gif' />
81
+ </td>
82
+ <td>
83
+ <table class='header-title'>
84
+ <tr>
85
+ <td class='header-title'>Workflow: #{@my_exp_wkf.title}</td>
86
+ </tr>
87
+ <tr>
88
+ <td class='right'>workflow by #{@my_exp_usr.name}</td>
89
+
90
+ </tr>
91
+ </table>
92
+ </td>
93
+ <td>
94
+ <img alt='LUMC logo' class='right' src='/images/lumc_logo2.png' />
95
+ </td>
96
+ </tr>
97
+ </table>
98
+ </div>
99
+ END
100
+ end
101
+
102
+
103
+ # Generates tooltip html text for descriptions
104
+ def generate_label_tooltip(input)
105
+ "Description: " << CGI::unescapeHTML(input.descriptions[0])
106
+ end
107
+
108
+ # Generates tooltip html text for textarea example
109
+ def generate_textarea_tooltip(input)
110
+ "Example: " << CGI::unescapeHTML(input.examples[0])
111
+ end
112
+
113
+
114
+ # Generates the contents of the data-navigation frame
115
+ def generate_data_navigation_frame(my_exp_wkf, uuid, wid, wkf_version, t2_server, finished_execution)
116
+
117
+ data_navigation_frame = "<html><head><link href='/css/results_navigation.css' rel='stylesheet'/></head><body><table>"
118
+ if my_exp_wkf.outputs.size >=1
119
+ my_exp_wkf.outputs.each do |output|
120
+ data_navigation_frame << "<tr>"
121
+ if finished_execution
122
+ data_navigation_frame << "<td><a href='javascript:void(0);' onclick='parent.getSampleOutput(\\\"#{t2_server}\\\", \\\"#{uuid}\\\", " <<
123
+ "\\\"#{output.name}\\\", \\\"#{wid}\\\", \\\"#{wkf_version}\\\");'>#{output.name}</a></td><td></td>"
124
+ else
125
+ data_navigation_frame << "<td>#{output.name}</td><td><img src='/images/snake_transparent.gif' alt='Loading Content...'></td>"
126
+ end
127
+ data_navigation_frame << "</tr>"
128
+ end
129
+ end
130
+ data_navigation_frame << "</table></body></html>"
131
+ end
132
+
133
+
134
+ # Check type of data and generate appropriate html for that result!
135
+ def generate_html_result(data)
136
+ html = ""
137
+ #p data
138
+ if data.instance_of? Array
139
+ html = data.flatten.join('<br>')
140
+ elsif data.instance_of? String
141
+ html = data.gsub(/[\n]/, '<br>')
142
+ else
143
+ html = data
144
+ end
145
+ html
146
+ end
147
+
148
+ end
149
+
150
+
151
+
152
+ # Create the Web UI for that workflow
153
+ get "/#{WEB_APP_NAME}/workflow/:wid" do
154
+
155
+ # Get http request's parameters
156
+ # TODO: consider adding the following to a session
157
+ @wid = params[:wid]
158
+ @wkf_version = params[:wkf_version] || nil
159
+ @t2_server = params[:server] || "http://test.mybiobank.org/taverna-server"
160
+
161
+ # Get myExperiment workflow object
162
+ # TODO: catch exception -- make custom exceptions?
163
+ @my_exp_wkf = MyExperimentREST::Workflow.from_id_and_version(@wid, @wkf_version)
164
+
165
+ # Get myExperiment user object
166
+ # TODO: catch exception -- make custom exceptions?
167
+ @my_exp_usr = MyExperimentREST::User.from_uri(@my_exp_wkf.uploader_uri)
168
+
169
+ haml :form
170
+
171
+ end
172
+
173
+
174
+ # Enact the workflow with the submitted parameters and returns
175
+ # result display (involves checking run's status and getting results)
176
+ post "/#{WEB_APP_NAME}/enact" do
177
+ #p params
178
+
179
+ # Get http POST request's parameters
180
+ # TODO: consider adding the following to a session
181
+ @wid = params[:wid]
182
+ @wkf_version = params[:wkf_version]
183
+ @t2_server = params[:server]
184
+
185
+ @my_exp_wkf = MyExperimentREST::Workflow.from_id_and_version(@wid, @wkf_version)
186
+
187
+ # Get myExperiment user object (TODO: session!, exceptions)
188
+ @my_exp_usr = MyExperimentREST::User.from_uri(@my_exp_wkf.uploader_uri)
189
+
190
+
191
+ # use the uri reference to download the workflow locally
192
+ #wkf_file = URI.parse(@my_exp_wkf.content_uri)
193
+ wkf = open(@my_exp_wkf.content_uri).read
194
+
195
+ # create run
196
+ begin
197
+ run = T2Server::Run.create(@t2_server, wkf)
198
+ rescue T2Server::T2ServerError => e
199
+ return "404 Not Found: run could not be instantiated!"
200
+ end
201
+
202
+ # Get the run as instance member to make visible in views
203
+ @run_uuid = run.uuid
204
+
205
+ # Set workflow inputs
206
+ @my_exp_wkf.inputs.each do |input|
207
+ if params[:"upload-checkbox-#{input.name}"] == "yes"
208
+ filename = params[:"#{input.name}-file"]
209
+ tmp_filename = "/tmp/#{WEB_APP_NAME}/#{filename}"
210
+
211
+ # make sure that the file is uploaded completely, i.e. all it's
212
+ # connections are closed
213
+ #while `lsof -c cp | grep /tmp/#{WEB_APP_NAME}/#{filename}` != ""
214
+ # sleep 1
215
+ #end
216
+
217
+ chomp_last_newline(tmp_filename)
218
+ run.upload_input_file(input.name, tmp_filename)
219
+ else
220
+ run.set_input(input.name, t2_library_sanitize(params["#{input.name}-input".to_sym]) )
221
+ end
222
+ end
223
+
224
+ # start run and wait until it is finished
225
+ run.start
226
+
227
+ haml :results
228
+ end
229
+
230
+
231
+
232
+ # Proxy operation (to bypass cross-domain AJAX) to get T2 run's status
233
+ get '/runs/:uuid/status' do
234
+ uuid = params[:uuid]
235
+ t2_server = params[:server]
236
+
237
+ response = RestClient.get t2_server + "/rest/runs/" + uuid + "/status", :content_type => "text/plain"
238
+
239
+ response.to_str
240
+ end
241
+
242
+
243
+
244
+ # Get results for specified run and output - display it in data-display div
245
+ # Cross-domain AJAX to get result from T2
246
+ get "/#{WEB_APP_NAME}/run/:uuid/output/:out" do
247
+
248
+ # Get http request's parameters
249
+ # TODO: consider adding the following to a session
250
+ @wid = params[:wid]
251
+ @wkf_version = params[:wkf_version]
252
+
253
+ # Get myExperiment workflow object
254
+ # TODO: with sessions that would be remembered
255
+ @my_exp_wkf = MyExperimentREST::Workflow.from_id_and_version(@wid, @wkf_version)
256
+
257
+ @run_uuid = params[:uuid]
258
+ @t2_server = params[:server]
259
+ t2_output = params[:out]
260
+
261
+ # Get t2 server and then the run using uuid
262
+ server = T2Server::Server.connect(@t2_server)
263
+ run = server.run(@run_uuid)
264
+
265
+ # Get output from t2 server
266
+ # TODO: that gets the whole output.. request client lib to support partial
267
+ # download! -- refs could then be used to download the full results!
268
+ begin
269
+ data_lists = run.get_output(t2_output, false)
270
+ rescue Exception => e
271
+ data_lists = run.get_output("#{t2_output}.error", false)
272
+ end
273
+
274
+ # that should be a sample of the results -- not the complete results!
275
+ data = generate_html_result(data_lists)
276
+
277
+ data
278
+ end
279
+
280
+
281
+ # Used from input's upload-form to upload files without refresh (actually
282
+ # a hidden iframe is refreshed).
283
+ post "/#{WEB_APP_NAME}/upload" do
284
+ filename = params[:file][:filename]
285
+ tempfile = params[:file][:tempfile]
286
+ FileUtils.mkdir("/tmp/#{WEB_APP_NAME}") unless File.exist?("/tmp/#{WEB_APP_NAME}")
287
+ FileUtils.copy(tempfile.path, "/tmp/#{WEB_APP_NAME}/#{filename}")
288
+ "Successfully copied #{filename}!!"
289
+ end
290
+
291
+ end
292
+
293
+
294
+ # Start Web App
295
+ WebT2App.run!
@@ -0,0 +1,70 @@
1
+ body{
2
+ background-color: #fdfdfd;
3
+ }
4
+
5
+ table.header {
6
+ width: 100%;
7
+ }
8
+
9
+ table.header-title {
10
+ border-collapse: collapse;
11
+ /* With equal left-right margins table will be aligned in the centre */
12
+ margin-left: auto;
13
+ margin-right: auto;
14
+ }
15
+
16
+ td.header-title {
17
+ font-size: 200%;
18
+ background-color: #f0f0f0;
19
+ padding: 12px;
20
+ border-bottom: 4px solid #909090;
21
+ border-top: 4px solid #909090;
22
+ }
23
+
24
+ #inputs {
25
+ }
26
+
27
+ table.inputs {
28
+ width: 800px;
29
+ border-collapse: collapse;
30
+ /* With equal left-right margins table will be aligned in the centre */
31
+ margin-left: auto;
32
+ margin-right: auto;
33
+ }
34
+
35
+ th.inputs {
36
+ font-size: 120%;
37
+ background-color: #f0f0f0;
38
+ padding: 10px;
39
+ border-bottom: 1px solid #909090;
40
+ border-top: 4px solid #909090;
41
+ }
42
+
43
+ td.inputs {
44
+ padding: 5px;
45
+ vertical-align: top;
46
+ }
47
+
48
+ td.right {
49
+ text-align: right;
50
+ }
51
+
52
+ img.right {
53
+ float: right;
54
+ }
55
+
56
+ #description {
57
+ }
58
+
59
+ #inputs {
60
+ }
61
+
62
+ #outputs {
63
+ }
64
+
65
+ #note {
66
+ }
67
+
68
+ label {
69
+ text-decoration: underline;
70
+ }