t2-server 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/LICENCE ADDED
@@ -0,0 +1,29 @@
1
+ Copyright (c) 2010, The University of Manchester, UK.
2
+
3
+ All rights reserved.
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ * Redistributions of source code must retain the above copyright notice,
9
+ this list of conditions and the following disclaimer.
10
+
11
+ * Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ * Neither the names of The University of Manchester nor the names of its
16
+ contributors may be used to endorse or promote products derived from this
17
+ software without specific prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
+ POSSIBILITY OF SUCH DAMAGE.
data/README.rdoc ADDED
@@ -0,0 +1,21 @@
1
+ = Taverna[http://www.taverna.org.uk/] 2 Server Interaction Gem
2
+
3
+ Authors:: Robert Haines
4
+ Version:: 0.1
5
+ Contact:: mailto:rhaines@manchester.ac.uk
6
+ URL:: http://taverna.sourceforge.net/
7
+ Licence:: BSD (See LICENCE or http://www.opensource.org/licenses/bsd-license.php)
8
+ Copyright:: (c) 2010 The University of Manchester, UK
9
+
10
+
11
+ == Synopsis
12
+
13
+ This is a Ruby library to interface with the Taverna 2 Server REST interface.
14
+
15
+ == Installation
16
+
17
+ [sudo] gem install t2-server
18
+
19
+ == Usage
20
+
21
+ TBC
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env ruby
2
+ # Copyright (c) 2010, The University of Manchester, UK.
3
+ #
4
+ # All rights reserved.
5
+ #
6
+ # Redistribution and use in source and binary forms, with or without
7
+ # modification, are permitted provided that the following conditions are met:
8
+ #
9
+ # * Redistributions of source code must retain the above copyright notice,
10
+ # this list of conditions and the following disclaimer.
11
+ #
12
+ # * Redistributions in binary form must reproduce the above copyright notice,
13
+ # this list of conditions and the following disclaimer in the documentation
14
+ # and/or other materials provided with the distribution.
15
+ #
16
+ # * Neither the names of The University of Manchester nor the names of its
17
+ # contributors may be used to endorse or promote products derived from this
18
+ # software without specific prior written permission.
19
+ #
20
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30
+ # POSSIBILITY OF SUCH DAMAGE.
31
+ #
32
+ # Author: Robert Haines
33
+
34
+ require 't2server'
35
+ require 'optparse'
36
+
37
+ # set up options
38
+ opts = OptionParser.new do |opt|
39
+ opt.banner = "Usage: delete_all_runs [options] server-address"
40
+ opt.separator ""
41
+ opt.separator " Where server-address is the full URI of the server to"
42
+ opt.separator " connect to, e.g.: http://example.com:8080/taverna"
43
+ opt.separator " and [options] can be:"
44
+ opt.on_tail("-h", "-?", "--help", "Show this message") do
45
+ puts opt
46
+ exit
47
+ end
48
+ opt.on_tail("-v", "--version", "Show the version") do
49
+ puts "Taverna 2 Server Ruby Gem version: #{T2Server::GEM_VERSION}"
50
+ puts "Taverna 2 Server REST API version: #{T2Server::API_VERSION}"
51
+ exit
52
+ end
53
+ end
54
+
55
+ # parse options
56
+ opts.parse!
57
+
58
+ # check for server address
59
+ if ARGV[0] == nil
60
+ puts opts
61
+ exit 1
62
+ end
63
+
64
+ # connect and delete them all!
65
+ T2Server::Server.connect(ARGV[0]).delete_all_runs
data/bin/run_workflow ADDED
@@ -0,0 +1,138 @@
1
+ #!/usr/bin/env ruby
2
+ # Copyright (c) 2010, The University of Manchester, UK.
3
+ #
4
+ # All rights reserved.
5
+ #
6
+ # Redistribution and use in source and binary forms, with or without
7
+ # modification, are permitted provided that the following conditions are met:
8
+ #
9
+ # * Redistributions of source code must retain the above copyright notice,
10
+ # this list of conditions and the following disclaimer.
11
+ #
12
+ # * Redistributions in binary form must reproduce the above copyright notice,
13
+ # this list of conditions and the following disclaimer in the documentation
14
+ # and/or other materials provided with the distribution.
15
+ #
16
+ # * Neither the names of The University of Manchester nor the names of its
17
+ # contributors may be used to endorse or promote products derived from this
18
+ # software without specific prior written permission.
19
+ #
20
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30
+ # POSSIBILITY OF SUCH DAMAGE.
31
+ #
32
+ # Author: Robert Haines
33
+
34
+ require 't2server'
35
+ require 'optparse'
36
+
37
+ # go through the outputs and either print the contents
38
+ # out or save them to a file.
39
+ # if the output is a list, it appears as a directory so
40
+ # all the individual entries must be grabbed from there.
41
+ # server seems to be rather sensitive to slashes, hence
42
+ # all the [...] mucking about.
43
+ def get_outputs(run, pout, dir="")
44
+ outputs = run.ls("out#{dir}")
45
+ outputs.each do |out|
46
+ if out.include? "/"
47
+ get_outputs(run, pout, "#{dir}/#{out[0...-1]}")
48
+ else
49
+ print " #{dir}/#{out} -> "
50
+ data = run.get_output("#{dir[1..-1]}/#{out}")
51
+ if pout
52
+ p data
53
+ else
54
+ filename = "#{dir[1..-1]}/#{out}".gsub('/','-')
55
+ File.open(filename, "w") do |file|
56
+ file.syswrite(data)
57
+ end
58
+ puts "written to file: #{filename}"
59
+ end
60
+ end
61
+ end
62
+ end
63
+
64
+ # set up options
65
+ inputs = {}
66
+ wkf_file = ""
67
+ print_output = true
68
+ opts = OptionParser.new do |opt|
69
+ opt.banner = "Usage: run_workflow [options] server-address"
70
+ opt.separator ""
71
+ opt.separator " Where server-address is the full URI of the server to"
72
+ opt.separator " connect to, e.g.: http://example.com:8080/taverna"
73
+ opt.separator " and [options] can be:"
74
+ opt.on("-w WORKFLOW", "--workflow=WORKFLOW", "The workflow to run. If this is not " +
75
+ "specified then the workflow is read from standard input") do |val|
76
+ wkf_file = val
77
+ end
78
+ opt.on("-i INPUT:VALUE", "--input=INPUT:VALUE", "Set input port INPUT to VALUE") do |val|
79
+ input, value = val.chomp.split(':')
80
+ inputs[input] = value
81
+ end
82
+ opt.on("-p", "--[no-]print", "Print outputs to the console. On by default") do |val|
83
+ print_output = val
84
+ end
85
+ opt.on_tail("-h", "-?", "--help", "Show this message") do
86
+ puts opt
87
+ exit
88
+ end
89
+ opt.on_tail("-v", "--version", "Show the version") do
90
+ puts "Taverna 2 Server Ruby Gem version: #{T2Server::GEM_VERSION}"
91
+ puts "Taverna 2 Server REST API version: #{T2Server::API_VERSION}"
92
+ exit
93
+ end
94
+ end
95
+
96
+ # parse options
97
+ opts.parse!
98
+
99
+ # read and check server address
100
+ uri = ARGV.shift
101
+ if uri == nil
102
+ puts opts
103
+ exit 1
104
+ end
105
+
106
+ # read workflow
107
+ if wkf_file == ""
108
+ wkf = ARGF.read
109
+ else
110
+ wkf = IO.read(wkf_file)
111
+ end
112
+
113
+ # create run and set inputs
114
+ run = T2Server::Run.create(uri, wkf)
115
+ puts "Created run with uuid: #{run.uuid}"
116
+
117
+ inputs.each do |input, value|
118
+ puts "Set input '#{input}' to #{value}"
119
+ run.set_input(input, value)
120
+ end
121
+
122
+ # start run and wait until it is finished
123
+ print "Running"
124
+ run.start_and_wait(:progress => true)
125
+
126
+ # get outputs
127
+ stdout = run.stdout
128
+ stderr = run.stderr
129
+ puts "Exitcode: #{run.exitcode}"
130
+ if stdout != "" then puts "Stdout:\n #{stdout}" end
131
+ if stderr != "" then puts "Stderr:\n #{stderr}" end
132
+
133
+ puts "Outputs:"
134
+ get_outputs(run, print_output)
135
+
136
+ # delete run
137
+ run.delete
138
+ puts "Finished and deleted run"
data/lib/t2server.rb ADDED
@@ -0,0 +1,40 @@
1
+ # Copyright (c) 2010, The University of Manchester, UK.
2
+ #
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # * Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ #
11
+ # * Redistributions in binary form must reproduce the above copyright notice,
12
+ # this list of conditions and the following disclaimer in the documentation
13
+ # and/or other materials provided with the distribution.
14
+ #
15
+ # * Neither the names of The University of Manchester nor the names of its
16
+ # contributors may be used to endorse or promote products derived from this
17
+ # software without specific prior written permission.
18
+ #
19
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
+ # POSSIBILITY OF SUCH DAMAGE.
30
+ #
31
+ # Author: Robert Haines
32
+
33
+ require 't2server/xml'
34
+ require 't2server/server'
35
+ require 't2server/run'
36
+
37
+ module T2Server
38
+ GEM_VERSION = "0.0.1"
39
+ API_VERSION = "2.2.0a1"
40
+ end
@@ -0,0 +1,228 @@
1
+ # Copyright (c) 2010, The University of Manchester, UK.
2
+ #
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # * Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ #
11
+ # * Redistributions in binary form must reproduce the above copyright notice,
12
+ # this list of conditions and the following disclaimer in the documentation
13
+ # and/or other materials provided with the distribution.
14
+ #
15
+ # * Neither the names of The University of Manchester nor the names of its
16
+ # contributors may be used to endorse or promote products derived from this
17
+ # software without specific prior written permission.
18
+ #
19
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
+ # POSSIBILITY OF SUCH DAMAGE.
30
+ #
31
+ # Author: Robert Haines
32
+
33
+ require 'rexml/document'
34
+ include REXML
35
+
36
+ module T2Server
37
+
38
+ class Run
39
+
40
+ STATE = {
41
+ :initialized => "Initialized",
42
+ :running => "Operating",
43
+ :finished => "Finished",
44
+ :stopped => "Stopped"
45
+ }
46
+
47
+ private_class_method :new
48
+ attr_reader :uuid
49
+
50
+ def initialize(server, uuid)
51
+ @server = server
52
+ @uuid = uuid
53
+ @workflow = ""
54
+ @baclava = false
55
+
56
+ @links = get_attributes(@server.get_run_attribute(uuid, ""))
57
+ #@links.each {|key, val| puts "#{key}: #{val}"}
58
+ end
59
+
60
+ def Run.create(server, workflow, uuid="")
61
+ if server.class == String
62
+ server = Server.connect(server)
63
+ end
64
+ if uuid == ""
65
+ new(server, server.initialize_run(workflow))
66
+ else
67
+ new(server, uuid)
68
+ end
69
+ end
70
+
71
+ def delete
72
+ @server.delete_run uuid
73
+ end
74
+
75
+ def inputs
76
+ @links[:inputs]
77
+ end
78
+
79
+ def set_input(input, value)
80
+ @server.set_run_input(self, input, value)
81
+ end
82
+
83
+ def set_input_file(input, filename)
84
+ @server.set_run_input_file(self, input, filename)
85
+ end
86
+
87
+ def get_output(output, type="text/plain")
88
+ return unless finished? ### raise exception?
89
+ doc = @server.get_run_attribute(@uuid, "#{@links[:wdir]}/out/#{output}")
90
+ doc
91
+ end
92
+
93
+ def expiry
94
+ @server.get_run_attribute(@uuid, @links[:expiry])
95
+ end
96
+
97
+ def expiry=(date)
98
+ @server.set_run_attribute(@uuid, @links[:expiry], date)
99
+ end
100
+
101
+ def workflow
102
+ if @workflow == ""
103
+ @workflow = @server.get_run_attribute(@uuid, @links[:workflow])
104
+ end
105
+ @workflow
106
+ end
107
+
108
+ def status
109
+ @server.get_run_attribute(@uuid, @links[:status])
110
+ end
111
+
112
+ def start
113
+ @server.set_run_attribute(@uuid, @links[:status], STATE[:running])
114
+ end
115
+
116
+ def start_and_wait(params={})
117
+ interval = params[:interval] || 1
118
+ progress = params[:progress] || false
119
+ keepalive = params[:keepalive] || false ### TODO maybe move out of params
120
+
121
+ # start run and wait
122
+ start
123
+ until finished?
124
+ sleep(interval)
125
+ if progress
126
+ print "."
127
+ STDOUT.flush
128
+ end
129
+ end
130
+
131
+ # tidy up output if there is any
132
+ puts if progress
133
+ end
134
+
135
+ def exitcode
136
+ @server.get_run_attribute(@uuid, @links[:exitcode]).to_i
137
+ end
138
+
139
+ def stdout
140
+ @server.get_run_attribute(@uuid, @links[:stdout])
141
+ end
142
+
143
+ def stderr
144
+ @server.get_run_attribute(@uuid, @links[:stderr])
145
+ end
146
+
147
+ def mkdir(dir)
148
+ @server.make_run_dir(@uuid, @links[:wdir], dir)
149
+ end
150
+
151
+ def upload_file(filename, params={})
152
+ location = params[:dir] || ""
153
+ location = "#{@links[:wdir]}/#{location}"
154
+ rename = params[:rename] || ""
155
+ @server.upload_run_file(@uuid, filename, location, rename)
156
+ end
157
+
158
+ def upload_input_file(input, filename, params={})
159
+ file = upload_file(filename, params)
160
+ set_input_file(input, file)
161
+ end
162
+
163
+ def upload_baclava_file(filename)
164
+ @baclava = true
165
+ rename = upload_file(filename)
166
+ @server.set_run_attribute(@uuid, @links[:baclava], rename)
167
+ end
168
+
169
+ def ls(dir="")
170
+ dir_list = @server.get_run_attribute(@uuid, "#{@links[:wdir]}/#{dir}")
171
+ doc = Document.new(dir_list)
172
+
173
+ # compile a list of directory entries stripping the
174
+ # directory name from the front of each filename
175
+ entries = []
176
+ XPath.each(doc, "//nss:dir", Namespaces::MAP) {|e| entries << "#{e.text.split('/')[-1]}/"}
177
+ XPath.each(doc, "//nss:file", Namespaces::MAP) {|e| entries << e.text.split('/')[-1]}
178
+ entries
179
+ end
180
+
181
+ def initialized?
182
+ status == STATE[:initialized]
183
+ end
184
+
185
+ def running?
186
+ status == STATE[:running]
187
+ end
188
+
189
+ def finished?
190
+ status == STATE[:finished]
191
+ end
192
+
193
+ private
194
+ def get_attributes(desc)
195
+ # first parse out the basic stuff
196
+ links = parse_description(desc)
197
+
198
+ # get inputs
199
+ inputs = @server.get_run_attribute(@uuid, links[:inputs])
200
+ doc = Document.new(inputs)
201
+ nsmap = Namespaces::MAP
202
+ links[:baclava] = "#{links[:inputs]}/" + XPath.first(doc, "//nsr:baclava", nsmap).attributes["href"].split('/')[-1]
203
+
204
+ # set io properties
205
+ links[:io] = "#{links[:listeners]}/io"
206
+ links[:stdout] = "#{links[:io]}/properties/stdout"
207
+ links[:stderr] = "#{links[:io]}/properties/stderr"
208
+ links[:exitcode] = "#{links[:io]}/properties/exitcode"
209
+
210
+ links
211
+ end
212
+
213
+ def parse_description(desc)
214
+ doc = Document.new(desc)
215
+ nsmap = Namespaces::MAP
216
+ {
217
+ :expiry => XPath.first(doc, "//nsr:expiry", nsmap).attributes["href"].split('/')[-1],
218
+ :workflow => XPath.first(doc, "//nsr:creationWorkflow", nsmap).attributes["href"].split('/')[-1],
219
+ :status => XPath.first(doc, "//nsr:status", nsmap).attributes["href"].split('/')[-1],
220
+ :wdir => XPath.first(doc, "//nsr:workingDirectory", nsmap).attributes["href"].split('/')[-1],
221
+ :inputs => XPath.first(doc, "//nsr:inputs", nsmap).attributes["href"].split('/')[-1],
222
+ :output => XPath.first(doc, "//nsr:output", nsmap).attributes["href"].split('/')[-1],
223
+ :securectx => XPath.first(doc, "//nsr:securityContext", nsmap).attributes["href"].split('/')[-1],
224
+ :listeners => XPath.first(doc, "//nsr:listeners", nsmap).attributes["href"].split('/')[-1]
225
+ }
226
+ end
227
+ end
228
+ end
@@ -0,0 +1,324 @@
1
+ # Copyright (c) 2010, The University of Manchester, UK.
2
+ #
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # * Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ #
11
+ # * Redistributions in binary form must reproduce the above copyright notice,
12
+ # this list of conditions and the following disclaimer in the documentation
13
+ # and/or other materials provided with the distribution.
14
+ #
15
+ # * Neither the names of The University of Manchester nor the names of its
16
+ # contributors may be used to endorse or promote products derived from this
17
+ # software without specific prior written permission.
18
+ #
19
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
+ # POSSIBILITY OF SUCH DAMAGE.
30
+ #
31
+ # Author: Robert Haines
32
+
33
+ require 'base64'
34
+ require 'uri'
35
+ require 'net/http'
36
+ require 'rexml/document'
37
+ include REXML
38
+
39
+ module T2Server
40
+ class Server
41
+ private_class_method :new
42
+ attr_reader :uri, :run_limit
43
+
44
+ # list of servers we know about
45
+ @@servers = []
46
+
47
+ def initialize(uri)
48
+ @uri = uri
49
+ uri = URI.parse(uri)
50
+ @host = uri.host
51
+ @port = uri.port
52
+ @base_path = uri.path
53
+ @rest_path = uri.path + "/rest"
54
+ @links = get_server_description
55
+ #@links.each {|key, val| puts "#{key}: #{val}"}
56
+
57
+ # get max runs
58
+ @run_limit = get_attribute(@links[:runlimit]).to_i
59
+
60
+ # initialise run list
61
+ @runs = {}
62
+ @runs = runs
63
+ end
64
+
65
+ def Server.connect(uri)
66
+ # see if we've already got this server
67
+ server = @@servers.find {|s| s.uri == uri}
68
+
69
+ if !server
70
+ # no, so create new one and return it
71
+ server = new(uri)
72
+ @@servers << server
73
+ end
74
+
75
+ server
76
+ end
77
+
78
+ def create_run(workflow)
79
+ uuid = initialize_run(workflow)
80
+ @runs[uuid] = Run.create(self, "", uuid)
81
+ end
82
+
83
+ def initialize_run(workflow)
84
+ request = Net::HTTP::Post.new("#{@links[:runs]}")
85
+ request.content_type = "application/xml"
86
+ response = Net::HTTP.new(@host, @port).start do |http|
87
+ http.request(request, Fragments::WORKFLOW % workflow)
88
+ end
89
+
90
+ case response
91
+ when Net::HTTPCreated
92
+ # return the uuid of the newly created run
93
+ epr = URI.parse(response['location'])
94
+ epr.path[-36..-1]
95
+ when Net::HTTPForbidden
96
+ puts "Sorry, but the server is already running its configured limit of concurrent workflows."
97
+ puts "Please try again later."
98
+ ""
99
+ else
100
+ response_error(response)
101
+ ""
102
+ end
103
+ end
104
+
105
+ def runs
106
+ request = Net::HTTP::Get.new("#{@links[:runs]}")
107
+ response = Net::HTTP.new(@host, @port).start {|http| http.request(request)}
108
+
109
+ case response
110
+ when Net::HTTPOK
111
+ doc = Document.new(response.body)
112
+
113
+ # get list of run uuids
114
+ uuids = []
115
+ XPath.each(doc, "//nsr:run", Namespaces::MAP) do |run|
116
+ uuids << run.attributes["href"].split('/')[-1]
117
+ end
118
+
119
+ # add new runs
120
+ uuids.each do |uuid|
121
+ if !@runs.has_key? uuid
122
+ description = get_run_description(uuid)
123
+ @runs[uuid] = Run.create(self, "", uuid)
124
+ end
125
+ end
126
+
127
+ # clear out the expired runs
128
+ if @runs.length > @run_limit
129
+ @runs.delete_if {|key, val| !uuids.member? key}
130
+ end
131
+
132
+ @runs
133
+ else
134
+ response_error(response)
135
+ end
136
+ end
137
+
138
+ def delete_run(uuid)
139
+ request = Net::HTTP::Delete.new("#{@links[:runs]}/#{uuid}")
140
+ response = Net::HTTP.new(@host, @port).start {|http| http.request(request)}
141
+
142
+ case response
143
+ when Net::HTTPNoContent
144
+ # Success, carry on...
145
+ @runs.delete(uuid)
146
+ true
147
+ when Net::HTTPNotFound
148
+ puts "Cannot find run #{run.uuid}."
149
+ false
150
+ else
151
+ response_error(response)
152
+ end
153
+ end
154
+
155
+ def delete_all_runs
156
+ # first refresh run list
157
+ runs.each_value {|run| run.delete}
158
+ end
159
+
160
+ def set_run_input(run, input, value)
161
+ request = Net::HTTP::Put.new("#{@links[:runs]}/#{run.uuid}/#{run.inputs}/input/#{input}")
162
+ request.content_type = "application/xml"
163
+ response = Net::HTTP.new(@host, @port).start do |http|
164
+ http.request(request, Fragments::RUNINPUTVALUE % value)
165
+ end
166
+
167
+ case response
168
+ when Net::HTTPOK
169
+ # Yay!
170
+ true
171
+ else
172
+ response_error(response)
173
+ end
174
+ end
175
+
176
+ def set_run_input_file(run, input, filename)
177
+ request = Net::HTTP::Put.new("#{@links[:runs]}/#{run.uuid}/#{run.inputs}/input/#{input}")
178
+ request.content_type = "application/xml"
179
+ response = Net::HTTP.new(@host, @port).start do |http|
180
+ http.request(request, Fragments::RUNINPUTFILE % filename)
181
+ end
182
+
183
+ case response
184
+ when Net::HTTPOK
185
+ # Yay!
186
+ true
187
+ else
188
+ response_error(response)
189
+ end
190
+ end
191
+
192
+ def make_run_dir(uuid, root, dir)
193
+ request = Net::HTTP::Post.new("#{@links[:runs]}/#{uuid}/#{root}")
194
+ request.content_type = "application/xml"
195
+ response = Net::HTTP.new(@host, @port).start do |http|
196
+ http.request(request, Fragments::MKDIR % dir)
197
+ end
198
+
199
+ case response
200
+ when Net::HTTPCreated
201
+ # OK, carry on...
202
+ true
203
+ when Net::HTTPForbidden
204
+ puts "Error!", response.body
205
+ false
206
+ when Net::HTTPNotFound
207
+ puts "Cannot find run #{uuid}."
208
+ false
209
+ else
210
+ response_error(response)
211
+ end
212
+ end
213
+
214
+ def upload_run_file(uuid, filename, location, rename)
215
+ contents = Base64.encode64(IO.read(filename))
216
+ rename = filename.split('/')[-1] if rename == ""
217
+ request = Net::HTTP::Post.new("#{@links[:runs]}/#{uuid}/#{location}")
218
+ request.content_type = "application/xml"
219
+ response = Net::HTTP.new(@host, @port).start do |http|
220
+ http.request(request, Fragments::UPLOAD % [rename, contents])
221
+ end
222
+
223
+ case response
224
+ when Net::HTTPCreated
225
+ # Success, return remote name of uploaded file
226
+ rename
227
+ when Net::HTTPForbidden
228
+ puts "Error!", response.body
229
+ else
230
+ response_error(response)
231
+ end
232
+ end
233
+
234
+ def get_run_attribute(uuid, path)
235
+ get_attribute("#{@links[:runs]}/#{uuid}/#{path}")
236
+ end
237
+
238
+ def set_run_attribute(uuid, path, value)
239
+ request = Net::HTTP::Put.new("#{@links[:runs]}/#{uuid}/#{path}")
240
+ request.content_type = "text/plain"
241
+ response = Net::HTTP.new(@host, @port).start {|http| http.request(request, value)}
242
+
243
+ case response
244
+ when Net::HTTPOK
245
+ # OK, so carry on
246
+ true
247
+ when Net::HTTPForbidden
248
+ puts "Error!"
249
+ puts response.body
250
+ false
251
+ when Net::HTTPNotFound
252
+ puts "Cannot find run #{uuid}."
253
+ false
254
+ else
255
+ response_error(response)
256
+ end
257
+ end
258
+
259
+ protected
260
+ def get_attribute(path)
261
+ request = Net::HTTP::Get.new(path)
262
+ response = Net::HTTP.new(@host, @port).start {|http| http.request(request)}
263
+
264
+ case response
265
+ when Net::HTTPOK
266
+ return response.body
267
+ when Net::HTTPNotFound
268
+ puts "Cannot find attribute #{path}."
269
+ else
270
+ response_error(response)
271
+ end
272
+ end
273
+
274
+ private
275
+ def get_server_description
276
+ request = Net::HTTP::Get.new(@rest_path)
277
+ response = Net::HTTP.new(@host, @port).start {|http| http.request(request)}
278
+
279
+ case response
280
+ when Net::HTTPOK
281
+ parse_description(response.body)
282
+ else
283
+ response_error(response)
284
+ end
285
+ end
286
+
287
+ def parse_description(desc)
288
+ doc = Document.new(desc)
289
+ nsmap = Namespaces::MAP
290
+ {
291
+ :runs => URI.parse(XPath.first(doc, "//nsr:runs", nsmap).attributes["href"]).path,
292
+ :runlimit => URI.parse(XPath.first(doc, "//nsr:runLimit", nsmap).attributes["href"]).path,
293
+ :permworkflows => URI.parse(XPath.first(doc, "//nsr:permittedWorkflows", nsmap).attributes["href"]).path,
294
+ :permlisteners => URI.parse(XPath.first(doc, "//nsr:permittedListeners", nsmap).attributes["href"]).path
295
+ }
296
+ end
297
+
298
+ def get_run_description(uuid)
299
+ request = Net::HTTP::Get.new("#{@links[:runs]}/#{uuid}")
300
+ response = Net::HTTP.new(@host, @port).start {|http| http.request(request)}
301
+
302
+ case response
303
+ when Net::HTTPOK
304
+ return response.body
305
+ when Net::HTTPNotFound
306
+ puts "Cannot find run #{uuid}."
307
+ else
308
+ response_error(response)
309
+ end
310
+ end
311
+
312
+ def response_error(response)
313
+ puts "Unnexpected response from Taverna Server!"
314
+ puts "Server is: #{@host}:#{@port}#{@base_path}"
315
+ puts "Response code is: #{response.code}"
316
+ if response.body
317
+ puts "Response body is: \n#{response.body}"
318
+ end
319
+ puts "\nRaw error is: \n#{response.error!}"
320
+ false
321
+ end
322
+
323
+ end
324
+ end
@@ -0,0 +1,51 @@
1
+ # Copyright (c) 2010, The University of Manchester, UK.
2
+ #
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # * Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ #
11
+ # * Redistributions in binary form must reproduce the above copyright notice,
12
+ # this list of conditions and the following disclaimer in the documentation
13
+ # and/or other materials provided with the distribution.
14
+ #
15
+ # * Neither the names of The University of Manchester nor the names of its
16
+ # contributors may be used to endorse or promote products derived from this
17
+ # software without specific prior written permission.
18
+ #
19
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
+ # POSSIBILITY OF SUCH DAMAGE.
30
+ #
31
+ # Author: Robert Haines
32
+
33
+ module T2Server
34
+ module Namespaces
35
+ SERVER = "http://ns.taverna.org.uk/2010/xml/server/"
36
+ REST = SERVER + "rest/"
37
+ MAP = {
38
+ "nss" => Namespaces::SERVER,
39
+ "nsr" => Namespaces::REST
40
+ }
41
+ end
42
+
43
+ module Fragments
44
+ WORKFLOW = "<t2s:scufl xmlns:t2s=\"#{Namespaces::SERVER}\">\n %s\n</t2s:scufl>"
45
+ RUNINPUT = "<t2sr:runInput xmlns:t2sr=\"#{Namespaces::REST}\">\n %s\n</t2sr:runInput>"
46
+ RUNINPUTVALUE = RUNINPUT % "<t2sr:value>%s</t2sr:value>"
47
+ RUNINPUTFILE = RUNINPUT % "<t2sr:file>%s</t2sr:file>"
48
+ UPLOAD = "<t2sr:upload xmlns:t2sr=\"#{Namespaces::REST}\" t2sr:name=\"%s\">\n %s\n</t2sr:upload>"
49
+ MKDIR = "<t2sr:mkdir xmlns:t2sr=\"#{Namespaces::REST}\" t2sr:name=\"%s\" />"
50
+ end
51
+ end
metadata ADDED
@@ -0,0 +1,75 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: t2-server
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Robert Haines
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-07-21 00:00:00 +01:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: This gem provides access to the Taverna 2 Server REST interface from Ruby.
23
+ email: rhaines@manchester.ac.uk
24
+ executables: []
25
+
26
+ extensions: []
27
+
28
+ extra_rdoc_files:
29
+ - README.rdoc
30
+ - LICENCE
31
+ files:
32
+ - bin/run_workflow
33
+ - bin/delete_all_runs
34
+ - lib/t2server.rb
35
+ - lib/t2server/server.rb
36
+ - lib/t2server/xml.rb
37
+ - lib/t2server/run.rb
38
+ - README.rdoc
39
+ - LICENCE
40
+ has_rdoc: true
41
+ homepage: http://www.taverna.org.uk/
42
+ licenses: []
43
+
44
+ post_install_message:
45
+ rdoc_options: []
46
+
47
+ require_paths:
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ hash: 3
55
+ segments:
56
+ - 0
57
+ version: "0"
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ none: false
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ hash: 3
64
+ segments:
65
+ - 0
66
+ version: "0"
67
+ requirements: []
68
+
69
+ rubyforge_project:
70
+ rubygems_version: 1.3.7
71
+ signing_key:
72
+ specification_version: 3
73
+ summary: Support for interacting with Taverna 2 Server.
74
+ test_files: []
75
+