triannon 0.7.1 → 0.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Rakefile +2 -6
- data/app/controllers/triannon/annotations_controller.rb +18 -4
- data/app/controllers/triannon/search_controller.rb +9 -0
- data/app/models/triannon/annotation.rb +7 -7
- data/app/services/triannon/ldp_loader.rb +11 -5
- data/app/services/triannon/ldp_writer.rb +26 -24
- data/app/services/triannon/solr_searcher.rb +10 -1
- data/app/services/triannon/solr_writer.rb +25 -10
- data/lib/triannon/error.rb +25 -2
- data/lib/triannon/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2548790e908598e117e457e7e2d051e30a9f40e4
|
4
|
+
data.tar.gz: 92b887940f9dcc100cb1c6aeca47f44b1aa2f641
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1fefd1bc5ea2b5e8d69d2c48c4cd7d8422ba861815f6ad79b89a44abf05bd2d81588e2226f41f2c8ab823741e56188023da18b4429ba7eb520dc1b46a7f42ba6
|
7
|
+
data.tar.gz: 87e9f142299da474e9f4ea8ba7405efa549429e883d2d0350986814571dd4d73bee2ad9cc993d2061b55949530cf8e8c6c48188725172a31087e1800bcb35de5
|
data/Rakefile
CHANGED
@@ -11,13 +11,9 @@ require 'jettywrapper'
|
|
11
11
|
|
12
12
|
require 'engine_cart/rake_task'
|
13
13
|
desc 'run the triannon specs'
|
14
|
-
task :ci =>
|
15
|
-
# run the tests
|
14
|
+
task :ci => 'engine_cart:generate' do
|
16
15
|
RAILS_ENV = 'test'
|
17
|
-
|
18
|
-
Jettywrapper.wrap(jetty_params) do
|
19
|
-
Rake::Task['spec'].invoke
|
20
|
-
end
|
16
|
+
Rake::Task['spec'].invoke
|
21
17
|
end
|
22
18
|
|
23
19
|
namespace :triannon do
|
@@ -4,9 +4,11 @@ module Triannon
|
|
4
4
|
class AnnotationsController < ApplicationController
|
5
5
|
include RdfResponseFormats
|
6
6
|
|
7
|
+
rescue_from Triannon::LDPStorageError, with: :ldp_storage_error
|
8
|
+
rescue_from Triannon::ExternalReferenceError, with: :ext_ref_error
|
9
|
+
rescue_from Triannon::SearchError, with: :search_error
|
7
10
|
before_action :default_format_jsonld, only: [:show]
|
8
11
|
before_action :set_annotation, only: [:show, :update, :destroy]
|
9
|
-
rescue_from Triannon::ExternalReferenceError, with: :ext_ref_error
|
10
12
|
|
11
13
|
# GET /annotations
|
12
14
|
def index
|
@@ -133,9 +135,21 @@ private
|
|
133
135
|
@annotation = Annotation.find(params[:id])
|
134
136
|
end
|
135
137
|
|
136
|
-
#
|
137
|
-
def ext_ref_error(
|
138
|
-
render plain:
|
138
|
+
# render Triannon::ExternalReferenceError
|
139
|
+
def ext_ref_error(err)
|
140
|
+
render plain: err.message, status: 403
|
141
|
+
end
|
142
|
+
|
143
|
+
# render Triannon::LDPStorage error
|
144
|
+
def ldp_storage_error(err)
|
145
|
+
render :body => "<h2>#{err.message}</h2>" + err.ldp_resp_body, status: err.ldp_resp_status, content_type: "text/html"
|
146
|
+
end
|
147
|
+
|
148
|
+
# render Triannon::SearchError
|
149
|
+
def search_error(err)
|
150
|
+
render :body => "<h2>#{err.message}</h2>" + (err.search_resp_body ? err.search_resp_body : ""),
|
151
|
+
status: err.search_resp_status ? err.search_resp_status : 400,
|
152
|
+
content_type: "text/html"
|
139
153
|
end
|
140
154
|
|
141
155
|
# render json_ld respecting requested context
|
@@ -5,6 +5,7 @@ module Triannon
|
|
5
5
|
include RdfResponseFormats
|
6
6
|
|
7
7
|
before_action :default_format_jsonld, only: [:find]
|
8
|
+
rescue_from Triannon::SearchError, with: :search_error
|
8
9
|
|
9
10
|
def find
|
10
11
|
anno_graphs_array = solr_searcher.find(params)
|
@@ -40,6 +41,14 @@ module Triannon
|
|
40
41
|
@ss ||= Triannon::SolrSearcher.new
|
41
42
|
end
|
42
43
|
|
44
|
+
private
|
45
|
+
|
46
|
+
# render Triannon::SearchError
|
47
|
+
def search_error(err)
|
48
|
+
render :body => "<h2>#{err.message}</h2>" + (err.search_resp_body ? err.search_resp_body : ""),
|
49
|
+
status: err.search_resp_status ? err.search_resp_status : 400,
|
50
|
+
content_type: "text/html"
|
51
|
+
end
|
43
52
|
|
44
53
|
end # SearchController
|
45
54
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module Triannon
|
2
2
|
class Annotation
|
3
3
|
include ActiveModel::Model
|
4
|
-
|
4
|
+
|
5
5
|
define_model_callbacks :save, :destroy
|
6
6
|
after_save :solr_save
|
7
7
|
after_destroy :solr_delete
|
@@ -19,7 +19,7 @@ module Triannon
|
|
19
19
|
|
20
20
|
|
21
21
|
# Class Methods ----------------------------------------------------------------
|
22
|
-
|
22
|
+
|
23
23
|
def self.create(attrs = {})
|
24
24
|
a = Triannon::Annotation.new attrs
|
25
25
|
a.save
|
@@ -77,12 +77,12 @@ module Triannon
|
|
77
77
|
@graph = Triannon::Graph.new g
|
78
78
|
end
|
79
79
|
end
|
80
|
-
|
80
|
+
|
81
81
|
# @return json-ld representation of anno with OpenAnnotation context as a url
|
82
82
|
def jsonld_oa
|
83
83
|
graph.jsonld_oa
|
84
84
|
end
|
85
|
-
|
85
|
+
|
86
86
|
# @return json-ld representation of anno with IIIF context as a url
|
87
87
|
def jsonld_iiif
|
88
88
|
graph.jsonld_iiif
|
@@ -109,7 +109,7 @@ protected
|
|
109
109
|
def solr_delete
|
110
110
|
solr_writer.delete(id) if id
|
111
111
|
end
|
112
|
-
|
112
|
+
|
113
113
|
private
|
114
114
|
|
115
115
|
# loads RDF::Graph from data attribute. If data is in json-ld or rdfxml, converts it to turtle.
|
@@ -130,7 +130,7 @@ private
|
|
130
130
|
else # infer the content type from the content itself
|
131
131
|
case data
|
132
132
|
# \A and \Z and m are needed instead of ^$ due to \n in data
|
133
|
-
when /\A\{.+\}\Z/m
|
133
|
+
when /\A\{.+\}\Z/m
|
134
134
|
g = jsonld_to_graph
|
135
135
|
when /\A<.+>\Z/m
|
136
136
|
g = rdfxml_to_graph
|
@@ -143,7 +143,7 @@ private
|
|
143
143
|
end
|
144
144
|
g
|
145
145
|
end
|
146
|
-
|
146
|
+
|
147
147
|
# create and load an RDF::Graph object from turtle in data attrib
|
148
148
|
# @return [RDF::Graph] populated RDF::Graph object, or nil
|
149
149
|
def ttl_to_graph
|
@@ -37,7 +37,7 @@ module Triannon
|
|
37
37
|
|
38
38
|
# load body objects into @ldp_annotation's (our Triannon::AnnotationLdp object) graph
|
39
39
|
def load_bodies
|
40
|
-
@ldp_annotation.body_uris.each { |body_uri|
|
40
|
+
@ldp_annotation.body_uris.each { |body_uri|
|
41
41
|
body_obj_path = body_uri.to_s.split(@base_uri + '/').last
|
42
42
|
load_object_into_annotation_graph(body_obj_path)
|
43
43
|
}
|
@@ -45,12 +45,12 @@ module Triannon
|
|
45
45
|
|
46
46
|
# load target objects into @ldp_annotation's (our Triannon::AnnotationLdp object) graph
|
47
47
|
def load_targets
|
48
|
-
@ldp_annotation.target_uris.each { |target_uri|
|
48
|
+
@ldp_annotation.target_uris.each { |target_uri|
|
49
49
|
target_obj_path = target_uri.to_s.split(@base_uri + '/').last
|
50
50
|
load_object_into_annotation_graph(target_obj_path)
|
51
51
|
}
|
52
52
|
end
|
53
|
-
|
53
|
+
|
54
54
|
# @return [Array<Triannon::Annotation>] an array of Triannon::Annotation objects with just the id set. Enough info to build the index page
|
55
55
|
def find_all
|
56
56
|
root_ttl = get_ttl
|
@@ -83,13 +83,17 @@ module Triannon
|
|
83
83
|
req.url "#{sub_path}" if sub_path
|
84
84
|
req.headers['Accept'] = 'application/x-turtle'
|
85
85
|
end
|
86
|
-
resp.
|
86
|
+
if resp.status.between?(400, 600)
|
87
|
+
raise Triannon::LDPStorageError.new("error getting #{sub_path} from LDP", resp.status, resp.body)
|
88
|
+
else
|
89
|
+
resp.body
|
90
|
+
end
|
87
91
|
end
|
88
92
|
|
89
93
|
# turns turtle serialization into Array of RDF::Statements, removing fedora-specific triples
|
90
94
|
# (leaving LDP and OA triples)
|
91
95
|
# @param [String] ttl a String containing RDF serialized as turtle
|
92
|
-
# @return [Array<RDF::Statements>] the RDF statements represented in the ttl
|
96
|
+
# @return [Array<RDF::Statements>] the RDF statements represented in the ttl
|
93
97
|
def statements_from_ttl_minus_fedora ttl
|
94
98
|
# RDF::Turtle::Reader.new(ttl).statements.to_a
|
95
99
|
g = RDF::Graph.new.from_ttl(ttl) if ttl
|
@@ -98,6 +102,8 @@ module Triannon
|
|
98
102
|
|
99
103
|
def conn
|
100
104
|
@c ||= Faraday.new @base_uri
|
105
|
+
@c.headers['Prefer'] = 'return=respresentation; omit="http://fedora.info/definitions/v4/repository#ServerManaged"'
|
106
|
+
@c
|
101
107
|
end
|
102
108
|
|
103
109
|
end
|
@@ -7,7 +7,7 @@ module Triannon
|
|
7
7
|
# @param [Triannon::Annotation] anno a Triannon::Annotation object, from which we use the graph
|
8
8
|
def self.create_anno(anno)
|
9
9
|
if anno && anno.graph
|
10
|
-
# TODO: special case if the Annotation object already has an id --
|
10
|
+
# TODO: special case if the Annotation object already has an id --
|
11
11
|
# see https://github.com/sul-dlss/triannon/issues/84
|
12
12
|
ldp_writer = Triannon::LdpWriter.new anno
|
13
13
|
id = ldp_writer.create_base
|
@@ -39,11 +39,11 @@ module Triannon
|
|
39
39
|
ldpw.delete_containers id
|
40
40
|
end
|
41
41
|
end
|
42
|
-
|
42
|
+
|
43
43
|
class << self
|
44
44
|
alias_method :delete_anno, :delete_container
|
45
45
|
end
|
46
|
-
|
46
|
+
|
47
47
|
# @param [Triannon::Annotation] anno a Triannon::Annotation object
|
48
48
|
# @param [String] id the unique id for the LDP container for the passed annotation; defaults to nil
|
49
49
|
def initialize(anno, id=nil)
|
@@ -59,14 +59,14 @@ module Triannon
|
|
59
59
|
if @anno.graph.query([nil, RDF::Triannon.externalReference, nil]).count > 0
|
60
60
|
raise Triannon::ExternalReferenceError, "Incoming annotations may not have http://triannon.stanford.edu/ns/externalReference as a predicate."
|
61
61
|
end
|
62
|
-
|
62
|
+
|
63
63
|
if @anno.graph.id_as_url && @anno.graph.id_as_url.size > 0
|
64
64
|
raise Triannon::ExternalReferenceError, "Incoming new annotations may not have an existing id (yet)."
|
65
65
|
end
|
66
66
|
|
67
|
-
# TODO: special case if the Annotation object already has an id --
|
67
|
+
# TODO: special case if the Annotation object already has an id --
|
68
68
|
# see https://github.com/sul-dlss/triannon/issues/84
|
69
|
-
|
69
|
+
|
70
70
|
# we need to work with a copy of the graph so we don't change @anno.graph
|
71
71
|
g = RDF::Graph.new
|
72
72
|
@anno.graph.each { |s|
|
@@ -93,7 +93,7 @@ module Triannon
|
|
93
93
|
def create_body_resources
|
94
94
|
create_resources_in_container RDF::OpenAnnotation.hasBody
|
95
95
|
end
|
96
|
-
|
96
|
+
|
97
97
|
# create the target resources inside the (already created) target container
|
98
98
|
def create_target_resources
|
99
99
|
create_resources_in_container RDF::OpenAnnotation.hasTarget
|
@@ -108,11 +108,11 @@ module Triannon
|
|
108
108
|
ldp_container_uris = [ldp_container_uris]
|
109
109
|
end
|
110
110
|
something_deleted = false
|
111
|
-
ldp_container_uris.each { |uri|
|
111
|
+
ldp_container_uris.each { |uri|
|
112
112
|
ldp_id = uri.to_s.split(@base_uri + '/').last
|
113
113
|
resp = conn.delete { |req| req.url ldp_id }
|
114
114
|
if resp.status != 204
|
115
|
-
raise "Unable to delete LDP container
|
115
|
+
raise Triannon::LDPStorageError.new("Unable to delete LDP container #{ldp_id}", resp.status, resp.body)
|
116
116
|
end
|
117
117
|
something_deleted = true
|
118
118
|
}
|
@@ -121,8 +121,8 @@ module Triannon
|
|
121
121
|
|
122
122
|
protected
|
123
123
|
|
124
|
-
# POSTS a ttl representation of a graph to
|
125
|
-
# @param [String] ttl a turtle representation of RDF data to be put in the
|
124
|
+
# POSTS a ttl representation of a graph to an existing LDP container in the LDP store
|
125
|
+
# @param [String] ttl a turtle representation of RDF data to be put in the LDP container
|
126
126
|
# @param [String] parent_path the path portion of the url for the LDP parent container for this resource
|
127
127
|
# if no path is supplied, then the resource will be created as a child of the root annotation;
|
128
128
|
# expected paths would also be (anno_id)/t for a target resource (inside the target container of anno_id)
|
@@ -136,12 +136,12 @@ module Triannon
|
|
136
136
|
req.body = ttl
|
137
137
|
end
|
138
138
|
if resp.status != 200 && resp.status != 201
|
139
|
-
raise "Unable to create LDP resource in container #{parent_path}
|
139
|
+
raise Triannon::LDPStorageError.new("Unable to create LDP resource in container #{parent_path}; RDF sent: #{ttl}", resp.status, resp.body)
|
140
140
|
end
|
141
141
|
new_url = resp.headers['Location'] ? resp.headers['Location'] : resp.headers['location']
|
142
142
|
new_url.split('/').last if new_url
|
143
143
|
end
|
144
|
-
|
144
|
+
|
145
145
|
# Creates an empty LDP DirectContainer in LDP Storage that is a member of the base container and has the memberRelation per the oa_vocab_term
|
146
146
|
# The id of the created containter will be (base container id)/b if hasBody or (base container id)/t if hasTarget
|
147
147
|
# @param [RDF::Vocabulary::Term] oa_vocab_term RDF::OpenAnnotation.hasTarget or RDF::OpenAnnotation.hasBody
|
@@ -160,7 +160,7 @@ module Triannon
|
|
160
160
|
req.body = g.to_ttl
|
161
161
|
end
|
162
162
|
if resp.status != 201
|
163
|
-
raise "Unable to create #{oa_vocab_term.fragment.sub('has', '')} LDP container for anno
|
163
|
+
raise Triannon::LDPStorageError.new("Unable to create #{oa_vocab_term.fragment.sub('has', '')} LDP container for anno; RDF sent: #{g.to_ttl}", resp.status, resp.body)
|
164
164
|
end
|
165
165
|
resp
|
166
166
|
end
|
@@ -176,7 +176,7 @@ module Triannon
|
|
176
176
|
if predicate_obj.is_a?(RDF::Node)
|
177
177
|
# we need to use the null relative URI representation of blank nodes to write to LDP
|
178
178
|
predicate_subject = RDF::URI.new
|
179
|
-
else
|
179
|
+
else
|
180
180
|
# it's already a URI, but we need to use the null relative URI representation so we can
|
181
181
|
# write out as a Triannon:externalRef property with the URL, and any addl props too.
|
182
182
|
if predicate_obj.to_str
|
@@ -185,7 +185,7 @@ module Triannon
|
|
185
185
|
:predicate => RDF::Triannon.externalReference,
|
186
186
|
:object => RDF::URI.new(predicate_obj.to_str)})
|
187
187
|
addl_stmts = @anno.graph.query([predicate_obj, nil, nil])
|
188
|
-
addl_stmts.each { |s|
|
188
|
+
addl_stmts.each { |s|
|
189
189
|
graph_for_resource << RDF::Statement({:subject => predicate_subject,
|
190
190
|
:predicate => s.predicate,
|
191
191
|
:object => s.object})
|
@@ -194,13 +194,13 @@ module Triannon
|
|
194
194
|
predicate_subject = predicate_obj
|
195
195
|
end
|
196
196
|
end
|
197
|
-
|
197
|
+
|
198
198
|
# add statements with predicate_obj as the subject
|
199
199
|
orig_hash_uri_objs = [] # the orig URI objects from [targetObject, OA.hasSource/.default/.item, (uri)] statements
|
200
200
|
hash_uri_counter = 1
|
201
201
|
Triannon::Graph.subject_statements(predicate_obj, @anno.graph).each { |s|
|
202
202
|
if s.subject == predicate_obj
|
203
|
-
# deal with any external URI references which may occur in:
|
203
|
+
# deal with any external URI references which may occur in:
|
204
204
|
# OA.hasSource (from SpecificResource), OA.default or OA.item (from Choice, Composite, List)
|
205
205
|
if s.object.is_a?(RDF::URI) && s.object.to_s
|
206
206
|
# do we need to represent the URL as an externalReference with hash URI
|
@@ -218,7 +218,7 @@ module Triannon
|
|
218
218
|
:predicate => s.predicate,
|
219
219
|
:object => s.object})
|
220
220
|
end
|
221
|
-
|
221
|
+
|
222
222
|
if hash_uri_str
|
223
223
|
# represent the object URL as an external ref
|
224
224
|
new_hash_uri_obj = RDF::URI.new(hash_uri_str)
|
@@ -228,7 +228,7 @@ module Triannon
|
|
228
228
|
graph_for_resource << RDF::Statement({:subject => predicate_subject,
|
229
229
|
:predicate => s.predicate,
|
230
230
|
:object => new_hash_uri_obj})
|
231
|
-
|
231
|
+
|
232
232
|
# add externalReference triple to graph
|
233
233
|
graph_for_resource << RDF::Statement({:subject => new_hash_uri_obj,
|
234
234
|
:predicate => RDF::Triannon.externalReference,
|
@@ -251,15 +251,15 @@ module Triannon
|
|
251
251
|
:predicate => s.predicate,
|
252
252
|
:object => s.object})
|
253
253
|
end
|
254
|
-
else
|
255
|
-
# s.subject != predicate_obj
|
254
|
+
else
|
255
|
+
# s.subject != predicate_obj
|
256
256
|
graph_for_resource << s
|
257
257
|
end
|
258
258
|
}
|
259
259
|
# make sure the graph we will write contains no extraneous statements about URIs
|
260
260
|
# now represented as hash URIs
|
261
|
-
orig_hash_uri_objs.each { |uri_node|
|
262
|
-
Triannon::Graph.subject_statements(uri_node, graph_for_resource).each { |s|
|
261
|
+
orig_hash_uri_objs.each { |uri_node|
|
262
|
+
Triannon::Graph.subject_statements(uri_node, graph_for_resource).each { |s|
|
263
263
|
graph_for_resource.delete(s)
|
264
264
|
}
|
265
265
|
}
|
@@ -274,6 +274,8 @@ module Triannon
|
|
274
274
|
|
275
275
|
def conn
|
276
276
|
@c ||= Faraday.new @base_uri
|
277
|
+
@c.headers['Prefer'] = 'return=respresentation; omit="http://fedora.info/definitions/v4/repository#ServerManaged"'
|
278
|
+
@c
|
277
279
|
end
|
278
280
|
|
279
281
|
end
|
@@ -14,7 +14,7 @@ module Triannon
|
|
14
14
|
}
|
15
15
|
result
|
16
16
|
end
|
17
|
-
|
17
|
+
|
18
18
|
# @note hardcoded Solr search service expectation in generated search params
|
19
19
|
# @note hardcoded mapping of REST params for /search to Solr params
|
20
20
|
#
|
@@ -114,6 +114,8 @@ module Triannon
|
|
114
114
|
end
|
115
115
|
|
116
116
|
|
117
|
+
attr_accessor :rsolr_client
|
118
|
+
|
117
119
|
def initialize
|
118
120
|
@rsolr_client = RSolr.connect :url => Triannon.config[:solr_url]
|
119
121
|
@logger = Rails.logger
|
@@ -145,6 +147,12 @@ module Triannon
|
|
145
147
|
def search(solr_params = {})
|
146
148
|
handler = Proc.new do |exception, attempt_cnt, total_delay|
|
147
149
|
@logger.debug "#{exception.inspect} on Solr search attempt #{attempt_cnt} for #{solr_params.inspect}"
|
150
|
+
if exception.kind_of?(RSolr::Error::Http)
|
151
|
+
# Note there are extra shenanigans b/c RSolr hijacks the Solr error to return RSolr Error
|
152
|
+
raise Triannon::SearchError.new("error searching Solr with params #{solr_params.inspect}: #{exception.message}", exception.response[:status], exception.response[:body])
|
153
|
+
elsif exception.kind_of?(StandardError)
|
154
|
+
raise Triannon::SearchError.new("error searching Solr with params #{solr_params.inspect}: #{exception.message}")
|
155
|
+
end
|
148
156
|
end
|
149
157
|
|
150
158
|
response = nil
|
@@ -154,6 +162,7 @@ module Triannon
|
|
154
162
|
:max_sleep_seconds => @max_sleep_seconds) do |attempt|
|
155
163
|
@logger.debug "Solr search attempt #{attempt} for #{solr_params.inspect}"
|
156
164
|
# use POST in case of long params
|
165
|
+
# RSolr throws RSolr::Error::Http for any Solr response without status 200 or 302
|
157
166
|
response = @rsolr_client.post 'select', :params => solr_params
|
158
167
|
@logger.info "Successfully searched Solr on attempt #{attempt}"
|
159
168
|
end
|
@@ -47,6 +47,7 @@ module Triannon
|
|
47
47
|
doc_hash
|
48
48
|
end
|
49
49
|
|
50
|
+
attr_accessor :rsolr_client
|
50
51
|
|
51
52
|
def initialize
|
52
53
|
@rsolr_client = RSolr.connect :url => Triannon.config[:solr_url]
|
@@ -72,37 +73,51 @@ module Triannon
|
|
72
73
|
|
73
74
|
handler = Proc.new do |exception, attempt_cnt, total_delay|
|
74
75
|
@logger.debug "#{exception.inspect} on Solr add attempt #{attempt_cnt} for #{id}"
|
76
|
+
if exception.kind_of?(RSolr::Error::Http)
|
77
|
+
# Note there are extra shenanigans b/c RSolr hijacks the Solr error to return RSolr Error
|
78
|
+
raise Triannon::SearchError.new("error adding doc #{id} to Solr #{doc.inspect}; #{exception.message}", exception.response[:status], exception.response[:body])
|
79
|
+
elsif exception.kind_of?(StandardError)
|
80
|
+
raise Triannon::SearchError.new("error adding doc #{id} to Solr #{doc.inspect}; #{exception.message}")
|
81
|
+
end
|
75
82
|
end
|
76
83
|
|
77
|
-
with_retries(:handler => handler,
|
78
|
-
:max_tries => @max_retries,
|
79
|
-
:base_sleep_seconds => @base_sleep_seconds,
|
84
|
+
with_retries(:handler => handler,
|
85
|
+
:max_tries => @max_retries,
|
86
|
+
:base_sleep_seconds => @base_sleep_seconds,
|
80
87
|
:max_sleep_seconds => @max_sleep_seconds) do |attempt|
|
81
88
|
@logger.debug "Solr add attempt #{attempt} for #{id}"
|
82
89
|
# add it and commit within 0.5 seconds
|
83
90
|
@rsolr_client.add(doc, :add_attributes => {:commitWithin => 500})
|
91
|
+
# RSolr throws RSolr::Error::Http for any Solr response without status 200 or 302
|
84
92
|
@logger.info "Successfully indexed #{id} to Solr on attempt #{attempt}"
|
85
93
|
end
|
86
94
|
end
|
87
|
-
|
95
|
+
|
88
96
|
# Delete the document from Solr, retrying if an error occurs.
|
89
97
|
# See https://github.com/ooyala/retries for info on with_retries.
|
90
98
|
# @param [String] id the id of the Solr document to be deleted
|
91
99
|
def delete(id)
|
92
100
|
handler = Proc.new do |exception, attempt_cnt, total_delay|
|
93
101
|
@logger.debug "#{exception.inspect} on Solr delete attempt #{attempt_cnt} for #{id}"
|
94
|
-
|
102
|
+
if exception.kind_of?(RSolr::Error::Http)
|
103
|
+
# Note there are extra shenanigans b/c RSolr hijacks the Solr error to return RSolr Error
|
104
|
+
raise Triannon::SearchError.new("error deleting doc #{id} from Solr: #{exception.message}", exception.response[:status], exception.response[:body])
|
105
|
+
elsif exception.kind_of?(StandardError)
|
106
|
+
raise Triannon::SearchError.new("error deleting doc #{id} from Solr: #{exception.message}")
|
107
|
+
end
|
108
|
+
end
|
95
109
|
|
96
|
-
with_retries(:handler => handler,
|
97
|
-
:max_tries => @max_retries,
|
98
|
-
:base_sleep_seconds => @base_sleep_seconds,
|
110
|
+
with_retries(:handler => handler,
|
111
|
+
:max_tries => @max_retries,
|
112
|
+
:base_sleep_seconds => @base_sleep_seconds,
|
99
113
|
:max_sleep_seconds => @max_sleep_seconds) do |attempt|
|
100
114
|
@logger.debug "Solr delete attempt #{attempt} for #{id}"
|
115
|
+
# RSolr throws RSolr::Error::Http for any Solr response without status 200 or 302
|
101
116
|
@rsolr_client.delete_by_id(id)
|
102
117
|
@rsolr_client.commit
|
103
118
|
@logger.info "Successfully deleted #{id} from Solr"
|
104
|
-
end
|
119
|
+
end
|
105
120
|
end
|
106
|
-
|
121
|
+
|
107
122
|
end
|
108
123
|
end
|
data/lib/triannon/error.rb
CHANGED
@@ -2,8 +2,31 @@ module Triannon
|
|
2
2
|
# generic Triannon error allowing rescue to catch all Triannon exceptions
|
3
3
|
class Error < RuntimeError
|
4
4
|
end
|
5
|
-
|
5
|
+
|
6
6
|
class ExternalReferenceError < Triannon::Error
|
7
|
+
def initialize(message = nil)
|
8
|
+
super(message)
|
9
|
+
end
|
7
10
|
end
|
8
|
-
|
11
|
+
|
12
|
+
# used to keep HTTP response info from LDP
|
13
|
+
class LDPStorageError < Triannon::Error
|
14
|
+
attr_accessor :ldp_resp_status, :ldp_resp_body
|
15
|
+
def initialize(message = nil, ldp_resp_status = nil, ldp_resp_body = nil)
|
16
|
+
super(message)
|
17
|
+
self.ldp_resp_status = ldp_resp_status if ldp_resp_status
|
18
|
+
self.ldp_resp_body = ldp_resp_body if ldp_resp_body
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# used to keep HTTP response info from Solr
|
23
|
+
class SearchError < Triannon::Error
|
24
|
+
attr_accessor :search_resp_status, :search_resp_body
|
25
|
+
def initialize(message = nil, search_resp_status = nil, search_resp_body = nil)
|
26
|
+
super(message)
|
27
|
+
self.search_resp_status = search_resp_status if search_resp_status
|
28
|
+
self.search_resp_body = search_resp_body if search_resp_body
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
9
32
|
end
|
data/lib/triannon/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: triannon
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.7.
|
4
|
+
version: 0.7.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Beer
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2015-04-
|
13
|
+
date: 2015-04-14 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rails
|