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
|
require 'open4'
# adding additional fields to Exception class to format errors according to OT-API
class RuntimeError
attr_accessor :report, :http_code
def initialize message
super message
self.set_backtrace message.backtrace if message.is_a? Exception
@http_code ||= 500
puts self.class
@report = OpenTox::ErrorReport.create self
$logger.error "\n"+@report.to_turtle
end
end
module OpenTox
class Error < RuntimeError
def initialize code, message
@http_code = code
super message
end
end
# OpenTox errors
{
"BadRequestError" => 400,
"NotAuthorizedError" => 401,
"NotFoundError" => 404,
"LockedError" => 423,
"InternalServerError" => 500,
"NotImplementedError" => 501,
"ServiceUnavailableError" => 503,
"TimeOutError" => 504,
}.each do |klass,code|
# create error classes
c = Class.new Error do
define_method :initialize do |message|
super code, message
end
end
OpenTox.const_set klass,c
# define global methods for raising errors, eg. bad_request_error
Object.send(:define_method, klass.underscore.to_sym) do |message|
raise c.new message
end
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
attr_accessor :rdf # RDF Graph
attr_accessor :http_code # TODO: remove when task service is fixed
def initialize
@rdf = RDF::Graph.new
end
# creates a error report object, from an ruby-exception object
# @param [Exception] error
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
puts error.inspect
if error.respond_to? :response
statusCode = error.response.code if error.response
message = error.response.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
def actor=(uri)
# TODO: test actor assignement (in opentox-server)
subject = RDF::Query.execute(@rdf) do
pattern [:subject, RDF.type, RDF::OT.ErrorReport]
end.limit(1).select(:subject)
@rdf << [subject, RDF::OT.actor, uri]
end
# define to_ and self.from_ methods for various rdf formats
[:rdfxml,:ntriples,:turtle].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
end
# overwrite backtick operator to catch system errors
module Kernel
# Override raises an error if _cmd_ returns a non-zero exit status.
# Returns stdout if _cmd_ succeeds. Note that these are simply concatenated; STDERR is not inline.
def ` cmd
stdout, stderr = ''
status = Open4::popen4(cmd) do |pid, stdin_stream, stdout_stream, stderr_stream|
stdout = stdout_stream.read
stderr = stderr_stream.read
end
raise stderr.strip if !status.success?
return stdout
rescue Exception
internal_server_error $!
end
alias_method :system!, :system
def system cmd
`#{cmd}`
return true
end
end
class Array
def short_backtrace
short = []
each do |c|
break if c =~ /sinatra\/base/
short << c
end
short.join("\n")
end
end
|