openbel-api 0.4.0-java

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