summaryrefslogtreecommitdiff
path: root/lib/error.rb
blob: 29f42345b890ba6d45dcfc1cc482b571762f89b2 (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
# 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
    @http_code ||= 500
    @report = OpenTox::ErrorReport.create self
    $logger.error "\n"+@report.to_ntriples
  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,
    "ServiceUnavailableError" => 503,
    "TimeOutError" => 504,
    "LockedError" => 423,
    "NotImplementedError" => 501,
  }.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
      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
    
    # 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
end

class Array
  def short_backtrace
    short = []
    each do |c|
      break if c =~ /sinatra\/base/
      short << c
    end
    short.join("\n")
  end
end