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.
- checksums.yaml +7 -0
- data/.gemspec +65 -0
- data/CHANGELOG.md +22 -0
- data/INSTALL.md +19 -0
- data/INSTALL_RUBY.md +107 -0
- data/LICENSE +191 -0
- data/README.md +208 -0
- data/app/openbel/api/app.rb +83 -0
- data/app/openbel/api/config.rb +45 -0
- data/app/openbel/api/config.ru +3 -0
- data/app/openbel/api/helpers/pager.rb +109 -0
- data/app/openbel/api/middleware/auth.rb +112 -0
- data/app/openbel/api/resources/adapters/basic_json.rb +52 -0
- data/app/openbel/api/resources/annotation.rb +141 -0
- data/app/openbel/api/resources/base.rb +16 -0
- data/app/openbel/api/resources/completion.rb +89 -0
- data/app/openbel/api/resources/evidence.rb +115 -0
- data/app/openbel/api/resources/evidence_transform.rb +143 -0
- data/app/openbel/api/resources/function.rb +98 -0
- data/app/openbel/api/resources/match_result.rb +79 -0
- data/app/openbel/api/resources/namespace.rb +174 -0
- data/app/openbel/api/routes/annotations.rb +168 -0
- data/app/openbel/api/routes/authenticate.rb +108 -0
- data/app/openbel/api/routes/base.rb +326 -0
- data/app/openbel/api/routes/datasets.rb +519 -0
- data/app/openbel/api/routes/evidence.rb +330 -0
- data/app/openbel/api/routes/expressions.rb +560 -0
- data/app/openbel/api/routes/functions.rb +41 -0
- data/app/openbel/api/routes/namespaces.rb +382 -0
- data/app/openbel/api/routes/root.rb +39 -0
- data/app/openbel/api/schemas.rb +34 -0
- data/app/openbel/api/schemas/annotation_collection.schema.json +20 -0
- data/app/openbel/api/schemas/annotation_resource.schema.json +36 -0
- data/app/openbel/api/schemas/annotation_value_collection.schema.json +21 -0
- data/app/openbel/api/schemas/annotation_value_resource.schema.json +35 -0
- data/app/openbel/api/schemas/completion_collection.schema.json +21 -0
- data/app/openbel/api/schemas/completion_resource.schema.json +146 -0
- data/app/openbel/api/schemas/evidence.schema.json +198 -0
- data/app/openbel/api/schemas/evidence_collection.schema.json +98 -0
- data/app/openbel/api/schemas/evidence_resource.schema.json +29 -0
- data/app/openbel/api/schemas/namespace_value_collection.schema.json +21 -0
- data/app/openbel/api/schemas/namespace_value_resource.schema.json +43 -0
- data/app/openbel/api/util.rb +11 -0
- data/bin/openbel-api +78 -0
- data/bin/openbel-config +46 -0
- data/config/async_evidence.rb +12 -0
- data/config/async_jena.rb +14 -0
- data/config/config.yml +31 -0
- data/config/server_config.rb +184 -0
- data/lib/openbel/api/cache/cache.rb +30 -0
- data/lib/openbel/api/config/config.rb +33 -0
- data/lib/openbel/api/evidence/api.rb +39 -0
- data/lib/openbel/api/evidence/facet_api.rb +18 -0
- data/lib/openbel/api/evidence/facet_filter.rb +83 -0
- data/lib/openbel/api/evidence/mongo.rb +247 -0
- data/lib/openbel/api/evidence/mongo_facet.rb +105 -0
- data/lib/openbel/api/helpers/dependency_graph.rb +52 -0
- data/lib/openbel/api/model/rdf_resource.rb +74 -0
- data/lib/openbel/api/plugin/cache/kyotocabinet.rb +85 -0
- data/lib/openbel/api/plugin/configure_plugins.rb +97 -0
- data/lib/openbel/api/plugin/evidence/evidence.rb +58 -0
- data/lib/openbel/api/plugin/plugin.rb +99 -0
- data/lib/openbel/api/plugin/plugin_manager.rb +20 -0
- data/lib/openbel/api/plugin/plugin_repository.rb +60 -0
- data/lib/openbel/api/storage/cache_proxy.rb +74 -0
- data/lib/openbel/api/storage/triple_storage.rb +43 -0
- metadata +379 -0
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'mongo'
|
2
|
+
require 'multi_json'
|
3
|
+
require_relative 'facet_api'
|
4
|
+
require_relative 'facet_filter'
|
5
|
+
|
6
|
+
module OpenBEL
|
7
|
+
module Evidence
|
8
|
+
|
9
|
+
class EvidenceFacets
|
10
|
+
include FacetAPI
|
11
|
+
include Mongo
|
12
|
+
include FacetFilter
|
13
|
+
|
14
|
+
def initialize(options = {})
|
15
|
+
host = options.delete(:host)
|
16
|
+
port = options.delete(:port)
|
17
|
+
db = options.delete(:database)
|
18
|
+
@db = MongoClient.new(host, port).db(db)
|
19
|
+
@evidence = @db[:evidence]
|
20
|
+
@evidence_facets = @db[:evidence_facets]
|
21
|
+
end
|
22
|
+
|
23
|
+
def create_facets(_id, query_hash)
|
24
|
+
# create and save facets, identified by query
|
25
|
+
facets_doc = _id.merge({
|
26
|
+
:facets => evidence_facets(query_hash)
|
27
|
+
})
|
28
|
+
@evidence_facets.save(facets_doc, :j => true)
|
29
|
+
|
30
|
+
# return facets document
|
31
|
+
facets_doc
|
32
|
+
end
|
33
|
+
|
34
|
+
def find_facets(query_hash, filters)
|
35
|
+
_id = {:_id => to_facets_id(filters)}
|
36
|
+
@evidence_facets.find_one(_id) || create_facets(_id, query_hash)
|
37
|
+
end
|
38
|
+
|
39
|
+
def remove_facets_by_filters(filters = [], options = {})
|
40
|
+
remove_spec =
|
41
|
+
if filters.empty?
|
42
|
+
{ :_id => "" }
|
43
|
+
else
|
44
|
+
{
|
45
|
+
:_id => {
|
46
|
+
:$in => filters.map { |filter|
|
47
|
+
to_regexp(MultiJson.load(filter))
|
48
|
+
}
|
49
|
+
}
|
50
|
+
}
|
51
|
+
end
|
52
|
+
@evidence_facets.remove(remove_spec, :j => true)
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def to_regexp(filter)
|
58
|
+
filter_s = "#{filter['category']}|#{filter['name']}|#{filter['value']}"
|
59
|
+
%r{.*#{Regexp.escape(filter_s)}.*}
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
def to_facets_id(filters)
|
64
|
+
filters.map { |filter|
|
65
|
+
"#{filter['category']}|#{filter['name']}|#{filter['value']}"
|
66
|
+
}.sort.join(',')
|
67
|
+
end
|
68
|
+
|
69
|
+
def evidence_facets(query_hash = nil)
|
70
|
+
pipeline =
|
71
|
+
if query_hash.is_a?(Hash) && !query_hash.empty?
|
72
|
+
[{:'$match' => query_hash}] + AGGREGATION_PIPELINE
|
73
|
+
else
|
74
|
+
AGGREGATION_PIPELINE
|
75
|
+
end
|
76
|
+
@evidence.aggregate(pipeline)
|
77
|
+
end
|
78
|
+
|
79
|
+
AGGREGATION_PIPELINE = [
|
80
|
+
{
|
81
|
+
:'$project' => {
|
82
|
+
:_id => 0,
|
83
|
+
:facets => 1
|
84
|
+
}
|
85
|
+
},
|
86
|
+
{
|
87
|
+
:'$unwind' => '$facets'
|
88
|
+
},
|
89
|
+
{
|
90
|
+
:'$group' => {
|
91
|
+
:_id => '$facets',
|
92
|
+
:count => {
|
93
|
+
:'$sum' => 1
|
94
|
+
}
|
95
|
+
}
|
96
|
+
},
|
97
|
+
{
|
98
|
+
:'$sort' => {
|
99
|
+
:count => -1
|
100
|
+
}
|
101
|
+
}
|
102
|
+
]
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'tsort'
|
2
|
+
|
3
|
+
module OpenBEL
|
4
|
+
module Helpers
|
5
|
+
|
6
|
+
class DependencyGraph
|
7
|
+
include TSort
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@hash = Hash.new { |hash, key| hash[key] = [] }
|
11
|
+
end
|
12
|
+
|
13
|
+
def [](key)
|
14
|
+
@hash[key]
|
15
|
+
end
|
16
|
+
|
17
|
+
def add_dependency(first, *dependency_requirements)
|
18
|
+
@hash[first] ||= []
|
19
|
+
(dependency_requirements || []).flatten.each do |dep|
|
20
|
+
_add_dependency(first, dep)
|
21
|
+
end
|
22
|
+
@hash[first]
|
23
|
+
end
|
24
|
+
|
25
|
+
def delete(key)
|
26
|
+
@hash.delete(key)
|
27
|
+
end
|
28
|
+
|
29
|
+
def each_key(&block)
|
30
|
+
@hash.each_key(&block)
|
31
|
+
end
|
32
|
+
|
33
|
+
def tsort_each_child(key, &block)
|
34
|
+
@hash[key].each(&block)
|
35
|
+
end
|
36
|
+
|
37
|
+
def tsort_each_node(&block)
|
38
|
+
@hash.each_key(&block)
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def _add_dependency(key1, key2)
|
44
|
+
@hash[key1] << key2
|
45
|
+
@hash[key2] = []
|
46
|
+
key2
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
# vim: ts=2 sts=2 sw=2 expandtab
|
52
|
+
# encoding: utf-8
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module OpenBEL
|
2
|
+
module Model
|
3
|
+
|
4
|
+
VOCABULARY_RDF = 'http://www.openbel.org/vocabulary/'
|
5
|
+
|
6
|
+
def self.included base
|
7
|
+
base.extend ClassMethods
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
def from(statements)
|
12
|
+
obj = self.new
|
13
|
+
statements.each do |sub, pred, obj_val|
|
14
|
+
index = pred.rindex('#') || pred.rindex('/')
|
15
|
+
if index
|
16
|
+
attribute = pred[index+1..-1]
|
17
|
+
|
18
|
+
# handle type statement
|
19
|
+
if attribute == 'type'
|
20
|
+
# ... the URI
|
21
|
+
if obj.respond_to?(:uri=)
|
22
|
+
obj.send(:uri=, sub)
|
23
|
+
end
|
24
|
+
# ... the BEL vocabulary type
|
25
|
+
if obj_val.start_with?(VOCABULARY_RDF) and obj.respond_to?(:type=)
|
26
|
+
obj.send(:type=, obj_val)
|
27
|
+
next
|
28
|
+
end
|
29
|
+
end
|
30
|
+
if obj.respond_to? :"#{attribute}="
|
31
|
+
obj.send(:"#{attribute}=", obj_val)
|
32
|
+
end
|
33
|
+
else
|
34
|
+
$stderr.puts "cannot parse local name for #{pred}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
(obj.respond_to? :uri and obj.uri) ? obj : nil
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class RdfResource
|
42
|
+
include OpenBEL::Model
|
43
|
+
|
44
|
+
def initialize(attr_values = {})
|
45
|
+
attr_values.each { |k, v|
|
46
|
+
instance_variable_set(:"@#{k}", v)
|
47
|
+
}
|
48
|
+
end
|
49
|
+
|
50
|
+
attr_accessor :uri
|
51
|
+
|
52
|
+
def ==(other)
|
53
|
+
return false if other == nil
|
54
|
+
@uri == other.uri
|
55
|
+
end
|
56
|
+
|
57
|
+
def hash
|
58
|
+
@uri.hash
|
59
|
+
end
|
60
|
+
|
61
|
+
def to_hash
|
62
|
+
instance_variables.inject({}) { |res, attr|
|
63
|
+
res.merge({attr[1..-1] => instance_variable_get(attr)})
|
64
|
+
}
|
65
|
+
end
|
66
|
+
|
67
|
+
def to_s
|
68
|
+
@uri
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
# vim: ts=2 sts=2 sw=2
|
74
|
+
# encoding: utf-8
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'pp'
|
2
|
+
require_relative '../plugin'
|
3
|
+
|
4
|
+
module OpenBEL
|
5
|
+
module Plugin
|
6
|
+
|
7
|
+
class CacheKyotoCabinet
|
8
|
+
include OpenBEL::Plugin
|
9
|
+
|
10
|
+
ID = 'kyotocabinet'
|
11
|
+
NAME = 'KyotoCabinet Cache'
|
12
|
+
DESC = 'Cache implementation using KyotoCabinet over FFI.'
|
13
|
+
MEMR_TYPES = [ :"memory-hash" ]
|
14
|
+
FILE_TYPES = [ :"file-hash" ]
|
15
|
+
TYPE_OPTION_VALUES = [ MEMR_TYPES, FILE_TYPES ].flatten
|
16
|
+
MODE_OPTION_VALUES = [ :reader, :writer, :create ]
|
17
|
+
|
18
|
+
CREATE_MUTEX = Mutex.new
|
19
|
+
|
20
|
+
def id
|
21
|
+
ID
|
22
|
+
end
|
23
|
+
|
24
|
+
def name
|
25
|
+
NAME
|
26
|
+
end
|
27
|
+
|
28
|
+
def description
|
29
|
+
DESC
|
30
|
+
end
|
31
|
+
|
32
|
+
def type
|
33
|
+
:cache
|
34
|
+
end
|
35
|
+
|
36
|
+
def on_load
|
37
|
+
require 'kyotocabinet_ffi'
|
38
|
+
end
|
39
|
+
|
40
|
+
def validate(extensions = {}, options = {})
|
41
|
+
type = options.delete(:type)
|
42
|
+
if not type
|
43
|
+
return ValidationError.new(self, :type, "Option is missing. Options are one of [#{TYPE_OPTION_VALUES.join(', ')}].")
|
44
|
+
end
|
45
|
+
type = type.to_sym
|
46
|
+
if not TYPE_OPTION_VALUES.include?(type)
|
47
|
+
return ValidationError.new(self, :type, "Value not supported. Options are one of [#{TYPE_OPTION_VALUES.join(', ')}].")
|
48
|
+
end
|
49
|
+
|
50
|
+
mode = options.delete(:mode)
|
51
|
+
if not mode
|
52
|
+
return ValidationError.new(self, :mode, "Option is missing. Options are one of [#{MODE_OPTION_VALUES.join(', ')}].")
|
53
|
+
end
|
54
|
+
mode = mode.map { |v| v.to_s.to_sym }
|
55
|
+
|
56
|
+
validation_successful
|
57
|
+
end
|
58
|
+
|
59
|
+
def configure(extensions = {}, options = {})
|
60
|
+
@options = options
|
61
|
+
end
|
62
|
+
|
63
|
+
def create_instance
|
64
|
+
CREATE_MUTEX.lock
|
65
|
+
begin
|
66
|
+
unless @instance
|
67
|
+
type = @options[:type].to_sym
|
68
|
+
mode = @options[:mode].map { |v| v.to_s.to_sym }
|
69
|
+
|
70
|
+
@instance = case type
|
71
|
+
when :"memory-hash"
|
72
|
+
KyotoCabinet::Db::MemoryHash.new mode
|
73
|
+
when :"file-hash"
|
74
|
+
KyotoCabinet::Db::PolymorphicDb::tmp_filedb(KyotoCabinet::FILE_HASH)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
ensure
|
78
|
+
CREATE_MUTEX.unlock
|
79
|
+
end
|
80
|
+
|
81
|
+
@instance
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require_relative '../helpers/dependency_graph'
|
2
|
+
|
3
|
+
module OpenBEL
|
4
|
+
module ConfigurePlugins
|
5
|
+
|
6
|
+
def check_configuration(plugins, config)
|
7
|
+
sorted_plugin_config_ids = build_dependency_graph(config)
|
8
|
+
|
9
|
+
all_errors = []
|
10
|
+
valid_plugins = {}
|
11
|
+
sorted_plugin_config_ids.each do |plugin_config_id|
|
12
|
+
# validate plugin configuration...
|
13
|
+
plugin_config = config[plugin_config_id.to_s]
|
14
|
+
|
15
|
+
# ...check plugin defines required properties
|
16
|
+
['type', 'plugin'].each do |p|
|
17
|
+
errors << %Q{The "#{p}" property (defined in "#{plugin_config_id}") does not define a type.} unless plugin_config.has_key?(p)
|
18
|
+
next
|
19
|
+
end
|
20
|
+
type = plugin_config['type']
|
21
|
+
plugin_id = plugin_config['plugin']
|
22
|
+
|
23
|
+
# ...check if any plugin(s) are loaded for specified type
|
24
|
+
if plugins.none? { |p| p.type.to_s.to_sym == type.to_s.to_sym }
|
25
|
+
errors << %Q{The "#{type}" type (defined in "#{plugin_config_id}") does not have any registered plugins.}
|
26
|
+
end
|
27
|
+
|
28
|
+
# ...check if plugin exists
|
29
|
+
plugin = plugins.find { |p| p.id == plugin_id }
|
30
|
+
unless plugin
|
31
|
+
errors << %Q{The "#{plugin_id}" plugin (defined in "#{plugin_config_id}") does not have any registered plugins.}
|
32
|
+
end
|
33
|
+
|
34
|
+
# ...check plugin extensions
|
35
|
+
extensions = plugin_config['extensions'] || {}
|
36
|
+
extensions.values.find_all { |ext|
|
37
|
+
not valid_plugins.has_key? ext.to_s
|
38
|
+
}.each do |ext|
|
39
|
+
all_errors << %Q{The "#{ext}" extension (defined in "#{plugin_config_id}") is not valid.}
|
40
|
+
end
|
41
|
+
|
42
|
+
# ...prepare extensions/options for plugin validation
|
43
|
+
extensions = Hash[extensions.map { |ext_type, ext_id|
|
44
|
+
[ext_type.to_s.to_sym, valid_plugins[ext_id.to_s]]
|
45
|
+
}]
|
46
|
+
options = Hash[(plugin_config['options'] || {}).map { |k, v|
|
47
|
+
[k.to_s.to_sym, v]
|
48
|
+
}]
|
49
|
+
|
50
|
+
# ...call plugin-specific validation
|
51
|
+
plugin_errors = [plugin.validate(extensions.dup, options.dup)].flatten.map(&:to_s)
|
52
|
+
if plugin_errors.empty?
|
53
|
+
valid_plugins[plugin_config_id.to_s] = plugin
|
54
|
+
else
|
55
|
+
all_errors.concat(plugin_errors)
|
56
|
+
end
|
57
|
+
# TODO Log successful plugin check if verbose.
|
58
|
+
end
|
59
|
+
all_errors
|
60
|
+
end
|
61
|
+
|
62
|
+
def configure_plugins(plugins, config)
|
63
|
+
sorted_plugin_config_ids = build_dependency_graph(config)
|
64
|
+
sorted_plugin_config_ids.inject({}) { |plugins_by_id, plugin_config_id|
|
65
|
+
plugin_config = config[plugin_config_id.to_s]
|
66
|
+
|
67
|
+
plugin_id = plugin_config['plugin']
|
68
|
+
|
69
|
+
plugin = plugins.find { |p| p.id == plugin_id }
|
70
|
+
extensions = Hash[(plugin_config['extensions'] || {}).map { |type, id|
|
71
|
+
[type.to_s.to_sym, plugins_by_id[id.to_s]]
|
72
|
+
}]
|
73
|
+
options = Hash[(plugin_config['options'] || {}).map { |k, v|
|
74
|
+
[k.to_s.to_sym, v]
|
75
|
+
}]
|
76
|
+
|
77
|
+
plugin.configure(extensions.dup, options.dup)
|
78
|
+
plugin.on_load
|
79
|
+
|
80
|
+
plugins_by_id[plugin_config_id.to_s] = plugin
|
81
|
+
plugins_by_id
|
82
|
+
}
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
def build_dependency_graph(config)
|
88
|
+
dependency_graph = Helpers::DependencyGraph.new
|
89
|
+
config.keys.each do |plugin_key|
|
90
|
+
block = config[plugin_key]
|
91
|
+
dependencies = (block['extensions'] || {}).each_value.to_a.map { |v| v.to_s.to_sym }
|
92
|
+
dependency_graph.add_dependency(plugin_key.to_s, *dependencies)
|
93
|
+
end
|
94
|
+
dependency_graph.tsort
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require_relative '../plugin'
|
2
|
+
|
3
|
+
module OpenBEL
|
4
|
+
module Plugin
|
5
|
+
|
6
|
+
class Evidence
|
7
|
+
include OpenBEL::Plugin
|
8
|
+
|
9
|
+
ID = 'evidence'
|
10
|
+
NAME = 'OpenBEL Evidence API'
|
11
|
+
DESC = 'API for accesing OpenBEL Evidence.'
|
12
|
+
|
13
|
+
def id
|
14
|
+
ID
|
15
|
+
end
|
16
|
+
|
17
|
+
def name
|
18
|
+
NAME
|
19
|
+
end
|
20
|
+
|
21
|
+
def description
|
22
|
+
DESC
|
23
|
+
end
|
24
|
+
|
25
|
+
def type
|
26
|
+
:evidence
|
27
|
+
end
|
28
|
+
|
29
|
+
def required_extensions
|
30
|
+
[]
|
31
|
+
end
|
32
|
+
|
33
|
+
def optional_extensions
|
34
|
+
[]
|
35
|
+
end
|
36
|
+
|
37
|
+
def on_load
|
38
|
+
require_relative '../../evidence/mongo'
|
39
|
+
end
|
40
|
+
|
41
|
+
def validate(extensions = {}, options = {})
|
42
|
+
[:host, :port, :database].map { |setting|
|
43
|
+
unless options[setting]
|
44
|
+
ValidationError.new(self, :storage, "The #{setting} setting is missing.")
|
45
|
+
end
|
46
|
+
}.compact!
|
47
|
+
end
|
48
|
+
|
49
|
+
def configure(extensions = {}, options = {})
|
50
|
+
@options = options
|
51
|
+
end
|
52
|
+
|
53
|
+
def create_instance
|
54
|
+
OpenBEL::Evidence::Evidence.new(@options)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|