summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormguetlein <martin.guetlein@gmail.com>2011-01-20 11:29:53 +0100
committermguetlein <martin.guetlein@gmail.com>2011-01-20 11:29:53 +0100
commit9d06bd3024139f2bfee4722c7536ee4ffa99fe32 (patch)
tree727956c9d110bfc9774268cd7125b6e19d7175a1
parent23d96df630689d122c023d76ec1d40d7688d2c96 (diff)
implemented new error handling, still TODO rdf-support, replace halts
-rw-r--r--lib/error.rb60
-rw-r--r--lib/opentox-ruby.rb4
-rw-r--r--lib/overwrite.rb44
-rw-r--r--lib/rest_client_wrapper.rb91
4 files changed, 99 insertions, 100 deletions
diff --git a/lib/error.rb b/lib/error.rb
index 87e1a5d..b72ce7e 100644
--- a/lib/error.rb
+++ b/lib/error.rb
@@ -1,11 +1,61 @@
-module OpenTox
- class NotFoundError < RuntimeError
-
+# adding additional fields to Exception class to format errors according to OT-API
+class Exception
+ attr_accessor :creator, :errorCause, :id
+end
+
+module OpenTox
+
+ class NotAuthorizedError < Exception
end
- class BadRequestError < RuntimeError
-
+ class NotFoundError < Exception
end
+ class BadRequestError < Exception
+ end
+
+ class RestCallError < Exception
+ attr_accessor :code, :body, :uri, :payload, :headers
+ end
+
+ class ErrorReport
+
+ # formats error according to accept-header, yaml is default
+ # ( sets content-type in response accordingly )
+ # @param [Exception] error
+ # @param |Sinatra::Request, optional] request
+ # @param [Sinatra::Response, optiona,] response, optional to set content-type
+ # @return [String] formated error
+ def self.format(error, request=nil, response=nil)
+ # sets current uri
+ error.creator = "#{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}#{request.env['REQUEST_URI']}" if request
+ accept = request.env['HTTP_ACCEPT'].to_s if request
+ case accept
+ # when /rdf/
+ # TODO add error to rdf
+ when /html/
+ response['Content-Type'] = 'text/html' if response
+ OpenTox.text_to_html error.to_yaml
+ else
+ response['Content-Type'] = 'application/x-yaml' if response
+ error.to_yaml
+ end
+ end
+
+ # trys to parse error from text
+ # @return [Exception] Exception if parsing sucessfull, nil otherwise
+ def self.parse( body )
+ begin
+ err = YAML.load(body)
+ if err and err.is_a?(Exception)
+ return err
+ else
+ return nil
+ end
+ rescue
+ return nil
+ end
+ end
+ end
end \ No newline at end of file
diff --git a/lib/opentox-ruby.rb b/lib/opentox-ruby.rb
index fc1732d..735b845 100644
--- a/lib/opentox-ruby.rb
+++ b/lib/opentox-ruby.rb
@@ -1,4 +1,4 @@
-['rubygems', 'sinatra', 'sinatra/url_for', 'rest_client', 'yaml', 'cgi', 'spork', 'overwrite', 'environment'].each do |lib|
+['rubygems', 'sinatra', 'sinatra/url_for', 'rest_client', 'yaml', 'cgi', 'spork', 'error', 'overwrite', 'environment'].each do |lib|
require lib
end
@@ -9,6 +9,6 @@ rescue LoadError
end
['opentox', 'compound','dataset', 'parser','serializer', 'algorithm','model','task','validation','feature',
- 'rest_client_wrapper', 'authorization', 'policy', 'helper', 'to-html', 'error' ].each do |lib|
+ 'rest_client_wrapper', 'authorization', 'policy', 'helper', 'to-html' ].each do |lib|
require lib
end
diff --git a/lib/overwrite.rb b/lib/overwrite.rb
index 720ed77..2f9fabd 100644
--- a/lib/overwrite.rb
+++ b/lib/overwrite.rb
@@ -10,30 +10,30 @@ before {
request.env['HTTP_ACCEPT'] += ";text/html" if request.env["HTTP_USER_AGENT"]=~/MSIE/
}
-# handle errors manually
-# this is to return 502, when an error occurs during a rest-call (see rest_client_wrapper.rb)
-set :raise_errors, Proc.new { false }
-set :show_exceptions, false
-error do
- # try if the error is an OpenTox::Error
- if OpenTox::Error.parse(request.env['sinatra.error'].to_s)
- # if true, this error comes from rest_client_wrapper, halt with 502
- # (502 is defined in OT API as Error coming from other service)
- halt 502,request.env['sinatra.error']
+# Error handling
+# Errors are logged as error and formated according to acccept-header
+# Non OpenTox::Errors (defined in error.rb) are handled as internal error (500), stacktrace is logged
+# IMPT: set sinatra settings :show_exceptions + :raise_errors to false in config.ru, otherwise Rack::Showexceptions takes over
+error Exception do
+ error = request.env['sinatra.error']
+ # log error to logfile
+ LOGGER.error error.class.to_s+": "+error.message
+ case error.class
+ when OpenTox::BadRequestError
+ code = 400
+ when OpenTox::NotAuthorizedError
+ code = 401
+ when OpenTox::NotFoundError
+ code = 404
+ when OpenTox::RestCallError
+ code = 502
else
- # else, raise exception, this will return 500 = internal error
- raise request.env['sinatra.error']
- end
-end
-
-class Sinatra::Base
- # overwriting halt to log halts (!= 202)
- def halt(*response)
- LOGGER.error "halt "+response.first.to_s+" "+(response.size>1 ? response[1].to_s : "") if response and response.first and response.first >= 300
- # orig sinatra code:
- response = response.first if response.length == 1
- throw :halt, response
+ # (unwanted RuntimeExceptions as well as sth. like 'raise "invalid state"' is handled here)
+ code = 500
+ # log backtrace for debugging
+ LOGGER.error error.backtrace.join("\n")
end
+ halt code,OpenTox::ErrorReport.format(error,request,response)
end
class String
diff --git a/lib/rest_client_wrapper.rb b/lib/rest_client_wrapper.rb
index 920a828..5bc8072 100644
--- a/lib/rest_client_wrapper.rb
+++ b/lib/rest_client_wrapper.rb
@@ -1,32 +1,4 @@
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
@@ -85,16 +57,16 @@ module OpenTox
# @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 )
+ raise_ot_error( nil, error_msg, nil, 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
+ raise OpenTox::BadRequestError.new "uri is null" unless uri
+ raise OpenTox::BadRequestError.new "not a uri: "+uri.to_s unless uri.to_s.uri?
+ raise OpenTox::BadRequestError.new "headers are no hash: "+headers.inspect unless headers==nil or headers.is_a?(Hash)
+ raise OpenTox::BadRequestError.new "nil headers for post not allowed, use {}" 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
@@ -124,18 +96,11 @@ module OpenTox
return res
rescue RestClient::RequestTimeout => ex
- raise_ot_error 408,ex.message,uri,headers,payload
+ raise_ot_error 408,ex.message,nil,ex.uri,headers,payload
+ rescue RestClient::ExceptionWithResponse => ex
+ raise_ot_error ex.http_code,ex.message,ex.http_body,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
+ raise_ot_error 500,ex.message,nil,uri,headers,payload
end
end
@@ -164,35 +129,19 @@ module OpenTox
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)]
+ def self.raise_ot_error( code, message, body, uri, headers, payload=nil )
+ error = OpenTox::RestCallError.new("REST call returned error: '"+message.to_s+"'")
+ error.code = code
+ error.uri = uri
+ error.headers = headers
+ error.payload = payload
+ parsed = OpenTox::ErrorReport.parse(body) if body
+ if parsed
+ error.errorCause = parsed
else
- error = [Error.new(code, body, uri, payload, headers)]
+ error.body = body
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
+ raise error
end
end
end