openbel-api 0.4.0-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.
Files changed (67) hide show
  1. checksums.yaml +7 -0
  2. data/.gemspec +65 -0
  3. data/CHANGELOG.md +22 -0
  4. data/INSTALL.md +19 -0
  5. data/INSTALL_RUBY.md +107 -0
  6. data/LICENSE +191 -0
  7. data/README.md +208 -0
  8. data/app/openbel/api/app.rb +83 -0
  9. data/app/openbel/api/config.rb +45 -0
  10. data/app/openbel/api/config.ru +3 -0
  11. data/app/openbel/api/helpers/pager.rb +109 -0
  12. data/app/openbel/api/middleware/auth.rb +112 -0
  13. data/app/openbel/api/resources/adapters/basic_json.rb +52 -0
  14. data/app/openbel/api/resources/annotation.rb +141 -0
  15. data/app/openbel/api/resources/base.rb +16 -0
  16. data/app/openbel/api/resources/completion.rb +89 -0
  17. data/app/openbel/api/resources/evidence.rb +115 -0
  18. data/app/openbel/api/resources/evidence_transform.rb +143 -0
  19. data/app/openbel/api/resources/function.rb +98 -0
  20. data/app/openbel/api/resources/match_result.rb +79 -0
  21. data/app/openbel/api/resources/namespace.rb +174 -0
  22. data/app/openbel/api/routes/annotations.rb +168 -0
  23. data/app/openbel/api/routes/authenticate.rb +108 -0
  24. data/app/openbel/api/routes/base.rb +326 -0
  25. data/app/openbel/api/routes/datasets.rb +519 -0
  26. data/app/openbel/api/routes/evidence.rb +330 -0
  27. data/app/openbel/api/routes/expressions.rb +560 -0
  28. data/app/openbel/api/routes/functions.rb +41 -0
  29. data/app/openbel/api/routes/namespaces.rb +382 -0
  30. data/app/openbel/api/routes/root.rb +39 -0
  31. data/app/openbel/api/schemas.rb +34 -0
  32. data/app/openbel/api/schemas/annotation_collection.schema.json +20 -0
  33. data/app/openbel/api/schemas/annotation_resource.schema.json +36 -0
  34. data/app/openbel/api/schemas/annotation_value_collection.schema.json +21 -0
  35. data/app/openbel/api/schemas/annotation_value_resource.schema.json +35 -0
  36. data/app/openbel/api/schemas/completion_collection.schema.json +21 -0
  37. data/app/openbel/api/schemas/completion_resource.schema.json +146 -0
  38. data/app/openbel/api/schemas/evidence.schema.json +198 -0
  39. data/app/openbel/api/schemas/evidence_collection.schema.json +98 -0
  40. data/app/openbel/api/schemas/evidence_resource.schema.json +29 -0
  41. data/app/openbel/api/schemas/namespace_value_collection.schema.json +21 -0
  42. data/app/openbel/api/schemas/namespace_value_resource.schema.json +43 -0
  43. data/app/openbel/api/util.rb +11 -0
  44. data/bin/openbel-api +78 -0
  45. data/bin/openbel-config +46 -0
  46. data/config/async_evidence.rb +12 -0
  47. data/config/async_jena.rb +14 -0
  48. data/config/config.yml +31 -0
  49. data/config/server_config.rb +184 -0
  50. data/lib/openbel/api/cache/cache.rb +30 -0
  51. data/lib/openbel/api/config/config.rb +33 -0
  52. data/lib/openbel/api/evidence/api.rb +39 -0
  53. data/lib/openbel/api/evidence/facet_api.rb +18 -0
  54. data/lib/openbel/api/evidence/facet_filter.rb +83 -0
  55. data/lib/openbel/api/evidence/mongo.rb +247 -0
  56. data/lib/openbel/api/evidence/mongo_facet.rb +105 -0
  57. data/lib/openbel/api/helpers/dependency_graph.rb +52 -0
  58. data/lib/openbel/api/model/rdf_resource.rb +74 -0
  59. data/lib/openbel/api/plugin/cache/kyotocabinet.rb +85 -0
  60. data/lib/openbel/api/plugin/configure_plugins.rb +97 -0
  61. data/lib/openbel/api/plugin/evidence/evidence.rb +58 -0
  62. data/lib/openbel/api/plugin/plugin.rb +99 -0
  63. data/lib/openbel/api/plugin/plugin_manager.rb +20 -0
  64. data/lib/openbel/api/plugin/plugin_repository.rb +60 -0
  65. data/lib/openbel/api/storage/cache_proxy.rb +74 -0
  66. data/lib/openbel/api/storage/triple_storage.rb +43 -0
  67. metadata +379 -0
@@ -0,0 +1,83 @@
1
+ require 'rubygems'
2
+
3
+ # TODO This should probably be in app-config.rb.
4
+ require 'jrjackson'
5
+
6
+ require_relative 'util'
7
+
8
+ require 'rack/cors'
9
+ require 'sinatra/base'
10
+ require "sinatra/reloader"
11
+ require "sinatra/cookies"
12
+
13
+ require_relative 'config'
14
+ require_relative 'routes/base'
15
+ require_relative 'routes/root'
16
+ require_relative 'routes/annotations'
17
+ require_relative 'routes/evidence'
18
+ require_relative 'routes/datasets'
19
+ require_relative 'routes/expressions'
20
+ require_relative 'routes/functions'
21
+ require_relative 'routes/namespaces'
22
+ require_relative 'routes/authenticate'
23
+ require_relative 'middleware/auth'
24
+
25
+ module OpenBEL
26
+
27
+ class Server < Sinatra::Application
28
+
29
+ configure :development do
30
+ register Sinatra::Reloader
31
+ end
32
+
33
+ configure do
34
+ config = OpenBEL::Config::load!
35
+ OpenBEL.const_set :Settings, config
36
+ end
37
+
38
+ if OpenBEL::Settings[:auth][:enabled]
39
+ enable :sessions
40
+ set :session_secret, OpenBEL::Settings['session_secret']
41
+ end
42
+
43
+ use Rack::Deflater
44
+ use Rack::Cors do
45
+ allow do
46
+ origins '*'
47
+ resource '*',
48
+ :headers => :any,
49
+ :methods => [ :get, :post, :put, :delete, :options ],
50
+ :max_age => 1,
51
+ :credentials => false,
52
+ :expose => [
53
+ 'Allow',
54
+ 'Content-Type',
55
+ 'Content-Encoding',
56
+ 'Content-Length',
57
+ 'ETag',
58
+ 'Last-Modified',
59
+ 'Link',
60
+ 'Location'
61
+ ]
62
+ end
63
+ end
64
+ disable :protection
65
+
66
+ # routes not requiring authentication
67
+ use OpenBEL::Routes::Root
68
+ use OpenBEL::Routes::Annotations
69
+ use OpenBEL::Routes::Expressions
70
+ use OpenBEL::Routes::Functions
71
+ use OpenBEL::Routes::Namespaces
72
+ use OpenBEL::Routes::Authenticate
73
+
74
+ # routes requiring authentication
75
+ if OpenBEL::Settings[:auth][:enabled]
76
+ use OpenBEL::JWTMiddleware::Authentication
77
+ end
78
+ use OpenBEL::Routes::Datasets
79
+ use OpenBEL::Routes::Evidence
80
+ end
81
+ end
82
+ # vim: ts=2 sts=2 sw=2
83
+ # encoding: utf-8
@@ -0,0 +1,45 @@
1
+ require 'dot_hash'
2
+
3
+ module OpenBEL
4
+ module Config
5
+ include DotHash
6
+
7
+ CFG_VAR = 'OPENBEL_API_CONFIG_FILE'
8
+
9
+ def self.load!
10
+ config_file = ENV[CFG_VAR] || raise('No OpenBEL API configuration found. Set the OPENBEL_API_CONFIG_FILE environment variable.')
11
+ config = {}
12
+ File.open(config_file, 'r:UTF-8') do |cf|
13
+ config = YAML::load(cf)
14
+ if not config
15
+ config = {}
16
+ end
17
+ end
18
+ cfg = Settings.new config, SilentProperties
19
+
20
+ failure = validate cfg
21
+ if failure
22
+ if block_given?
23
+ yield failure[1]
24
+ else
25
+ fail "Configuration error: #{failure[1]}"
26
+ end
27
+ end
28
+
29
+ cfg
30
+ end
31
+
32
+ private
33
+
34
+ def self.validate(cfg)
35
+ nil
36
+ end
37
+
38
+ class SilentProperties < Properties
39
+ def method_missing(key, *args, &block)
40
+ return nil unless has_key?(key)
41
+ execute(key, *args, &block)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,3 @@
1
+ require_relative 'app'
2
+
3
+ run OpenBEL::Server
@@ -0,0 +1,109 @@
1
+ module OpenBEL
2
+ module Helpers
3
+
4
+ class Pager
5
+
6
+ NEGATIVE_FUNCTION = lambda { |v| v < 0 ? 0 : v }
7
+ FLOAT_FUNCTION = lambda { |v| Float(v) }
8
+ PREVIOUS_COND_FUNCTION = lambda { |pager, neg_proc, pos_proc|
9
+ [
10
+ pager.start_offset,
11
+ pager.page_size,
12
+ ].any?(&(lambda { |v| v <= 0 })) ?
13
+ neg_proc.call(pager) :
14
+ pos_proc.call(pager)
15
+ }
16
+ NEXT_COND_FUNCTION = lambda { |pager, false_proc, true_proc|
17
+ test = pager.page_size > 0
18
+ test &= (pager.start_offset + pager.page_size) <= pager.total_size
19
+
20
+ test ?
21
+ true_proc.call(pager) :
22
+ false_proc.call(pager)
23
+ }
24
+
25
+ private_constant :NEGATIVE_FUNCTION
26
+ private_constant :FLOAT_FUNCTION
27
+ private_constant :PREVIOUS_COND_FUNCTION
28
+ private_constant :NEXT_COND_FUNCTION
29
+
30
+ def initialize(start_offset, page_size, total_size)
31
+ raise ArgumentError.new("start_offset must be >= 0") if start_offset < 0
32
+ raise ArgumentError.new("page_size must be >= 0") if page_size < 0
33
+ raise ArgumentError.new("total_size must be >= 0") if total_size < 0
34
+
35
+ @start_offset = NEGATIVE_FUNCTION.call(start_offset)
36
+ @page_size = FLOAT_FUNCTION.call(page_size)
37
+ @total_size = total_size
38
+ end
39
+
40
+ def start_offset
41
+ @start_offset
42
+ end
43
+
44
+ def current_page
45
+ return 0 if @total_size == 0
46
+
47
+ if @page_size > 0
48
+ ((@start_offset + @page_size) / @page_size).floor
49
+ else
50
+ total_pages = total_pages()
51
+
52
+ case total_pages
53
+ when 1
54
+ 1
55
+ when 2
56
+ midpoint = @total_size / total_pages
57
+ @start_offset < midpoint ? 1 : 2
58
+ end
59
+ end
60
+ end
61
+
62
+ def page_size
63
+ @page_size.to_i
64
+ end
65
+
66
+ def total_pages
67
+ return 0 if @total_size == 0
68
+
69
+ if @page_size > 0
70
+ (@total_size / @page_size).ceil
71
+ else
72
+ @start_offset == 0 ? 1 : 2
73
+ end
74
+ end
75
+
76
+ def total_size
77
+ @total_size
78
+ end
79
+
80
+ def previous_page
81
+ PREVIOUS_COND_FUNCTION.call(
82
+ self,
83
+ lambda { |_| nil },
84
+ lambda { |pager|
85
+ Pager.new(
86
+ NEGATIVE_FUNCTION.call(start_offset - page_size),
87
+ page_size,
88
+ total_size
89
+ )
90
+ }
91
+ )
92
+ end
93
+
94
+ def next_page
95
+ NEXT_COND_FUNCTION.call(
96
+ self,
97
+ lambda { |_| nil },
98
+ lambda { |pager|
99
+ Pager.new(
100
+ NEGATIVE_FUNCTION.call(start_offset + page_size),
101
+ page_size,
102
+ total_size
103
+ )
104
+ }
105
+ )
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,112 @@
1
+ require 'base64'
2
+ require 'sinatra/base'
3
+ require 'jwt'
4
+
5
+ module OpenBEL
6
+ module JWTMiddleware
7
+
8
+ def self.encode(payload, secret)
9
+ ::JWT.encode(payload, secret, 'HS256')
10
+ end
11
+
12
+ def self.decode(token, secret, verify, options)
13
+ ::JWT.decode(token, secret, verify, options)
14
+ end
15
+
16
+ def self.check_cookie(env)
17
+ cookie_hdr = env['HTTP_COOKIE']
18
+ auth_hdr = env['HTTP_AUTHORIZATION']
19
+ if cookie_hdr.nil? and auth_hdr.nil?
20
+ raise 'missing authorization cookie/header'
21
+ end
22
+
23
+ if not cookie_hdr.nil?
24
+ cookies = cookie_hdr.split('; ')
25
+ selected = cookies.select {|x| x.start_with?('jwt=') }
26
+ if selected.size > 0
27
+ tokens = selected[0].split('=')
28
+ if tokens.size > 1
29
+ token = tokens[1]
30
+ end
31
+ end
32
+ if token.nil?
33
+ raise 'missing authorization cookie'
34
+ end
35
+ end
36
+
37
+ if not auth_hdr.nil?
38
+ tokens = auth_hdr.split('Bearer ')
39
+ if tokens.size == 2
40
+ token = tokens[1]
41
+ end
42
+ if token.nil?
43
+ raise 'missing authorization header'
44
+ end
45
+ end
46
+
47
+ secret = OpenBEL::Settings[:auth][:secret]
48
+ secret = Base64.decode64(secret)
49
+ # whether we should verify the token
50
+ verify = true
51
+ # JWT options passed to decode
52
+ options = {}
53
+
54
+ begin
55
+ decoded_token = decode(token, secret, verify, options)
56
+ rescue ::JWT::VerificationError => ve
57
+ raise 'invalid authorization token'
58
+ rescue ::JWT::DecodeError => je
59
+ puts je.inspect
60
+ raise 'malformed authorization token'
61
+ end
62
+ env['jwt.header'] = decoded_token.last unless decoded_token.nil?
63
+ env['jwt.payload'] = decoded_token.first unless decoded_token.nil?
64
+
65
+ exp = env['jwt.payload']['exp']
66
+ now = Time.now.to_i
67
+ if now > exp
68
+ raise 'token expired'
69
+ end
70
+
71
+ env['email'] = env['jwt.payload']['email']
72
+ end
73
+
74
+ class Authentication
75
+ def initialize(app, opts = {})
76
+ @app = app
77
+ @paths = opts.fetch(:paths, [])
78
+ end
79
+
80
+ def call(env)
81
+ check = false
82
+ if @paths.size == 0
83
+ # w/out paths, always check for token
84
+ check = true
85
+ else
86
+ path = env['PATH_INFO']
87
+ # w/ paths, only check for token iff matched
88
+ if @paths.any? {|x| path.start_with?(x)}
89
+ check = true
90
+ end
91
+ end
92
+
93
+ if check
94
+ begin
95
+ JWTMiddleware.check_cookie(env)
96
+ rescue Exception => e
97
+ return _401(e.message)
98
+ end
99
+ @app.call(env)
100
+ end
101
+ end
102
+
103
+ private
104
+
105
+ def _401(message)
106
+ hdrs = {'Content-Type' => 'application/json'}
107
+ msg = {error: message }
108
+ [401, hdrs, [msg.to_json]]
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,52 @@
1
+ module Oat
2
+ module Adapters
3
+ class BasicJson < Oat::Adapter
4
+ def link(rel, opts = {})
5
+ # no-op to maintain interface compatibility with hypermedia adapters
6
+ end
7
+
8
+ def link(rel, opts = {})
9
+ if opts.is_a?(Array)
10
+ data[:_links][rel] = opts.select { |link_obj| link_obj.include?(:href) }
11
+ else
12
+ data[:_links][rel] = opts if opts[:href]
13
+ end
14
+ end
15
+
16
+ def properties(&block)
17
+ data.merge! yield_props(&block)
18
+ end
19
+
20
+ def property(key, value)
21
+ data[key] = value
22
+ end
23
+
24
+ alias_method :meta, :property
25
+
26
+ def rel(rels)
27
+ # no-op to maintain interface compatibility with the Siren adapter
28
+ end
29
+
30
+ def entity(name, obj, serializer_class = nil, context_options = {}, &block)
31
+ entity_serializer = serializer_from_block_or_class(obj, serializer_class, context_options, &block)
32
+ data[entity_name(name)] = entity_serializer ? entity_serializer.to_hash : nil
33
+ end
34
+
35
+ def entities(name, collection, serializer_class = nil, context_options = {}, &block)
36
+ data[entity_name(name)] = collection.map do |obj|
37
+ entity_serializer = serializer_from_block_or_class(obj, serializer_class, context_options, &block)
38
+ entity_serializer ? entity_serializer.to_hash : nil
39
+ end
40
+ end
41
+ alias_method :collection, :entities
42
+
43
+ def entity_name(name)
44
+ # entity name may be an array, but HAL only uses the first
45
+ name.respond_to?(:first) ? name.first : name
46
+ end
47
+
48
+ private :entity_name
49
+
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,141 @@
1
+ require_relative 'base'
2
+
3
+ module OpenBEL
4
+ module Resource
5
+ module Annotations
6
+
7
+ VOCABULARY_RDF = 'http://www.openbel.org/vocabulary/'
8
+
9
+ class AnnotationValueSearchResult < BEL::Resource::AnnotationValue
10
+
11
+ def match_text=(match_text)
12
+ @match_text = match_text
13
+ end
14
+
15
+ def match_text
16
+ @match_text
17
+ end
18
+ end
19
+
20
+ class AnnotationSerializer < BaseSerializer
21
+ # adapter Oat::Adapters::HAL
22
+ schema do
23
+ type :annotation
24
+ property :rdf_uri, item.uri.to_s
25
+ property :name, item.prefLabel
26
+ property :prefix, item.prefix
27
+ property :domain, item.domain
28
+ end
29
+ end
30
+
31
+ class AnnotationResourceSerializer < BaseSerializer
32
+ adapter Oat::Adapters::HAL
33
+ schema do
34
+ type :annotation
35
+ property :annotation, item
36
+ link :self, link_self(item[:prefix])
37
+ end
38
+
39
+ private
40
+
41
+ def link_self(id)
42
+ {
43
+ :type => :annotation,
44
+ :href => "#{base_url}/api/annotations/#{id}"
45
+ }
46
+ end
47
+
48
+ def link_collection
49
+ {
50
+ :type => :annotation_collection,
51
+ :href => "#{base_url}/api/annotations"
52
+ }
53
+ end
54
+ end
55
+
56
+ class AnnotationCollectionSerializer < BaseSerializer
57
+ adapter Oat::Adapters::HAL
58
+ schema do
59
+ type :annotation_collection
60
+ property :annotation_collection, item
61
+ link :self, link_self
62
+ link :start, link_start
63
+ end
64
+
65
+ private
66
+
67
+ def link_self
68
+ {
69
+ :type => :annotation_collection,
70
+ :href => "#{base_url}/api/annotations"
71
+ }
72
+ end
73
+
74
+ def link_start
75
+ {
76
+ :type => :start,
77
+ :href => "#{base_url}/api/annotations/values"
78
+ }
79
+ end
80
+ end
81
+
82
+ class AnnotationValueSerializer < BaseSerializer
83
+ #adapter Oat::Adapters::HAL
84
+ schema do
85
+ type :annotation_value
86
+ property :rdf_uri, item.uri.to_s
87
+ property :type, [item.type].flatten.map(&:to_s)
88
+ property :identifier, item.identifier
89
+ property :name, item.prefLabel
90
+ entity :annotation, item.annotation, AnnotationSerializer
91
+
92
+ # Support inclusion of the matched text when annotation values are filtered by
93
+ # a full-text search.
94
+ if item.match_text
95
+ property :match_text, item.match_text
96
+ end
97
+
98
+ setup(item)
99
+ link :self, link_self
100
+ link :collection, link_annotation
101
+ end
102
+
103
+ private
104
+
105
+ def setup(item)
106
+ @annotation_id, @annotation_value_id = URI(item.uri).path.split('/')[3..-1]
107
+ end
108
+
109
+ def link_self
110
+ {
111
+ :type => :annotation_value,
112
+ :href => "#{base_url}/api/annotations/#{@annotation_id}/values/#{@annotation_value_id}"
113
+ }
114
+ end
115
+
116
+ def link_annotation
117
+ {
118
+ :type => :annotation,
119
+ :href => "#{base_url}/api/annotations/#{@annotation_id}"
120
+ }
121
+ end
122
+ end
123
+
124
+ class AnnotationValueResourceSerializer < BaseSerializer
125
+ adapter Oat::Adapters::HAL
126
+ schema do
127
+ type :annotation_value
128
+ property :annotation_value, item
129
+ end
130
+ end
131
+
132
+ class AnnotationValueCollectionSerializer < BaseSerializer
133
+ adapter Oat::Adapters::HAL
134
+ schema do
135
+ type :annotation_value_collection
136
+ property :annotation_value_collection, item
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end