summaryrefslogtreecommitdiff
path: root/lib/rest-client-wrapper.rb
blob: 1e871b0230a5c0a4e8832a8f2cddfc2a92978d72 (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
module OpenTox
  
  class RestClientWrapper
    
    attr_accessor :request, :response

    # REST methods 
    # Raises OpenTox::Error if call fails (rescued in overwrite.rb -> halt 502)
    # Waits for Task to finish and returns result URI of Task per default
    # @param [String] destination URI
    # @param [optional,Hash|String] Payload data posted to the service
    # @param [optional,Hash] Headers with params like :accept, :content_type, :subjectid
    # @param [optional,OpenTox::Task] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
    # @param [wait,Boolean] Set to false to NOT wait for task if result is a task
    # @return [RestClient::Response] REST call response 
    [:head,:get,:post,:put,:dealete].each do |method|

      define_singleton_method method do |uri,payload={},headers={},waiting_task=nil, wait=true|
      
        # create request
        args={}
        args[:method] = method
        args[:url] = uri
        args[:timeout] = 600
        args[:payload] = payload
        headers.each{ |k,v| headers.delete(k) if v==nil } if headers #remove keys with empty values, as this can cause problems
        args[:headers] = headers 
        @request = RestClient::Request.new(args)

        # catch input errors
        rest_error "Invalid URI: '#{uri}'" unless URI.valid? uri
        rest_error "Unreachable URI: '#{uri}'" unless URI.accessible? uri
        rest_error "Headers are not a hash: #{headers.inspect}" unless headers==nil or headers.is_a?(Hash)
        # make sure that no header parameters are set in payload
        [:accept,:content_type,:subjectid].each do |header|
          rest_error "#{header} should be submitted in the headers" if payload and payload.is_a?(Hash) and payload[header] 
        end
        rest_error "waiting_task is not 'nil', OpenTox::SubTask or OpenTox::Task: #{waiting_task.class}" unless waiting_task.nil? or waiting_task.is_a?(OpenTox::Task) or waiting_task.is_a?(OpenTox::SubTask)

        
        begin
          @response = @request.execute do |response, request, result|
            # ignore error codes from Task services (may contain eg 500 which causes exceptions in RestClient and RDF::Reader
            rest_error unless response.code < 400 or URI.task? uri
            return response
          end

          # TODO: tests for workarounds
          # PENDING NTUA does return errors with 200
          #raise RestClient::ExceptionWithResponse.new(@response) if uri=~/ntua/ and @response.body =~ /about.*http:\/\/anonymous.org\/error/
          
          return @response if @response.code==200 or wait.false?

          # wait for task
          while @response.code==201 or @response.code==202
            @response = wait_for_task(@response, uri, waiting_task)
          end
          return @response
          
        rescue
          rest_error $!.message
        end
=begin
        rescue RestClient::RequestTimeout 
          raise OpenTox::Error @request, @response, $!.message
          #received_error ex.message, 408, nil, {:rest_uri => uri, :headers => headers, :payload => payload}
        rescue Errno::ETIMEDOUT 
          raise OpenTox::Error @request, @response, $!.message
          #received_error ex.message, 408, nil, {:rest_uri => uri, :headers => headers, :payload => payload}
        rescue Errno::ECONNREFUSED
          raise OpenTox::Error $!.message
          #received_error ex.message, 500, nil, {:rest_uri => uri, :headers => headers, :payload => payload}
        rescue RestClient::ExceptionWithResponse
          # error comming from a different webservice, 
          received_error ex.http_body, ex.http_code, ex.response.net_http_res.content_type, {:rest_uri => uri, :headers => headers, :payload => payload}
        #rescue OpenTox::RestCallError => ex
          # already a rest-error, probably comes from wait_for_task, just pass through
          #raise ex       
        #rescue => ex
          # some internal error occuring in rest-client-wrapper, just pass through
          #raise ex
        end
=end
      end
    end
    
    def wait_for_task( response, base_uri, waiting_task=nil )
      #TODO remove TUM hack
      # @response.headers[:content_type] = "text/uri-list" if base_uri =~/tu-muenchen/ and @response.headers[:content_type] == "application/x-www-form-urlencoded;charset=UTF-8"

      task = nil
      case @response.headers[:content_type]
      when /application\/rdf\+xml/
        # TODO: task uri from rdf
        #task = OpenTox::Task.from_rdfxml(@response)
        #task = OpenTox::Task.from_rdfxml(@response)
      when /text\/uri-list/
        rest_error "Uri list has more than one entry, should be a single task" if @response.split("\n").size > 1 #if uri list contains more then one uri, its not a task
        task = OpenTox::Task.new(@response.to_s.chomp) if URI.available? @response.to_s
      else
        rest_error @response, "Unknown content-type for task : '"+@response.headers[:content_type].to_s+"'"+" base-uri: "+base_uri.to_s+" content: "+@response[0..200].to_s
      end
      
      #LOGGER.debug "result is a task '"+task.uri.to_s+"', wait for completion"
      task.wait waiting_task
      unless task.completed? # maybe task was cancelled / error
        if task.errorReport
          received_error task.errorReport, task.http_code, nil, {:rest_uri => task.uri, :rest_code => task.http_code}
        else
          rest_call_error "Status of task '"+task.uri.to_s+"' is no longer running (hasStatus is '"+task.status+
            "'), but it is neither completed nor has an errorReport"
        end 
      end
      @response
    end

    def self.rest_error message
      raise OpenTox::RestError.new :request => @request, :response => @response, :cause => message
    end

=begin
    def self.bad_request_error message
      raise OpenTox::Error.new message
    end

    def self.not_found_error message
      raise OpenTox::NotFoundError.new message
    end
    
    def self.received_error( body, code, content_type=nil, params=nil )

      # try to parse body TODO
      body.is_a?(OpenTox::ErrorReport) ? report = body : report = OpenTox::ErrorReport.from_rdf(body)
      rest_call_error "REST call returned error: '"+body.to_s+"'" unless report
      # parsing sucessfull
      # raise RestCallError with parsed report as error cause
      err = OpenTox::RestCallError.new(@request, @response, "REST call subsequent error")
      err.errorCause = report
      raise err
    end
=end
=begin
    def self.received_error( body, code, content_type=nil, params=nil )

      # try to parse body
      report = nil
      #report = OpenTox::ErrorReport.from_rdf(body)
      if body.is_a?(OpenTox::ErrorReport)
        report = body
      else
        case content_type
        when /yaml/
           report = YAML.load(body)
        when /rdf/
           report = OpenTox::ErrorReport.from_rdf(body)
        end
      end

      unless report
		    # parsing was not successfull
        # raise 'plain' RestCallError
        err = OpenTox::RestCallError.new("REST call returned error: '"+body.to_s+"'")
        err.rest_params = params
        raise err
      else
        # parsing sucessfull
        # raise RestCallError with parsed report as error cause
        err = OpenTox::RestCallError.new("REST call subsequent error")
        err.errorCause = report
        err.rest_params = params
        raise err
      end
    end
=end
  end
end