opentox-client 0.0.2pre → 1.0.0pre1

Sign up to get free protection for your applications and to get access to all the features.
@@ -6,8 +6,9 @@ module OpenTox
6
6
  # @param [Hash] params Parameters for OpenTox model
7
7
  # @param [optional,OpenTox::Task] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
8
8
  # @return [text/uri-list] Task or resource URI
9
- def run params=nil
10
- post params, {:accept => 'text/uri-list'}
9
+ def run params=nil, wait=true
10
+ uri = RestClientWrapper.post @uri, params, { :content_type => "text/uri-list", :subjectid => @subjectid}
11
+ wait_for_task uri if wait
11
12
  end
12
13
 
13
14
  end
@@ -2,34 +2,39 @@ require 'rubygems'
2
2
  require "bundler/setup"
3
3
  require 'rdf'
4
4
  require 'rdf/raptor'
5
+ require 'rdf/n3'
5
6
  require "rest-client"
6
7
  require 'uri'
7
8
  require 'yaml'
8
9
  require 'json'
9
10
  require 'logger'
11
+ require "securerandom"
10
12
 
11
13
  # define constants and global variables
12
14
  #TODO: switch services to 1.2
13
15
  RDF::OT = RDF::Vocabulary.new 'http://www.opentox.org/api/1.2#'
14
16
  RDF::OT1 = RDF::Vocabulary.new 'http://www.opentox.org/api/1.1#'
15
17
  RDF::OTA = RDF::Vocabulary.new 'http://www.opentox.org/algorithmTypes.owl#'
18
+ RDF::OLO = RDF::Vocabulary.new 'http://purl.org/ontology/olo/core#'
16
19
 
17
- #CLASSES = ["Compound", "Feature", "Dataset", "Algorithm", "Model", "Validation", "Task", "ErrorReport", "Investigation"]
18
20
  CLASSES = ["Generic", "Compound", "Feature", "Dataset", "Algorithm", "Model", "Validation", "Task", "Investigation"]
19
21
  RDF_FORMATS = [:rdfxml,:ntriples,:turtle]
20
- $default_rdf = "application/rdf+xml"
21
22
 
22
23
  # Regular expressions for parsing classification data
23
24
  TRUE_REGEXP = /^(true|active|1|1.0|tox|activating|carcinogen|mutagenic)$/i
24
25
  FALSE_REGEXP = /^(false|inactive|0|0.0|low tox|deactivating|non-carcinogen|non-mutagenic)$/i
25
26
 
26
- require File.join(File.dirname(__FILE__),"overwrite.rb")
27
- require File.join(File.dirname(__FILE__),"error.rb")
28
- require File.join(File.dirname(__FILE__),"rest-client-wrapper.rb")
29
- require File.join(File.dirname(__FILE__),"authorization.rb")
30
- require File.join(File.dirname(__FILE__),"policy.rb")
31
- require File.join(File.dirname(__FILE__),"otlogger.rb") # avoid require conflicts with logger
32
- require File.join(File.dirname(__FILE__),"opentox.rb")
33
- require File.join(File.dirname(__FILE__),"task.rb")
34
- require File.join(File.dirname(__FILE__),"compound.rb")
35
- require File.join(File.dirname(__FILE__),"dataset.rb")
27
+ [
28
+ "overwrite.rb",
29
+ "rest-client-wrapper.rb",
30
+ "error.rb",
31
+ "authorization.rb",
32
+ "policy.rb",
33
+ "otlogger.rb",
34
+ "opentox.rb",
35
+ "task.rb",
36
+ "compound.rb",
37
+ "dataset.rb",
38
+ "model.rb",
39
+ ].each{ |f| require File.join(File.dirname(__FILE__),f) }
40
+
@@ -4,7 +4,7 @@ $logger.level = Logger::DEBUG
4
4
 
5
5
  module OpenTox
6
6
 
7
- attr_accessor :uri, :subjectid, :rdf, :response, :reload
7
+ attr_accessor :uri, :subjectid, :rdf
8
8
 
9
9
  # Ruby interface
10
10
 
@@ -13,134 +13,156 @@ module OpenTox
13
13
  # @param [optional,String] subjectid
14
14
  # @return [OpenTox] OpenTox object
15
15
  def initialize uri=nil, subjectid=nil
16
- @uri = uri.to_s.chomp
17
- @subjectid = subjectid
18
- @reload = true
19
16
  @rdf = RDF::Graph.new
17
+ if uri
18
+ @uri = uri.to_s.chomp
19
+ else
20
+ service = self.class.to_s.split('::').last.downcase
21
+ service_uri = eval("$#{service}[:uri]")
22
+ bad_request_error "$#{service}[:uri] variable not set. Please set $#{service}[:uri] or use an explicit uri as first constructor argument " unless service_uri
23
+ @uri = File.join service_uri, SecureRandom.uuid
24
+ end
25
+ append RDF.type, eval("RDF::OT."+self.class.to_s.split('::').last)
26
+ append RDF::DC.date, DateTime.now
27
+ @subjectid = subjectid
20
28
  end
21
29
 
22
- # Load metadata from service
23
- def pull
24
- # TODO generic method for all formats
25
- parse_rdfxml RestClientWrapper.get(@uri,{},{:accept => $default_rdf, :subjectid => @subjectid})
26
- end
27
-
28
- # Get object metadata
29
- # @return [Hash] Metadata
30
+ # Object metadata
31
+ # @return [Hash] Object metadata
30
32
  def metadata
31
- pull if @reload # force update
32
- @rdf.to_hash[RDF::URI.new(@uri)]
33
+ # return plain strings instead of RDF objects
34
+ @rdf.to_hash[RDF::URI.new(@uri)].inject({}) { |h, (predicate, values)| h[predicate.to_s] = values.collect{|v| v.to_s}; h }
33
35
  end
34
36
 
35
- # Get metadata values
36
- # @param [RDF] Key from RDF Vocabularies
37
- # @return [Array] Values for supplied key
38
- def [](key)
39
- pull if @reload # force update
40
- result = @rdf.query([RDF::URI.new(@uri),key,nil]).collect{|statement| statement.object}
41
- # TODO: convert to OpenTox objects??
42
- return nil if result and result.empty?
43
- return result.first.to_s if result.size == 1
44
- return result.collect{|r| r.to_s}
45
- result
37
+ # Metadata values
38
+ # @param [String] Predicate URI
39
+ # @return [Array, String] Predicate value(s)
40
+ def [](predicate)
41
+ return nil if metadata[predicate.to_s].nil?
42
+ metadata[predicate.to_s].size == 1 ? metadata[predicate.to_s].first : metadata[predicate.to_s]
46
43
  end
47
44
 
48
- # Save object at service
49
- def save
50
- #TODO: dynamic assignment
51
- post self.to_rdfxml, { :content_type => $default_rdf}
45
+ # Set object metadata
46
+ # @param [String] Predicate URI
47
+ # @param [Array, String] Predicate value(s)
48
+ def []=(predicate,values)
49
+ @rdf.delete [RDF::URI.new(@uri.to_s),RDF::URI.new(predicate.to_s),nil]
50
+ append predicate.to_s, values
52
51
  end
53
52
 
54
- RDF_FORMATS.each do |format|
55
-
56
- # rdf parse methods for all formats e.g. parse_rdfxml
57
- send :define_method, "parse_#{format}".to_sym do |rdf|
58
- @rdf = RDF::Graph.new
59
- RDF::Reader.for(format).new(rdf) do |reader|
60
- reader.each_statement{ |statement| @rdf << statement }
61
- end
53
+ def parameters
54
+ params = {}
55
+ query = RDF::Query.new({
56
+ :parameter => {
57
+ RDF.type => RDF::OT.Parameter,
58
+ :property => :value,
59
+ }
60
+ })
61
+ query.execute(@rdf).each do |solution|
62
+ params[solution.parameter] = {} unless params[solution.parameter]
63
+ params[solution.parameter][solution.property.to_s] = solution.value.to_s
62
64
  end
65
+ params.values
66
+ end
63
67
 
64
- # rdf serialization methods for all formats e.g. to_rdfxml
65
- send :define_method, "to_#{format}".to_sym do
66
- rdf = RDF::Writer.for(format).buffer do |writer|
67
- @rdf.each{|statement| writer << statement}
68
- end
69
- rdf
68
+ def parameters=(parameters)
69
+ parameters.each do |param|
70
+ p_node = RDF::Node.new
71
+ @rdf << [RDF::URI.new(@uri), RDF::OT.parameters, p_node]
72
+ @rdf << [p_node, RDF.type, RDF::OT.Parameter]
73
+ param.each{ |p,o| @rdf << [p_node, p, o] }
70
74
  end
71
75
  end
72
76
 
73
- def to_yaml
74
- @rdf.to_hash.to_yaml
77
+ # Append object metadata
78
+ # @param [String] Predicate URI
79
+ # @param [Array, String] Predicate value(s)
80
+ def append(predicate,values)
81
+ uri = RDF::URI.new @uri
82
+ predicate = RDF::URI.new predicate
83
+ [values].flatten.each { |value| @rdf << [uri, predicate, value] }
75
84
  end
76
85
 
77
- def to_json
78
- to_hash.to_json
86
+ # Get object from webservice
87
+ def get mime_type="text/plain"
88
+ response = RestClientWrapper.get(@uri,{},{:accept => mime_type, :subjectid => @subjectid})
89
+ if URI.task?(response)
90
+ wait_for_task response
91
+ response = RestClientWrapper.get(t.resultURI,{},{:accept => mime_type, :subjectid => @subjectid})
92
+ end
93
+ parse_ntriples response if mime_type == "text/plain"
94
+ parse_rdfxml response if mime_type == "application/rdf+xml"
79
95
  end
80
96
 
81
- # REST API
82
- def get headers={}
83
- headers[:subjectid] ||= @subjectid
84
- headers[:accept] ||= 'application/rdf+xml'
85
- @response = RestClientWrapper.get @uri, {}, headers
97
+ # Post object to webservice
98
+ def post service_uri, wait=true
99
+ # TODO: RDFXML
100
+ uri = RestClientWrapper.post service_uri, to_ntriples, { :content_type => "text/plain", :subjectid => @subjectid}
101
+ wait_for_task uri if wait
86
102
  end
87
103
 
88
- def post payload={}, headers={}
89
- headers[:subjectid] ||= @subjectid
90
- headers[:accept] ||= 'application/rdf+xml'
91
- @response = RestClientWrapper.post(@uri.to_s, payload, headers)
104
+ # Save object at webservice
105
+ def put wait=true
106
+ # TODO: RDFXML
107
+ append RDF::DC.modified, DateTime.now
108
+ uri = RestClientWrapper.put @uri.to_s, self.to_ntriples, { :content_type => "text/plain", :subjectid => @subjectid}
109
+ wait_for_task uri if wait
92
110
  end
93
111
 
94
- def put payload={}, headers={}
95
- headers[:subjectid] ||= @subjectid
96
- headers[:accept] ||= 'application/rdf+xml'
97
- @response = RestClientWrapper.put(@uri.to_s, payload, headers)
112
+ # Delete object at webservice
113
+ def delete
114
+ RestClientWrapper.delete(@uri.to_s,nil,{:subjectid => @subjectid})
98
115
  end
99
116
 
100
- def delete headers={}
101
- headers[:subjectid] ||= @subjectid
102
- @response = RestClientWrapper.delete(@uri.to_s,nil,headers)
117
+ def wait_for_task uri
118
+ if URI.task?(uri)
119
+ t = OpenTox::Task.new uri
120
+ t.wait
121
+ unless t.completed?
122
+ #TODO raise correct error
123
+ #internal_server_error "Task #{uri} failed with #{$!.inspect}"
124
+ end
125
+ uri = t.resultURI
126
+ end
127
+ uri
103
128
  end
104
129
 
105
- # class methods
106
- module ClassMethods
130
+ RDF_FORMATS.each do |format|
107
131
 
108
- def all service_uri, subjectid=nil
109
- uris = RestClientWrapper.get(service_uri, {}, :accept => 'text/uri-list').split("\n").compact
110
- uris.collect{|uri| URI.task?(service_uri) ? from_uri(uri, subjectid, false) : from_uri(uri, subjectid)}
132
+ # rdf parse methods for all formats e.g. parse_rdfxml
133
+ send :define_method, "parse_#{format}".to_sym do |rdf|
134
+ @rdf = RDF::Graph.new
135
+ RDF::Reader.for(format).new(rdf) do |reader|
136
+ reader.each_statement{ |statement| @rdf << statement }
137
+ end
111
138
  end
112
139
 
113
- def create service_uri, subjectid=nil
114
- uri = RestClientWrapper.post(service_uri, {}, {:accept => 'text/uri-list', :subjectid => subjectid})
115
- URI.task?(service_uri) ? from_uri(uri, subjectid, false) : from_uri(uri, subjectid)
140
+ # rdf serialization methods for all formats e.g. to_rdfxml
141
+ send :define_method, "to_#{format}".to_sym do
142
+ RDF::Writer.for(format).buffer do |writer|
143
+ @rdf.each{|statement| writer << statement}
144
+ end
116
145
  end
146
+ end
117
147
 
118
- def from_file service_uri, filename, subjectid=nil
119
- file = File.new filename
120
- from_uri RestClientWrapper.post(service_uri, {:file => file}, {:subjectid => subjectid, :content_type => file.mime_type, :accept => "text/uri-list"}), subjectid
148
+ def to_turtle # redefine to use prefixes (not supported by RDF::Writer)
149
+ prefixes = {:rdf => "http://www.w3.org/1999/02/22-rdf-syntax-ns#"}
150
+ ['OT', 'DC', 'XSD', 'OLO'].each{|p| prefixes[p.downcase.to_sym] = eval("RDF::#{p}.to_s") }
151
+ RDF::N3::Writer.for(:turtle).buffer(:prefixes => prefixes) do |writer|
152
+ @rdf.each{|statement| writer << statement}
121
153
  end
154
+ end
122
155
 
123
- private
124
- def from_uri uri, subjectid=nil, wait=true
125
-
126
- uri.chomp!
127
- # TODO add waiting task
128
- if URI.task? uri and wait
129
- t = OpenTox::Task.new(uri)
130
- t.wait
131
- uri = t.resultURI
132
- end
133
-
134
- # guess class from uri, this is potentially unsafe, but polling metadata from large uri lists is way too slow (and not all service provide RDF.type in their metadata)
135
- result = CLASSES.collect{|s| s if uri =~ /#{s.downcase}/}.compact
136
- if result.size == 1
137
- klass = result.first
138
- else
139
- klass = OpenTox::Generic.new(uri)[RDF.type]
140
- internal_server_error "Cannot determine class from URI '#{uri} (Candidate classes are #{result.inspect}) or matadata." unless klass
141
- end
142
- # initialize with/without subjectid
143
- subjectid ? eval("#{self}.new(\"#{uri}\", \"#{subjectid}\")") : eval("#{self}.new(\"#{uri}\")")
156
+ {
157
+ :title => RDF::DC.title,
158
+ :dexcription => RDF::DC.description,
159
+ :type => RDF.type
160
+ }.each do |method,predicate|
161
+ send :define_method, method do
162
+ self.[](predicate)
163
+ end
164
+ send :define_method, "#{method}=" do |value|
165
+ self.[]=(predicate,value)
144
166
  end
145
167
  end
146
168
 
@@ -148,7 +170,11 @@ module OpenTox
148
170
  CLASSES.each do |klass|
149
171
  c = Class.new do
150
172
  include OpenTox
151
- extend OpenTox::ClassMethods
173
+
174
+ def self.all service_uri, subjectid=nil
175
+ uris = RestClientWrapper.get(service_uri, {}, :accept => 'text/uri-list').split("\n").compact
176
+ uris.collect{|uri| self.new(uri, subjectid)}
177
+ end
152
178
  end
153
179
  OpenTox.const_set klass,c
154
180
  end
@@ -1,3 +1,21 @@
1
+ class Object
2
+ # An object is blank if it's false, empty, or a whitespace string.
3
+ # For example, "", " ", +nil+, [], and {} are all blank.
4
+ def blank?
5
+ respond_to?(:empty?) ? empty? : !self
6
+ end
7
+
8
+ def numeric?
9
+ true if Float(self) rescue false
10
+ end
11
+ end
12
+
13
+ module Enumerable
14
+ def duplicates
15
+ inject({}) {|h,v| h[v]=h[v].to_i+1; h}.reject{|k,v| v==1}.keys
16
+ end
17
+ end
18
+
1
19
  class String
2
20
  def underscore
3
21
  self.gsub(/::/, '/').
@@ -68,11 +86,10 @@ module Kernel
68
86
  stdout = stdout_stream.read
69
87
  stderr = stderr_stream.read
70
88
  end
71
- internal_server_error "`" + cmd + "` failed.\n" + stdout + stderr if !status.success?
89
+ internal_server_error "`" + cmd + "` failed.\n" + stdout + stderr unless status.success?
72
90
  return stdout
73
91
  rescue
74
- internal_server_error $!.message
92
+ internal_server_error $!.message
75
93
  end
76
94
 
77
95
  end
78
-
@@ -58,7 +58,7 @@ module OpenTox
58
58
  when "guest", "anonymous" then "default_guest_policy"
59
59
  else "default_policy"
60
60
  end
61
- xml = File.read(File.join(File.dirname(__FILE__), "templates/#{template}.xml"))
61
+ xml = get_xml_template(template)
62
62
  self.load_xml(xml)
63
63
  datestring = Time.now.strftime("%Y-%m-%d-%H-%M-%S-x") + rand(1000).to_s
64
64
 
@@ -78,6 +78,10 @@ module OpenTox
78
78
  return true
79
79
  end
80
80
 
81
+ def get_xml_template(template)
82
+ File.read(File.join(File.dirname(__FILE__), "templates/#{template}.xml"))
83
+ end
84
+
81
85
  #loads a xml template
82
86
  def load_xml(xml)
83
87
  rexml = REXML::Document.new(xml)
@@ -247,19 +251,22 @@ module OpenTox
247
251
  end
248
252
 
249
253
  # helper method sets value and type to opentox LDAP Distinguished Name (DN) of a user
254
+ # @param [String]Username set a username into LDAP DN
250
255
  def set_ot_user(username)
251
256
  self.value = "uid=#{username},ou=people,dc=opentox,dc=org"
252
257
  self.type = "LDAPUsers"
253
258
  true
254
259
  end
255
260
 
261
+ # @param [String]Username set a groupname into LDAP DN
256
262
  def set_ot_group(groupname)
257
263
  self.value = "cn=#{groupname},ou=groups,dc=opentox,dc=org"
258
264
  self.type = "LDAPGroups"
259
265
  true
260
266
  end
261
267
 
262
- #rule inside a policy
268
+ # policyrule
269
+ # sets the permission for REST actions (GET, POST, PUT, DELETE) of a specific URI to allow/deny/nil
263
270
  class Rule
264
271
 
265
272
  attr_accessor :name, :uri, :get, :post, :put, :delete, :read, :readwrite
@@ -293,14 +300,18 @@ module OpenTox
293
300
  @put = check_value(value, @put)
294
301
  end
295
302
 
303
+ # read getter method
296
304
  def read
297
305
  return true if @get == "allow" && (@put == "deny" || !@put) && (@post == "deny" || !@post)
298
306
  end
299
307
 
308
+ # readwrite getter method
300
309
  def readwrite
301
310
  return true if @get == "allow" && @put == "allow" && @post == "allow"
302
311
  end
303
312
 
313
+ # Set(true case) or remove read(GET=allow) permissions.
314
+ # @param [Boolean]value (true,false)
304
315
  def read=(value)
305
316
  if value
306
317
  @get = "allow"; @put = nil; @post = nil
@@ -309,6 +320,8 @@ module OpenTox
309
320
  end
310
321
  end
311
322
 
323
+ # Set(true case) or remove readwrite(GET=allow,POST=allow,PUT=allow) permissions.
324
+ # @param [Boolean]value (true,false)
312
325
  def readwrite=(value)
313
326
  if value
314
327
  @get = "allow"; @put = "allow"; @post = "allow"
@@ -324,6 +337,8 @@ module OpenTox
324
337
  end
325
338
  end
326
339
 
340
+ # Subject of a policy
341
+ # name(subjectname), type('LDAPUsers' or 'LDAPGroups'), value(LDAP DN e.G.:'uid=guest,ou=people,dc=opentox,dc=org')
327
342
  class Subject
328
343
 
329
344
  attr_accessor :name, :type, :value