module OpenTox #PENDING: implement ot error api, move to own file class Error attr_accessor :code, :body, :uri, :payload, :headers def initialize(code, body, uri, payload, headers) self.code = code self.body = body.to_s[0..1000] self.uri = uri self.payload = payload self.headers = headers end def self.parse(error_array_string) begin err = YAML.load(error_array_string) if err and err.is_a?(Array) and err.size>0 and err[0].is_a?(Error) return err else return nil end rescue return nil end end end class WrapperResult < String attr_accessor :content_type, :code end class RestClientWrapper # performs a GET REST call # raises OpenTox::Error if call fails (rescued in overwrite.rb -> halt 502) # per default: waits for Task to finish and returns result URI of Task # @param [String] uri destination URI # @param [optional,Hash] headers contains params like accept-header # @param [optional,OpenTox::Task] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly # @param [wait,Boolean] wait set to false to NOT wait for task if result is task # @return [OpenTox::WrapperResult] a String containing the result-body of the REST call def self.get(uri, headers=nil, waiting_task=nil, wait=true ) execute( "get", uri, headers, nil, waiting_task, wait) end # performs a POST REST call # raises OpenTox::Error if call fails (rescued in overwrite.rb -> halt 502) # per default: waits for Task to finish and returns result URI of Task # @param [String] uri destination URI # @param [optional,Hash] headers contains params like accept-header # @param [optional,String] payload data posted to the service # @param [optional,OpenTox::Task] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly # @param [wait,Boolean] wait set to false to NOT wait for task if result is task # @return [OpenTox::WrapperResult] a String containing the result-body of the REST call def self.post(uri, headers, payload=nil, waiting_task=nil, wait=true ) execute( "post", uri, headers, payload, waiting_task, wait ) end # performs a PUT REST call # raises OpenTox::Error if call fails (rescued in overwrite.rb -> halt 502) # @param [String] uri destination URI # @param [optional,Hash] headers contains params like accept-header # @param [optional,String] payload data put to the service # @return [OpenTox::WrapperResult] a String containing the result-body of the REST call def self.put(uri, headers, payload=nil ) execute( "put", uri, headers, payload ) end # performs a DELETE REST call # raises OpenTox::Error if call fails (rescued in overwrite.rb -> halt 502) # @param [String] uri destination URI # @param [optional,Hash] headers contains params like accept-header # @return [OpenTox::WrapperResult] a String containing the result-body of the REST call def self.delete(uri, headers=nil ) execute( "delete", uri, headers, nil) end # raises an Error message (rescued in overwrite.rb -> halt 502) # usage: if the return value of a call is invalid # @param [String] error_msg the error message # @param [String] uri destination URI that is responsible for the error # @param [optional,Hash] headers sent to the URI # @param [optional,String] payload data sent to the URI def self.raise_uri_error(error_msg, uri, headers=nil, payload=nil) raise_ot_error( "-", error_msg, uri, headers, payload ) end private def self.execute( rest_call, uri, headers, payload=nil, waiting_task=nil, wait=true ) raise_ot_error 400,"uri is null",uri,headers,payload unless uri raise_ot_error 400,"not a uri",uri,headers,payload unless uri.to_s.uri? raise_ot_error 400,"headers are no hash",uri,headers,payload unless headers==nil or headers.is_a?(Hash) raise_ot_error 400,"nil headers for post not allowed, use {}",uri,headers,payload if rest_call=="post" and headers==nil headers.each{ |k,v| headers.delete(k) if v==nil } if headers #remove keys with empty values, as this can cause problems begin #LOGGER.debug "RestCall: "+rest_call.to_s+" "+uri.to_s+" "+headers.inspect resource = RestClient::Resource.new(uri,{:timeout => 60}) if payload result = resource.send(rest_call, payload, headers) elsif headers result = resource.send(rest_call, headers) else result = resource.send(rest_call) end # result is a string, with the additional fields content_type and code res = WrapperResult.new(result.body) res.content_type = result.headers[:content_type] raise "content-type not set" unless res.content_type res.code = result.code # TODO: Ambit returns task representation with 200 instead of result URI return res if res.code==200 || !wait while (res.code==201 || res.code==202) res = wait_for_task(res, uri, waiting_task) end raise "illegal status code: '"+res.code.to_s+"'" unless res.code==200 return res rescue RestClient::RequestTimeout => ex raise_ot_error 408,ex.message,uri,headers,payload rescue => ex #raise ex #raise "'"+ex.message+"' uri: "+uri.to_s begin code = ex.http_code msg = ex.http_body rescue code = 500 msg = ex.to_s end raise_ot_error code,msg,uri,headers,payload end end def self.wait_for_task( res, base_uri, waiting_task=nil ) task = nil case res.content_type when /application\/rdf\+xml/ task = OpenTox::Task.from_rdfxml(res) when /yaml/ task = OpenTox::Task.from_yaml(res) when /text\// raise "uri list has more than one entry, should be a task" if res.content_type=~/text\/uri-list/ and res.split("\n").size > 1 #if uri list contains more then one uri, its not a task task = OpenTox::Task.find(res.to_s.chomp) if res.to_s.uri? else raise "unknown content-type for task: '"+res.content_type.to_s+"'" #+"' content: "+res[0..200].to_s end LOGGER.debug "result is a task '"+task.uri.to_s+"', wait for completion" task.wait_for_completion waiting_task raise task.description unless task.completed? # maybe task was cancelled / error res = WrapperResult.new task.result_uri res.code = task.http_code res.content_type = "text/uri-list" return res end def self.raise_ot_error( code, body, uri, headers, payload=nil ) #build error causing_errors = Error.parse(body) if causing_errors error = causing_errors + [Error.new(code, "subsequent error", uri, payload, headers)] else error = [Error.new(code, body, uri, payload, headers)] end #debug utility: write error to file error_dir = "/tmp/ot_errors" FileUtils.mkdir(error_dir) unless File.exist?(error_dir) raise "could not create error dir" unless File.exist?(error_dir) and File.directory?(error_dir) file_name = "error" time=Time.now.strftime("%m.%d.%Y-%H:%M:%S") count = 1 count+=1 while File.exist?(File.join(error_dir,file_name+"_"+time+"_"+count.to_s)) File.new(File.join(error_dir,file_name+"_"+time+"_"+count.to_s),"w").puts(body) # handle error # PENDING: always return yaml for now # raising OpenTox::Error # to handle the error yourself, put rest-call in begin, rescue block # if the error is not caught: # if we are in a task, the error is caught, logged, and task state is set to error in Task.as_task # if we are in a default call, the error is handled in overwrite.rb to return 502 (according to OT API) raise error.to_yaml end end end