summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristoph Helma <helma@in-silico.ch>2012-03-02 09:33:44 +0000
committerChristoph Helma <helma@in-silico.ch>2012-03-02 09:33:44 +0000
commitcbc5f08e92c92601009f0c11c8ec67ede2894858 (patch)
tree72fba983048ce7cbc3923190e8527906478843d3
parentdd39ae3a5479eed32d57d1d3934d907a82048486 (diff)
error report fixed for old task services
-rw-r--r--lib/error.rb160
-rw-r--r--lib/opentox.rb8
-rw-r--r--lib/rest-client-wrapper.rb28
-rw-r--r--lib/task.rb25
-rw-r--r--test/task.rb25
5 files changed, 137 insertions, 109 deletions
diff --git a/lib/error.rb b/lib/error.rb
index 88c8be8..8368404 100644
--- a/lib/error.rb
+++ b/lib/error.rb
@@ -1,101 +1,107 @@
# adding additional fields to Exception class to format errors according to OT-API
class RuntimeError
- attr_accessor :http_code
- @http_code = 500
+ attr_accessor :report, :http_code
+ def initialize message
+ super message
+ @http_code ||= 500
+ @report = OpenTox::ErrorReport.create self
+ $logger.error "\n"+@report.to_ntriples
+ end
end
module OpenTox
- # Errors received from RestClientWrapper calls
- class RestError < RuntimeError
- attr_accessor :request, :response, :cause
- def initialize args
- @request = args[:request]
- @response = args[:response]
- args[:http_code] ? @http_code = args[:http_code] : @http_code = @response.code if @response
- @cause = args[:cause]
- msg = args.to_yaml
- $logger.error msg
- super msg
+ class Error < RuntimeError
+ def initialize code, message
+ @http_code = code
+ super message
end
end
- # Errors rescued from task blocks
- class TaskError < RuntimeError
- attr_reader :error, :actor, :report
- def initialize error, actor=nil
- @error = error
- @actor = actor
- @report = ErrorReport.create error, actor
- # TODO avoid error log duplication, improve output
- msg = "\nActor: \"#{actor}\"\n"
- msg += "\nCode: #{@report.http_code}"
- msg += "\nerrorCause: #{@report.errorCause}\n"
- msg += @report.message
- $logger.error msg
- super msg
+ # create error classes dynamically
+ {
+ "BadRequestError" => 400,
+ "NotAuthorizedError" => 401,
+ "NotFoundError" => 404,
+ "ServiceUnavailableError" => 503,
+ "TimeOutError" => 504,
+ }.each do |klass,code|
+ c = Class.new Error do
+ define_method :initialize do |message|
+ super code, message
+ end
+ end
+ OpenTox.const_set klass,c
+ end
+
+ # Errors received from RestClientWrapper calls
+ class RestCallError < Error
+ attr_accessor :request, :response
+ def initialize request, response, message
+ @request = request
+ @response = response
+ super 502, message
end
end
class ErrorReport
- # TODO replace params with URIs (errorCause -> OT.errorCause)
- attr_reader :message, :actor, :errorCause, :http_code, :errorDetails, :errorType
+ attr_accessor :rdf # RDF Graph
+ attr_accessor :http_code # TODO: remove when task service is fixed
- private
- def initialize( http_code, erroType, message, actor, errorCause, rest_params=nil, backtrace=nil )
- @http_code = http_code
- @errorType = erroType
- @message = message
- @actor = actor
- @errorCause = errorCause
- @rest_params = rest_params
- @backtrace = backtrace
+ def initialize
+ @rdf = RDF::Graph.new
end
-
- public
+
# creates a error report object, from an ruby-exception object
# @param [Exception] error
- # @param [String] actor, URI of the call that cause the error
- def self.create( error, actor )
- rest_params = error.request if error.respond_to? :request
- backtrace = error.backtrace.short_backtrace if error.respond_to? :backtrace and error.backtrace #if CONFIG[:backtrace]
- error.respond_to?(:http_code) ? http_code = error.http_code : http_code = 500
- error.respond_to?(:cause) ? cause = error.cause : cause = 'Unknown'
- ErrorReport.new( http_code, error.class.to_s, error.message, actor, cause, rest_params, backtrace )
- end
-
- def self.from_rdf(rdf)
- metadata = OpenTox::Parser::Owl.from_rdf( rdf, OT.ErrorReport ).metadata
- ErrorReport.new(metadata[OT.statusCode], metadata[OT.errorCode], metadata[OT.message], metadata[OT.actor], metadata[OT.errorCause])
- end
-
- # overwrite sorting to make easier readable
- def to_yaml_properties
- p = super
- p = ( p - ["@backtrace"]) + ["@backtrace"] if @backtrace
- p = ( p - ["@errorCause"]) + ["@errorCause"] if @errorCause
- p
- end
-
- def rdf_content()
- c = {
- RDF.type => [OT.ErrorReport],
- OT.statusCode => @http_code,
- OT.message => @message,
- OT.actor => @actor,
- OT.errorCode => @errorType,
- }
- c[OT.errorCause] = @errorCause.rdf_content if @errorCause
- c
+ def self.create error
+ report = ErrorReport.new
+ subject = RDF::Node.new
+ report.rdf << [subject, RDF.type, RDF::OT.ErrorReport]
+ message = error.message
+ errorDetails = ""
+ if error.respond_to? :request
+ report.rdf << [subject, RDF::OT.actor, error.request.url ]
+ errorDetails += "REST paramenters:\n#{error.request.args.inspect}"
+ end
+ error.respond_to?(:http_code) ? statusCode = error.http_code : statusCode = 500
+ if error.respond_to? :response
+ statusCode = error.response.code
+ message = error.body
+ end
+ statusCode = error.http_code if error.respond_to? :http_code
+ report.rdf << [subject, RDF::OT.statusCode, statusCode ]
+ report.rdf << [subject, RDF::OT.errorCode, error.class.to_s ]
+ # TODO: remove kludge for old task services
+ report.http_code = statusCode
+ report.rdf << [subject, RDF::OT.message , message ]
+
+ errorDetails += "\nBacktrace:\n" + error.backtrace.short_backtrace if error.respond_to?(:backtrace) and error.backtrace
+ report.rdf << [subject, RDF::OT.errorDetails, errorDetails ]
+ # TODO Error cause
+ #report.rdf << [subject, OT.errorCause, error.report] if error.respond_to?(:report) and !error.report.empty?
+ report
end
- # TODO: use rdf.rb
- def to_rdfxml
- s = Serializer::Owl.new
- s.add_resource(CONFIG[:services]["opentox-task"]+"/tmpId/ErrorReport/tmpId", OT.errorReport, rdf_content)
- s.to_rdfxml
+ # define to_ and self.from_ methods for various rdf formats
+ [:rdfxml,:ntriples].each do |format|
+
+ define_singleton_method ("from_#{format}").to_sym do |rdf|
+ report = ErrorReport.new
+ RDF::Reader.for(format).new(rdf) do |reader|
+ reader.each_statement{ |statement| report.rdf << statement }
+ end
+ report
+ end
+
+ send :define_method, ("to_#{format}").to_sym do
+ rdfxml = RDF::Writer.for(format).buffer do |writer|
+ @rdf.each{|statement| writer << statement}
+ end
+ rdfxml
+ end
end
end
diff --git a/lib/opentox.rb b/lib/opentox.rb
index 4c2a668..10c7895 100644
--- a/lib/opentox.rb
+++ b/lib/opentox.rb
@@ -24,7 +24,7 @@ module OpenTox
if reload or @metadata.empty?
@metadata = {}
kind_of?(OpenTox::Dataset) ? uri = File.join(@uri,"metadata") : uri = @uri
- RDF::Reader.for(:rdfxml).new( RestClientWrapper.get(@uri) ) do |reader|
+ RDF::Reader.for(:rdfxml).new( RestClientWrapper.get(uri) ) do |reader|
reader.each_statement do |statement|
@metadata[statement.predicate] = statement.object if statement.subject == @uri
end
@@ -34,10 +34,14 @@ module OpenTox
end
def save
+ post self.to_rdfxml, { :content_type => 'application/rdf+xml'}
+ end
+
+ def to_rdfxml
rdf = RDF::Writer.for(:rdfxml).buffer do |writer|
@metadata.each { |p,o| writer << RDF::Statement.new(RDF::URI.new(@uri), p, o) }
end
- post rdf, { :content_type => 'application/rdf+xml'}
+ rdf
end
# REST API
diff --git a/lib/rest-client-wrapper.rb b/lib/rest-client-wrapper.rb
index 1e871b0..0780dd5 100644
--- a/lib/rest-client-wrapper.rb
+++ b/lib/rest-client-wrapper.rb
@@ -27,29 +27,25 @@ module OpenTox
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
+ # check input
+ raise OpenTox::Error.new 400, "Invalid URI: '#{uri}'" unless URI.valid? uri
+ raise OpenTox::Error.new 400, "Unreachable URI: '#{uri}'" unless URI.accessible? uri
+ raise OpenTox::Error.new 400, "Headers are not a hash: #{headers.inspect}" unless headers==nil or headers.is_a?(Hash)
+ # make sure that no header parameters are set in the 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]
+ raise OpenTox::Error.new 400, "#{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)
+ raise OpenTox::Error.new 400, "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
+ rest_error "Response code is #{response.code}" 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?
+ return @response if @response.code==200 or !wait
# wait for task
while @response.code==201 or @response.code==202
@@ -98,7 +94,7 @@ module OpenTox
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
+ rest_error "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"
@@ -107,7 +103,7 @@ module OpenTox
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+
+ rest_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
@@ -115,7 +111,7 @@ module OpenTox
end
def self.rest_error message
- raise OpenTox::RestError.new :request => @request, :response => @response, :cause => message
+ raise OpenTox::RestCallError.new @request, @response, message
end
=begin
diff --git a/lib/task.rb b/lib/task.rb
index d3b6312..f75f87d 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -17,7 +17,7 @@ module OpenTox
if URI.accessible?(result_uri)
task.completed result_uri
else
- raise "\"#{result_uri}\" is not a valid result URI"
+ raise NotFoundError.new "\"#{result_uri}\" is not a valid result URI"
#task.error OpenTox::RestError.new :http_code => 404, :cause => "#{result_uri} is not a valid URI", :actor => params[:creator]
end
rescue
@@ -53,7 +53,7 @@ module OpenTox
end
def creator
- metadata[RDF::DC.creator]
+ metadata[RDF::DC.creator]
end
def cancel
@@ -63,13 +63,16 @@ module OpenTox
def completed(uri)
#error OpenTox::RestError.new :http_code => 404, :cause => "\"#{uri}\" does not exist.", :actor => creator unless URI.accessible? uri
- raise "Result URI \"#{uri}\" does not exist." unless URI.accessible? uri
+ raise NotFoundError.new "Result URI \"#{uri}\" does not exist." unless URI.accessible? uri
RestClientWrapper.put(File.join(@uri,'Completed'),{:resultURI => uri})
end
def error error
- error = OpenTox::TaskError.new error, creator
- RestClientWrapper.put(File.join(@uri,'Error'),{:errorReport => error.report})
+ # TODO: switch task service to rdf
+ #RestClientWrapper.put(File.join(@uri,'Error'),{:errorReport => error.report.to_rdfxml})
+ # create report for non-runtime errors
+ error.respond_to?(:reporti) ? report = error.report : report = OpenTox::ErrorReport.create(error)
+ RestClientWrapper.put(File.join(@uri,'Error'),{:errorReport => report.to_yaml})
kill
raise error
end
@@ -80,7 +83,7 @@ module OpenTox
due_to_time = Time.new + DEFAULT_TASK_MAX_DURATION
while running?
sleep dur
- raise "max wait time exceeded ("+DEFAULT_TASK_MAX_DURATION.to_s+"sec), task: '"+@uri.to_s+"'" if (Time.new > due_to_time)
+ raise TimeOutError.new "max wait time exceeded ("+DEFAULT_TASK_MAX_DURATION.to_s+"sec), task: '"+@uri.to_s+"'" if (Time.new > due_to_time)
end
end
@@ -100,7 +103,8 @@ module OpenTox
end
def error?
- RestClientWrapper.head(@uri).code == 500
+ code = RestClientWrapper.head(@uri).code
+ code >= 400 and code != 503
end
def method_missing(method,*args)
@@ -114,14 +118,15 @@ module OpenTox
response = metadata[RDF::OT[method]].to_s
response = metadata[RDF::OT1[method]].to_s #if response.empty? # API 1.1 compatibility
if response.empty?
- $logger.error "No #{method} metadata for #{@uri} "
- raise "No #{method} metadata for #{@uri} "
+ raise NotFoundError.new "No #{method} metadata for #{@uri} "
end
return response
end
+ rescue OpenTox::Error
+ raise $!
rescue
$logger.error "Unknown #{self.class} method #{method}"
- #super
+ super
end
end
diff --git a/test/task.rb b/test/task.rb
index 7ea30b9..d49871f 100644
--- a/test/task.rb
+++ b/test/task.rb
@@ -10,6 +10,8 @@ TASK_SERVICE_URI = "http://ot-dev.in-silico.ch/task"
class TaskTest < Test::Unit::TestCase
+=begin
+=end
def test_all
all = OpenTox::Task.all(TASK_SERVICE_URI)
assert_equal Array, all.class
@@ -44,8 +46,20 @@ class TaskTest < Test::Unit::TestCase
def test_create_and_fail
task = OpenTox::Task.create TASK_SERVICE_URI, :description => "test failure", :creator => "http://test.org/fake_creator" do
- sleep 1
- raise "an unexpected error occured"
+ sleep 0.5
+ raise "A runtime error occured"
+ end
+ assert task.running?
+ assert_equal "Running", task.hasStatus
+ task.wait
+ assert task.error?
+ assert_equal "Error", task.hasStatus
+ end
+
+ def test_create_and_fail_with_opentox_error
+ task = OpenTox::Task.create TASK_SERVICE_URI, :description => "test failure", :creator => "http://test.org/fake_creator" do
+ sleep 0.5
+ raise OpenTox::Error.new 500, "An OpenTox::Error occured"
end
assert task.running?
assert_equal "Running", task.hasStatus
@@ -56,14 +70,17 @@ class TaskTest < Test::Unit::TestCase
def test_wrong_result_uri
task = OpenTox::Task.create TASK_SERVICE_URI, :description => "test wrong result uri", :creator => "http://test.org/fake_creator" do
- sleep 1
+ sleep 0.5
"Asasadasd"
end
assert task.running?
assert_equal "Running", task.hasStatus
+ puts task.uri
task.wait
assert task.error?
- assert_equal "Error", task.hasStatus
+ #assert_equal "Error", task.hasStatus
end
+=begin
+=end
end