openbel-api 0.5.1-java → 0.6.1-java

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.
@@ -1,100 +1,8 @@
1
- require 'uri'
2
- require 'rest-client'
3
-
4
- def current_host(env)
5
- scheme = env['rack.url_scheme'] || 'http'
6
- host = env['HTTP_HOST']
7
- "#{scheme}://#{host}"
8
- end
9
-
10
- def current_path(env)
11
- scheme = env['rack.url_scheme'] || 'http'
12
- host = env['HTTP_HOST']
13
- path = env['PATH_INFO']
14
- "#{scheme}://#{host}#{path}"
15
- end
16
-
17
1
  module OpenBEL
18
2
  module Routes
19
3
 
20
4
  class Authenticate < Base
21
5
 
22
- get '/api/authenticate' do
23
- state = params[:state]
24
- code = params[:code]
25
- if code.nil?
26
- default_connection = OpenBEL::Settings[:auth][:default_connection]
27
- default_auth_url = current_path(env) + "/#{default_connection}"
28
- if not state.nil?
29
- default_auth_url += "?state=#{state}"
30
- end
31
- redirect to(default_auth_url)
32
- end
33
-
34
- domain = OpenBEL::Settings[:auth][:domain]
35
- id = OpenBEL::Settings[:auth][:id]
36
- secret = OpenBEL::Settings[:auth][:secret]
37
-
38
- callback_url = current_path(env)
39
- payload = {
40
- client_id: id,
41
- client_secret: secret,
42
- redirect_uri: callback_url,
43
- code: code,
44
- grant_type: :authorization_code
45
- }
46
-
47
- token_url = "https://#{domain}/oauth/token"
48
- body = payload.to_json
49
-
50
- begin
51
- token_response = RestClient.post token_url, body,
52
- :content_type => :json,
53
- :accept => :json
54
- rescue => e
55
- hdrs = {'Content-Type' => 'application/json'}
56
- msg = {error: e.response }
57
- return [401, hdrs, [msg.to_json]]
58
- end
59
-
60
- token_response = JSON.parse(token_response)
61
- access_token = token_response['access_token']
62
- jwt = token_response['id_token']
63
-
64
- user_url = "https://#{domain}/userinfo?access_token=#{access_token}"
65
- begin
66
- user_response = RestClient.get user_url, :accept => :json
67
- rescue => e
68
- hdrs = {'Content-Type' => 'application/json'}
69
- msg = {error: e.response }
70
- return [401, hdrs, [msg.to_json]]
71
- end
72
-
73
- email = JSON.parse(user_response)['email']
74
- hdrs = {'Content-Type' => 'application/json'}
75
- msg = {success: email}
76
- cookies[:jwt] = jwt
77
- if not state.nil?
78
- redirect to(state + "?jwt=#{jwt}")
79
- else
80
- [200, hdrs, [msg.to_json]]
81
- end
82
- end
83
-
84
- get '/api/authenticate/:connection' do
85
- state = params[:state]
86
- redirect_setting = OpenBEL::Settings[:auth][:redirect]
87
- connection = params[:connection]
88
- redirect_uri = current_host(env) + '/api/authenticate'
89
- auth_url = "#{redirect_setting}"
90
- auth_url += "&redirect_uri=#{redirect_uri}"
91
- auth_url += "&connection=#{connection}"
92
- if not state.nil?
93
- auth_url += "&state=#{state}"
94
- end
95
- redirect to(auth_url)
96
- end
97
-
98
6
  get '/api/authentication-enabled' do
99
7
  enabled = OpenBEL::Settings[:auth][:enabled]
100
8
  hdrs = {'Content-Type' => 'application/json'}
@@ -21,14 +21,14 @@ module OpenBEL
21
21
  include OpenBEL::Resource::Namespaces
22
22
  include OpenBEL::Schemas
23
23
 
24
- DEFAULT_CONTENT_TYPE = 'application/hal+json'
25
- SPOKEN_CONTENT_TYPES = %w[application/hal+json application/json]
24
+ DEFAULT_CONTENT_TYPE = 'application/hal+json'
25
+ DEFAULT_CONTENT_TYPE_ID = :hal
26
+ SPOKEN_CONTENT_TYPES = %w[application/hal+json application/json]
26
27
  SPOKEN_CONTENT_TYPES.concat(
27
28
  BEL::Translator.plugins.values.flat_map { |p| p.media_types.map(&:to_s) }
28
29
  )
29
-
30
- SCHEMA_BASE_URL = 'http://next.belframework.org/schemas/'
31
- RESOURCE_SERIALIZERS = {
30
+ SCHEMA_BASE_URL = 'http://next.belframework.org/schemas/'
31
+ RESOURCE_SERIALIZERS = {
32
32
  :annotation => AnnotationResourceSerializer,
33
33
  :annotation_collection => AnnotationCollectionSerializer,
34
34
  :annotation_value => AnnotationValueResourceSerializer,
@@ -80,6 +80,16 @@ module OpenBEL
80
80
  SCHEMA_BASE_URL + "#{name}.schema.json"
81
81
  end
82
82
 
83
+ def wants_default?
84
+ if params[:format]
85
+ return params[:format] == DEFAULT_CONTENT_TYPE
86
+ end
87
+
88
+ request.accept.any? { |accept_entry|
89
+ accept_entry.to_s == DEFAULT_CONTENT_TYPE
90
+ }
91
+ end
92
+
83
93
  def validate_media_type!(content_type, options = {})
84
94
  ctype = request.content_type
85
95
  valid = ctype.start_with? content_type
@@ -143,6 +153,10 @@ module OpenBEL
143
153
  end
144
154
  end
145
155
 
156
+ def write_filter(filter)
157
+ MultiJson.dump(filter)
158
+ end
159
+
146
160
  def render_json(obj, media_type = 'application/hal+json', profile = nil)
147
161
  ctype =
148
162
  if profile
@@ -1,10 +1,13 @@
1
1
  require 'bel'
2
+ require 'bel/util'
2
3
  require 'rdf'
3
4
  require 'cgi'
4
5
  require 'multi_json'
5
6
  require 'openbel/api/evidence/mongo'
6
7
  require 'openbel/api/evidence/facet_filter'
7
8
  require_relative '../resources/evidence_transform'
9
+ require_relative '../helpers/evidence'
10
+ require_relative '../helpers/filters'
8
11
  require_relative '../helpers/pager'
9
12
 
10
13
  module OpenBEL
@@ -16,7 +19,6 @@ module OpenBEL
16
19
  include OpenBEL::Helpers
17
20
 
18
21
  DEFAULT_TYPE = 'application/hal+json'
19
-
20
22
  ACCEPTED_TYPES = {
21
23
  :bel => 'application/bel',
22
24
  :xml => 'application/xml',
@@ -24,9 +26,14 @@ module OpenBEL
24
26
  :json => 'application/json',
25
27
  }
26
28
 
29
+ MONGO_BATCH = 500
30
+ FACET_THRESHOLD = 10000
31
+
27
32
  def initialize(app)
28
33
  super
29
34
 
35
+ BEL.translator(:rdf)
36
+
30
37
  # Evidence API using Mongo.
31
38
  mongo = OpenBEL::Settings[:evidence_store][:mongo]
32
39
  @api = OpenBEL::Evidence::Evidence.new(mongo)
@@ -36,9 +43,6 @@ module OpenBEL
36
43
  :tdb_directory => OpenBEL::Settings[:resource_rdf][:jena][:tdb_directory]
37
44
  )
38
45
 
39
- # Load RDF monkeypatches.
40
- BEL::Translator.plugins[:rdf].create_translator
41
-
42
46
  # Annotations using RdfRepository
43
47
  annotations = BEL::Resource::Annotations.new(@rr)
44
48
  @annotation_transform = AnnotationTransform.new(annotations)
@@ -233,35 +237,66 @@ the "multipart/form-data" content type. Allowed dataset content types are: #{ACC
233
237
  # Create dataset in RDF.
234
238
  @rr.insert_statements(void_dataset)
235
239
 
236
- dataset = retrieve_dataset(void_dataset_uri)
240
+ dataset = retrieve_dataset(void_dataset_uri)
241
+ dataset_id = dataset[:identifier]
242
+
243
+ # Add batches of read evidence objects; save to Mongo and RDF.
244
+ # TODO Add JRuby note regarding Enumerator threading.
245
+ evidence_count = 0
246
+ evidence_batch = []
237
247
 
238
- # Add slices of read evidence objects; save to Mongo and RDF.
239
- BEL.evidence(io, type).each.lazy.each_slice(500) do |slice|
240
- slice.map! do |ev|
241
- # Standardize annotations from experiment_context.
242
- @annotation_transform.transform_evidence!(ev, base_url)
248
+ # Clear out all facets before loading dataset.
249
+ @api.delete_facets
243
250
 
244
- # Add filterable metadata field for dataset identifier.
245
- ev.metadata[:dataset] = dataset[:identifier]
251
+ BEL.evidence(io, type).each do |ev|
252
+ # Standardize annotations from experiment_context.
253
+ @annotation_transform.transform_evidence!(ev, base_url)
246
254
 
247
- facets = map_evidence_facets(ev)
248
- ev.bel_statement = ev.bel_statement.to_s
249
- hash = ev.to_h
250
- hash[:facets] = facets
255
+ ev.metadata[:dataset] = dataset_id
256
+ facets = map_evidence_facets(ev)
257
+ ev.bel_statement = ev.bel_statement.to_s
258
+ hash = BEL.object_convert(String, ev.to_h) { |str|
259
+ str.gsub(/\n/, "\\n").gsub(/\r/, "\\r")
260
+ }
261
+ hash[:facets] = facets
262
+ # Create dataset field for efficient removal.
263
+ hash[:_dataset] = dataset_id
251
264
 
252
- # Create dataset field for efficient removal.
253
- hash[:_dataset] = dataset[:identifier]
254
- hash
265
+ evidence_batch << hash
266
+
267
+ if evidence_batch.size == MONGO_BATCH
268
+ _ids = @api.create_evidence(evidence_batch)
269
+
270
+ dataset_parts = _ids.map { |object_id|
271
+ RDF::Statement.new(void_dataset_uri, RDF::DC.hasPart, object_id.to_s)
272
+ }
273
+ @rr.insert_statements(dataset_parts)
274
+
275
+ evidence_batch.clear
276
+
277
+ # Clear out all facets after FACET_THRESHOLD nanopubs have been seen.
278
+ evidence_count += MONGO_BATCH
279
+ if evidence_count >= FACET_THRESHOLD
280
+ @api.delete_facets
281
+ evidence_count = 0
282
+ end
255
283
  end
284
+ end
256
285
 
257
- _ids = @api.create_evidence(slice)
286
+ unless evidence_batch.empty?
287
+ _ids = @api.create_evidence(evidence_batch)
258
288
 
259
289
  dataset_parts = _ids.map { |object_id|
260
290
  RDF::Statement.new(void_dataset_uri, RDF::DC.hasPart, object_id.to_s)
261
291
  }
262
292
  @rr.insert_statements(dataset_parts)
293
+
294
+ evidence_batch.clear
263
295
  end
264
296
 
297
+ # Clear out all facets after the dataset is completely loaded.
298
+ @api.delete_facets
299
+
265
300
  status 201
266
301
  headers 'Location' => void_dataset_uri.to_s
267
302
  end
@@ -297,142 +332,19 @@ the "multipart/form-data" content type. Allowed dataset content types are: #{ACC
297
332
  start = (params[:start] || 0).to_i
298
333
  size = (params[:size] || 0).to_i
299
334
  faceted = as_bool(params[:faceted])
300
- max_values_per_facet = (params[:max_values_per_facet] || 0).to_i
301
-
302
- # check filters
303
- filters = []
304
- filter_params = CGI::parse(env["QUERY_STRING"])['filter']
305
- filter_params.each do |filter|
306
- filter = read_filter(filter)
307
- halt 400 unless ['category', 'name', 'value'].all? { |f| filter.include? f}
308
-
309
- if filter['category'] == 'fts' && filter['name'] == 'search'
310
- unless filter['value'].to_s.length > 1
311
- halt(
312
- 400,
313
- { 'Content-Type' => 'application/json' },
314
- render_json({
315
- :status => 400,
316
- :msg => 'Full-text search filter values must be larger than one.'
317
- })
318
- )
319
- end
320
- end
321
-
322
- # Remove dataset filters since we're filtering a specific one already.
323
- next if filter.values_at('category', 'name') == ['metadata', 'dataset']
335
+ max_values_per_facet = (params[:max_values_per_facet] || -1).to_i
324
336
 
325
- filters << filter
326
- end
337
+ filters = validate_filters!
327
338
 
328
339
  collection_total = @api.count_evidence
329
340
  filtered_total = @api.count_evidence(filters)
330
- page_results = @api.find_dataset_evidence(dataset, filters, start, size, faceted)
331
-
332
- accept_type = request.accept.find { |accept_entry|
333
- ACCEPTED_TYPES.values.include?(accept_entry.to_s)
334
- }
335
- accept_type ||= DEFAULT_TYPE
336
-
337
- if params[:format]
338
- translator = BEL::Translator.plugins[params[:format].to_sym]
339
- halt 501 if !translator || translator.id == :rdf
340
- accept_type = [translator.media_types].flatten.first
341
- end
342
-
343
- if accept_type == DEFAULT_TYPE
344
- evidence = page_results[:cursor].map { |item|
345
- item.delete('facets')
346
- item
347
- }.to_a
348
-
349
- facets = page_results[:facets]
350
-
351
- halt 404 if evidence.empty?
352
-
353
- pager = Pager.new(start, size, filtered_total)
354
-
355
- options = {
356
- :start => start,
357
- :size => size,
358
- :filters => filter_params,
359
- :metadata => {
360
- :collection_paging => {
361
- :total => collection_total,
362
- :total_filtered => pager.total_size,
363
- :total_pages => pager.total_pages,
364
- :current_page => pager.current_page,
365
- :current_page_size => evidence.size,
366
- }
367
- }
368
- }
369
-
370
- if facets
371
- # group by category/name
372
- hashed_values = Hash.new { |hash, key| hash[key] = [] }
373
- facets.each { |facet|
374
- filter = read_filter(facet['_id'])
375
- category, name = filter.values_at('category', 'name')
376
- next if !category || !name
377
-
378
- key = [category.to_sym, name.to_sym]
379
- facet_obj = {
380
- :value => filter['value'],
381
- :filter => facet['_id'],
382
- :count => facet['count']
383
- }
384
- hashed_values[key] << facet_obj
385
- }
386
-
387
- if max_values_per_facet == 0
388
- facet_hashes = hashed_values.map { |(category, name), value_objects|
389
- {
390
- :category => category,
391
- :name => name,
392
- :values => value_objects
393
- }
394
- }
395
- else
396
- facet_hashes = hashed_values.map { |(category, name), value_objects|
397
- {
398
- :category => category,
399
- :name => name,
400
- :values => value_objects.take(max_values_per_facet)
401
- }
402
- }
403
- end
404
-
405
- options[:facets] = facet_hashes
406
- end
407
-
408
- # pager links
409
- options[:previous_page] = pager.previous_page
410
- options[:next_page] = pager.next_page
411
-
412
- render_collection(evidence, :evidence, options)
413
- else
414
- out_translator = BEL.translator(accept_type)
415
- extension = ACCEPTED_TYPES.key(accept_type.to_s)
416
-
417
- response.headers['Content-Type'] = accept_type
418
- status 200
419
- attachment "#{dataset[:identifier].gsub(/[^\w]/, '_')}.#{extension}"
420
- stream :keep_open do |response|
421
- cursor = page_results[:cursor]
422
- json_evidence_enum = cursor.lazy.map { |evidence|
423
- evidence.delete('facets')
424
- evidence.delete('_id')
425
- evidence.keys.each do |key|
426
- evidence[key.to_sym] = evidence.delete(key)
427
- end
428
- BEL::Model::Evidence.create(evidence)
429
- }
341
+ page_results = @api.find_dataset_evidence(dataset, filters, start, size, faceted, max_values_per_facet)
342
+ name = dataset[:identifier].gsub(/[^\w]/, '_')
430
343
 
431
- out_translator.write(json_evidence_enum) do |converted_evidence|
432
- response << converted_evidence
433
- end
434
- end
435
- end
344
+ render_evidence_collection(
345
+ name, page_results, start, size, filters,
346
+ filtered_total, collection_total, @api
347
+ )
436
348
  end
437
349
 
438
350
  get '/api/datasets' do
@@ -469,6 +381,7 @@ the "multipart/form-data" content type. Allowed dataset content types are: #{ACC
469
381
  halt 404 unless dataset_exists?(void_dataset_uri)
470
382
 
471
383
  dataset = retrieve_dataset(void_dataset_uri)
384
+ # XXX Removes all facets due to load of many evidence.
472
385
  @api.delete_dataset(dataset[:identifier])
473
386
  @rr.delete_statement(RDF::Statement.new(void_dataset_uri, nil, nil))
474
387
 
@@ -485,6 +398,7 @@ the "multipart/form-data" content type. Allowed dataset content types are: #{ACC
485
398
 
486
399
  datasets.each do |void_dataset_uri|
487
400
  dataset = retrieve_dataset(void_dataset_uri)
401
+ # XXX Removes all facets due to load of many evidence.
488
402
  @api.delete_dataset(dataset[:identifier])
489
403
  @rr.delete_statement(RDF::Statement.new(void_dataset_uri, nil, nil))
490
404
  end
@@ -3,6 +3,8 @@ require 'cgi'
3
3
  require 'openbel/api/evidence/mongo'
4
4
  require 'openbel/api/evidence/facet_filter'
5
5
  require_relative '../resources/evidence_transform'
6
+ require_relative '../helpers/evidence'
7
+ require_relative '../helpers/filters'
6
8
  require_relative '../helpers/pager'
7
9
 
8
10
  module OpenBEL
@@ -142,19 +144,7 @@ module OpenBEL
142
144
  size = (params[:size] || 0).to_i
143
145
  group_as_array = as_bool(params[:group_as_array])
144
146
 
145
- # check filters
146
- filters = []
147
- filter_params = CGI::parse(env["QUERY_STRING"])['filter']
148
- filter_params.each do |filter|
149
- filter = read_filter(filter)
150
- halt 400 unless ['category', 'name', 'value'].all? { |f| filter.include? f}
151
-
152
- if filter['category'] == 'fts' && filter['name'] == 'search'
153
- halt 400 unless filter['value'].to_s.length > 1
154
- end
155
-
156
- filters << filter
157
- end
147
+ filters = validate_filters!
158
148
 
159
149
  cursor = @api.find_evidence(filters, start, size, false)[:cursor]
160
150
  if group_as_array
@@ -168,93 +158,18 @@ module OpenBEL
168
158
  start = (params[:start] || 0).to_i
169
159
  size = (params[:size] || 0).to_i
170
160
  faceted = as_bool(params[:faceted])
171
- max_values_per_facet = (params[:max_values_per_facet] || 0).to_i
161
+ max_values_per_facet = (params[:max_values_per_facet] || -1).to_i
172
162
 
173
- # check filters
174
- filters = []
175
- filter_params = CGI::parse(env["QUERY_STRING"])['filter']
176
- filter_params.each do |filter|
177
- filter = read_filter(filter)
178
- halt 400 unless ['category', 'name', 'value'].all? { |f| filter.include? f}
179
-
180
- if filter['category'] == 'fts' && filter['name'] == 'search'
181
- halt 400 unless filter['value'].to_s.length > 1
182
- end
183
-
184
- filters << filter
185
- end
163
+ filters = validate_filters!
186
164
 
187
165
  collection_total = @api.count_evidence()
188
166
  filtered_total = @api.count_evidence(filters)
189
- page_results = @api.find_evidence(filters, start, size, faceted)
190
- evidence = page_results[:cursor].map { |item|
191
- item.delete('facets')
192
- item
193
- }.to_a
194
- facets = page_results[:facets]
195
-
196
- halt 404 if evidence.empty?
197
-
198
- pager = Pager.new(start, size, filtered_total)
199
-
200
- options = {
201
- :start => start,
202
- :size => size,
203
- :filters => filter_params,
204
- :metadata => {
205
- :collection_paging => {
206
- :total => collection_total,
207
- :total_filtered => pager.total_size,
208
- :total_pages => pager.total_pages,
209
- :current_page => pager.current_page,
210
- :current_page_size => evidence.size,
211
- }
212
- }
213
- }
214
-
215
- if facets
216
- # group by category/name
217
- hashed_values = Hash.new { |hash, key| hash[key] = [] }
218
- facets.each { |facet|
219
- filter = read_filter(facet['_id'])
220
- category, name = filter.values_at('category', 'name')
221
- next if !category || !name
222
-
223
- key = [category.to_sym, name.to_sym]
224
- facet_obj = {
225
- :value => filter['value'],
226
- :filter => facet['_id'],
227
- :count => facet['count']
228
- }
229
- hashed_values[key] << facet_obj
230
- }
231
-
232
- if max_values_per_facet == 0
233
- facet_hashes = hashed_values.map { |(category, name), value_objects|
234
- {
235
- :category => category,
236
- :name => name,
237
- :values => value_objects
238
- }
239
- }
240
- else
241
- facet_hashes = hashed_values.map { |(category, name), value_objects|
242
- {
243
- :category => category,
244
- :name => name,
245
- :values => value_objects.take(max_values_per_facet)
246
- }
247
- }
248
- end
249
-
250
- options[:facets] = facet_hashes
251
- end
252
-
253
- # pager links
254
- options[:previous_page] = pager.previous_page
255
- options[:next_page] = pager.next_page
167
+ page_results = @api.find_evidence(filters, start, size, faceted, max_values_per_facet)
256
168
 
257
- render_collection(evidence, :evidence, options)
169
+ render_evidence_collection(
170
+ 'evidence-export', page_results, start, size, filters,
171
+ filtered_total, collection_total, @api
172
+ )
258
173
  end
259
174
 
260
175
  get '/api/evidence/:id' do