openbel-api 0.5.1-java → 0.6.1-java

Sign up to get free protection for your applications and to get access to all the features.
@@ -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