summaryrefslogtreecommitdiff
path: root/lib/opentox.rb
blob: faa7b5851eeeec32cee1b8cbd73873613d63364b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# defaults to stderr, may be changed to file output (e.g in opentox-service)
$logger = OTLogger.new(STDERR) 
$logger.level = Logger::DEBUG

module OpenTox

  attr_accessor :uri, :subjectid, :rdf

  # Ruby interface

  # Create a new OpenTox object (does not load data from service)
  # @param [optional,String] URI
  # @param [optional,String] subjectid
  # @return [OpenTox] OpenTox object
  def initialize uri=nil, subjectid=nil
    @rdf = RDF::Graph.new
    if uri
      @uri = uri.to_s.chomp
    else
      service = self.class.to_s.split('::').last.downcase
      service_uri = eval("$#{service}[:uri]")
      bad_request_error "$#{service}[:uri] variable not set. Please set $#{service}[:uri] or use an explicit uri as first constructor argument " unless service_uri
      @uri = File.join service_uri, SecureRandom.uuid
    end
    append RDF.type, eval("RDF::OT."+self.class.to_s.split('::').last)
    append RDF::DC.date, DateTime.now
    @subjectid = subjectid
  end

  # Object metadata 
  # @return [Hash] Object metadata
  def metadata 
    # return plain strings instead of RDF objects
    @rdf.to_hash[RDF::URI.new(@uri)].inject({}) { |h, (predicate, values)| h[predicate.to_s] = values.collect{|v| v.to_s}; h }
  end

  # Metadata values 
  # @param [String] Predicate URI
  # @return [Array, String] Predicate value(s)
  def [](predicate)
    return nil if metadata[predicate.to_s].nil?
    metadata[predicate.to_s].size == 1 ? metadata[predicate.to_s].first : metadata[predicate.to_s]
  end

  # Set object metadata
  # @param [String] Predicate URI
  # @param [Array, String] Predicate value(s)
  def []=(predicate,values)
    @rdf.delete [RDF::URI.new(@uri.to_s),RDF::URI.new(predicate.to_s),nil] 
    append predicate.to_s, values
  end

  def parameters
    params = {}
    query = RDF::Query.new({
      :parameter => {
        RDF.type  => RDF::OT.Parameter,
        :property => :value,
      }
    })
    query.execute(@rdf).each do |solution|
      params[solution.parameter] = {} unless params[solution.parameter] 
      params[solution.parameter][solution.property.to_s] = solution.value.to_s
    end
    params.values
  end

  def parameters=(parameters)
    parameters.each do |param|
      p_node = RDF::Node.new
      @rdf << [RDF::URI.new(@uri), RDF::OT.parameters, p_node]
      @rdf << [p_node, RDF.type, RDF::OT.Parameter]
      param.each{ |p,o| @rdf << [p_node, p, o] }
    end
  end

  # Append object metadata
  # @param [String] Predicate URI
  # @param [Array, String] Predicate value(s)
  def append(predicate,values)
    uri = RDF::URI.new @uri
    predicate = RDF::URI.new predicate
    [values].flatten.each { |value| @rdf << [uri, predicate, value] }
  end

  # Get object from webservice
  def get mime_type="text/plain"
    response = RestClientWrapper.get(@uri,{},{:accept => mime_type, :subjectid => @subjectid})
    if URI.task?(response)
      wait_for_task response
      response = RestClientWrapper.get(t.resultURI,{},{:accept => mime_type, :subjectid => @subjectid})
    end
    parse_ntriples response if mime_type == "text/plain"
    parse_rdfxml response if mime_type == "application/rdf+xml"
  end

  # Post object to webservice
  def post params=nil, wait=true
    # TODO: RDFXML
    uri = RestClientWrapper.post @uri.to_s, params, { :content_type => "text/plain", :subjectid => @subjectid}
    wait_for_task uri if wait
  end

  # Save object at webservice
  def put wait=true
    # TODO: RDFXML
    append RDF::DC.modified, DateTime.now
    uri = RestClientWrapper.put @uri.to_s, self.to_ntriples, { :content_type => "text/plain", :subjectid => @subjectid}
    wait_for_task uri if wait
  end

  # Delete object at webservice
  def delete 
    RestClientWrapper.delete(@uri.to_s,nil,{:subjectid => @subjectid})
  end

  def wait_for_task uri
    if URI.task?(uri) 
      t = OpenTox::Task.new uri
      t.wait
      unless t.completed?
        #TODO raise correct error
        #internal_server_error "Task #{uri} failed with #{$!.inspect}"
      end
      uri = t.resultURI
    end
    uri
  end

  RDF_FORMATS.each do |format|

    # rdf parse methods for all formats e.g. parse_rdfxml
    send :define_method, "parse_#{format}".to_sym do |rdf|
      @rdf = RDF::Graph.new
      RDF::Reader.for(format).new(rdf) do |reader|
        reader.each_statement{ |statement| @rdf << statement }
      end
    end

    # rdf serialization methods for all formats e.g. to_rdfxml
    send :define_method, "to_#{format}".to_sym do
      RDF::Writer.for(format).buffer do |writer|
        @rdf.each{|statement| writer << statement}
      end
    end
  end

  def to_turtle # redefine to use prefixes (not supported by RDF::Writer)
    prefixes = {:rdf => "http://www.w3.org/1999/02/22-rdf-syntax-ns#"}
    ['OT', 'DC', 'XSD', 'OLO'].each{|p| prefixes[p.downcase.to_sym] = eval("RDF::#{p}.to_s") }
    RDF::N3::Writer.for(:turtle).buffer(:prefixes => prefixes)  do |writer|
      @rdf.each{|statement| writer << statement}
    end
  end

  {
    :title => RDF::DC.title,
    :dexcription => RDF::DC.description,
    :type => RDF.type
  }.each do |method,predicate|
    send :define_method, method do 
      self.[](predicate) 
    end
    send :define_method, "#{method}=" do |value|
      self.[]=(predicate,value) 
    end
  end

  # create default OpenTox classes
  CLASSES.each do |klass|
    c = Class.new do
      include OpenTox

      def self.all service_uri, subjectid=nil
        uris = RestClientWrapper.get(service_uri, {}, :accept => 'text/uri-list').split("\n").compact
        uris.collect{|uri| self.new(uri, subjectid)}
      end
    end
    OpenTox.const_set klass,c
  end

end