Duplicated structures (all structures/activities used for model building, please make sure, that the results were obtained from independent experiments):
" + duplicate_warnings unless duplicate_warnings.empty?
+
+ @dataset.metadata[OT.Warnings] = warnings
+
+ @dataset
+
+ end
+
+ def add(smiles, act, row)
+ compound = Compound.from_smiles(smiles)
+ if compound.nil? or compound.inchi.nil? or compound.inchi == ""
+ @smiles_errors << "Row #{row}: " + [smiles,act].join(", ")
+ return false
+ end
+ unless numeric?(act) or classification?(act)
+ @activity_errors << "Row #{row}: " + [smiles,act].join(", ")
+ return false
+ end
+ @duplicates[compound.inchi] = [] unless @duplicates[compound.inchi]
+ @duplicates[compound.inchi] << "Row #{row}: " + [smiles, act].join(", ")
+ @type = "regression" unless classification?(act)
+ # TODO: set OT.NumericalFeature, ...
+ @nr_compounds += 1
+ @data << [ compound.uri, act , row ]
+ end
+
+ def numeric?(object)
+ true if Float(object) rescue false
+ end
+
+ def classification?(object)
+ !object.to_s.strip.match(TRUE_REGEXP).nil? or !object.to_s.strip.match(FALSE_REGEXP).nil?
+ end
+
+ end
+ end
+end
diff --git a/lib/serializer.rb b/lib/serializer.rb
new file mode 100644
index 0000000..3def252
--- /dev/null
+++ b/lib/serializer.rb
@@ -0,0 +1,297 @@
+require 'spreadsheet'
+require 'yajl'
+
+module OpenTox
+
+ module Serializer
+
+ # modelled according to to http://n2.talis.com/wiki/RDF_JSON_Specification
+ class Owl
+
+ attr_accessor :object
+
+ def initialize
+
+ @object = {
+ # this should come from opntox.owl
+ OT.Compound => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
+ OT.Feature => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
+ OT.NominalFeature => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
+ OT.NumericFeature => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
+ OT.StringFeature => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
+ OT.Dataset => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
+ OT.DataEntry => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
+ OT.FeatureValue => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
+ OT.Algorithm => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
+ OT.Parameter => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
+
+ OT.compound => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
+ OT.feature => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
+ OT.dataEntry => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
+ OT.acceptValue => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
+ OT.values => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
+ #XSD.anyUri => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
+ OT.algorithm => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
+ OT.parameters => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
+
+ DC.title => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ DC.identifier => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ DC.contributor => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ DC.creator => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.isA => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+
+ OT.hasSource => { RDF["type"] => [{ "type" => "uri", "value" => OWL.DatatypeProperty }] } ,
+ OT.value => { RDF["type"] => [{ "type" => "uri", "value" => OWL.DatatypeProperty }] } ,
+ OT.paramScope => { RDF["type"] => [{ "type" => "uri", "value" => OWL.DatatypeProperty }] } ,
+ OT.paramValue => { RDF["type"] => [{ "type" => "uri", "value" => OWL.DatatypeProperty }] } ,
+
+ #Untyped Individual: http://localhost/algorithm
+ }
+
+ @data_entries = {}
+ @values_id = 0
+ @parameter_id = 0
+
+ @classes = Set.new
+ @object_properties = Set.new
+ @annotation_properties = Set.new
+ @datatype_properties = Set.new
+
+ @objects = Set.new
+ end
+
+ def add_compound(uri)
+ #@classes << OT.Compound unless @classes.include? OT.Compound
+ @object[uri] = { RDF["type"] => [{ "type" => "uri", "value" => OT.Compound }] }
+ end
+
+ def add_feature(uri,metadata)
+ #@classes << OT.Feature unless @classes.include? OT.Feature
+ #@classes << OT.NominalFeature unless @classes.include? OT.NominalFeature
+ #@classes << OT.NumericFeature unless @classes.include? OT.NumericFeature
+ #@classes << OT.StringFeature unless @classes.include? OT.StringFeature
+ @object[uri] = { RDF["type"] => [{ "type" => "uri", "value" => OT.Feature }] }
+ add_metadata uri, metadata
+ end
+
+ def add_dataset(dataset)
+
+ @dataset = dataset.uri
+
+ @object[dataset.uri] = { RDF["type"] => [{ "type" => "uri", "value" => OT.Dataset }] }
+
+ add_metadata dataset.uri, dataset.metadata
+
+ dataset.compounds.each { |compound| add_compound compound }
+
+ dataset.features.each { |feature,metadata| add_feature feature,metadata }
+
+ dataset.data_entries.each do |compound,entry|
+ entry.each do |feature,values|
+ values.each { |value| add_data_entry compound,feature,value }
+ end
+ end
+
+ end
+
+ def add_algorithm(uri,metadata,parameters)
+ @object[uri] = { RDF["type"] => [{ "type" => "uri", "value" => OT.Algorithm }] }
+ add_metadata uri, metadata
+ add_parameters uri, parameters
+ #metadata.each { |u,v| @object[uri][u] = [{"type" => type(v), "value" => v }] }
+ end
+
+ def add_model(uri,metadata)
+ end
+
+ def add_metadata(uri,metadata)
+ #@object[uri] = { RDF["type"] => [{ "type" => "uri", "value" => OT[type] }] }
+ metadata.each do |u,v|
+ @object[uri][u] = [{"type" => type(v), "value" => v }]
+ end
+ end
+
+ def add_parameters(uri,parameters)
+ #@object[uri] = { RDF["type"] => [{ "type" => "uri", "value" => OT[type] }] }
+ @object[uri][OT.parameters] = [] unless @object[uri][OT.parameters]
+ parameters.each do |p|
+ parameter = "_:parameter#{@parameter_id}"
+ @parameter_id += 1
+ @object[uri][OT.parameters] << {"type" => "bnode", "value" => parameter}
+ @object[parameter] = { RDF["type"] => [{ "type" => "uri", "value" => OT.Parameter }] }
+ add_metadata parameter, p
+ end
+ end
+
+ def add_data_entry(compound,feature,value)
+ add_compound(compound) unless @object[compound]
+ add_feature(feature,{}) unless @object[feature]
+ unless data_entry = @data_entries[compound]
+ data_entry = "_:dataentry#{@data_entries.size}"
+ @data_entries[compound] = data_entry
+ @object[@dataset][OT.dataEntry] = [] unless @object[@dataset][OT.dataEntry]
+ @object[@dataset][OT.dataEntry] << {"type" => "bnode", "value" => data_entry}
+ @object[data_entry] = {
+ RDF["type"] => [{ "type" => "uri", "value" => OT.DataEntry }],
+ OT.compound => [{ "type" => "uri", "value" => compound }],
+ OT.values => [],
+ }
+ end
+ values = "_:values#{@values_id}"
+ @values_id += 1
+ @object[data_entry][OT.values] << {"type" => "bnode", "value" => values}
+ case type(value)
+ when "uri"
+ v = [{ "type" => "uri", "value" => value}]
+ when "literal"
+ v = [{ "type" => "literal", "value" => value, "datatype" => datatype(value) }]
+ else
+ raise "Illegal type #{type(value)} for #{value}."
+ end
+ @object[values] = {
+ RDF["type"] => [{ "type" => "uri", "value" => OT.FeatureValue }],
+ OT.feature => [{ "type" => "uri", "value" => feature }],
+ OT.value => v
+ }
+ @object[feature][RDF["type"]] << { "type" => "uri", "value" => featuretype(value) }
+ end
+
+ # Serializers
+
+ def ntriples
+
+ #rdf_types
+ @triples = Set.new
+ @object.each do |s,entry|
+ s = url(s) if type(s) == "uri"
+ entry.each do |p,objects|
+ p = url(p)
+ objects.each do |o|
+ case o["type"]
+ when "uri"
+ o = url(o["value"])
+ when "literal"
+ o = literal(o["value"],datatype(o["value"]))
+ when "bnode"
+ o = o["value"]
+ end
+ @triples << [s,p,o]
+ end
+ end
+ end
+ @triples.sort.collect{ |s| s.join(' ').concat(" .") }.join("\n")+"\n"
+ end
+
+ def rdfxml
+ Tempfile.open("owl-serializer"){|f| f.write(ntriples); @path = f.path}
+ `rapper -i ntriples -o rdfxml #{@path}`
+ end
+
+ def json
+ #rdf_types
+ Yajl::Encoder.encode(@object)
+ end
+
+ # Helpers for type detection
+ private
+
+ def datatype(value)
+ if value.is_a? TrueClass or value.is_a? FalseClass
+ XSD.boolean
+ elsif value.is_a? Float
+ XSD.float
+ else
+ XSD.string
+ end
+ end
+
+ def featuretype(value)
+ if value.is_a? TrueClass or value.is_a? FalseClass
+ datatype = OT.NominalFeature
+ elsif value.is_a? Float
+ datatype = OT.NumericFeature
+ else
+ datatype = OT.StringFeature
+ end
+ end
+
+ def type(value)
+ begin
+ uri = URI.parse(value)
+ if uri.class == URI::HTTP or uri.class == URI::HTTPS
+ "uri"
+ elsif value.match(/^_/)
+ "bnode"
+ else
+ "literal"
+ end
+ rescue
+ "literal"
+ end
+ end
+
+ def literal(value,type)
+ # concat and << are faster string concatination operators than +
+ '"'.concat(value.to_s).concat('"^^<').concat(type).concat('>')
+ end
+
+ def url(uri)
+ # concat and << are faster string concatination operators than +
+ '<'.concat(uri).concat('>')
+ end
+
+ def rdf_types
+ @classes.each { |c| @object[c] = { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } }
+ @object_properties.each { |p| @object[p] = { RDF["type"] => [{ "type" => "uri", "value" => OWL['ObjectProperty'] }] } }
+ @annotation_properties.each { |a| @object[a] = { RDF["type"] => [{ "type" => "uri", "value" => OWL['AnnotationProperty'] }] } }
+ @datatype_properties.each { |d| @object[d] = { RDF["type"] => [{ "type" => "uri", "value" => OWL['DatatypeProperty'] }] } }
+ end
+
+ end
+
+ class Spreadsheets # to avoid nameclash with Spreadsheet gem
+
+ def initialize(dataset)
+ @rows = []
+ @rows << ["SMILES"]
+ features = dataset.features.keys
+ @rows.first << features
+ @rows.first.flatten!
+ dataset.data_entries.each do |compound,entries|
+ smiles = Compound.new(compound).smiles
+ row = Array.new(@rows.first.size)
+ row[0] = smiles
+ entries.each do |feature, values|
+ i = features.index(feature)+1
+ values.each do |value|
+ row[i] = value #TODO overwrites duplicated values
+ end
+ end
+ @rows << row
+ end
+ end
+
+ def csv
+ @rows.collect{|r| r.join(", ")}.join("\n")
+ end
+
+ def excel
+ Spreadsheet.client_encoding = 'UTF-8'
+ book = Spreadsheet::Workbook.new
+ sheet = book.create_worksheet(:name => '')
+ sheet.column(0).width = 100
+ i = 0
+ @rows.each do |row|
+ row.each do |c|
+ sheet.row(i).push c
+ end
+ i+=1
+ end
+ book
+ end
+
+ end
+
+
+ end
+end
diff --git a/lib/task.rb b/lib/task.rb
index 1ab3893..50f0347 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -16,7 +16,7 @@ module OpenTox
# create is private now, use OpenTox::Task.as_task
def self.create( params )
- task_uri = RestClientWrapper.post(@@config[:services]["opentox-task"], params, nil, false).to_s
+ task_uri = RestClientWrapper.post(CONFIG[:services]["opentox-task"], params, nil, false).to_s
Task.find(task_uri.chomp)
end
@@ -36,7 +36,7 @@ module OpenTox
def reload( accept_header=nil )
unless accept_header
- if (@@config[:yaml_hosts].include?(URI.parse(uri).host))
+ if (CONFIG[:yaml_hosts].include?(URI.parse(uri).host))
accept_header = "application/x-yaml"
else
accept_header = 'application/rdf+xml'
@@ -99,7 +99,7 @@ module OpenTox
# waits for a task, unless time exceeds or state is no longer running
def wait_for_completion(dur=0.3)
- if (@uri.match(@@config[:services]["opentox-task"]))
+ if (@uri.match(CONFIG[:services]["opentox-task"]))
due_to_time = (@due_to_time.is_a?(Time) ? @due_to_time : Time.parse(@due_to_time))
running_time = due_to_time - (@date.is_a?(Time) ? @date : Time.parse(@date))
else
@@ -144,7 +144,7 @@ module OpenTox
#return yield nil
params = {:title=>title, :creator=>creator, :max_duration=>max_duration, :description=>description }
- task = OpenTox::Task.create(params)
+ task = ::OpenTox::Task.create(params)
task_pid = Spork.spork(:logger => LOGGER) do
LOGGER.debug "Task #{task.uri} started #{Time.now}"
$self_task = task
diff --git a/lib/validation.rb b/lib/validation.rb
index 89a2a0c..340332a 100644
--- a/lib/validation.rb
+++ b/lib/validation.rb
@@ -4,11 +4,11 @@ module OpenTox
attr_accessor :uri
def initialize(params)
- @uri = OpenTox::RestClientWrapper.post(File.join(@@config[:services]["opentox-validation"],"/crossvalidation"),params,nil,false)
+ @uri = OpenTox::RestClientWrapper.post(File.join(CONFIG[:services]["opentox-validation"],"/crossvalidation"),params,nil,false)
end
def self.crossvalidation(params)
- params[:uri] = File.join(@@config[:services]['opentox-validation'], "crossvalidation")
+ params[:uri] = File.join(CONFIG[:services]['opentox-validation'], "crossvalidation")
params[:num_folds] = 10 unless params[:num_folds]
params[:random_seed] = 2 unless params[:random_seed]
params[:stratified] = false unless params[:stratified]
--
cgit v1.2.3
From b93002b4ea50ff7e357da08abd10577347ce2d5f Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Thu, 11 Nov 2010 09:31:27 +0100
Subject: first steps towards version 2.0, yard documentation started, passes
compound, dataset, feature, algorithm, fminer tests
---
lib/algorithm.rb | 127 +++++++----
lib/compound.rb | 105 +++++----
lib/dataset.rb | 482 ++++++++++++---------------------------
lib/environment.rb | 29 +++
lib/feature.rb | 4 +-
lib/model.rb | 485 +++++++++++++++++++++++++++++++---------
lib/opentox-ruby-api-wrapper.rb | 2 +-
lib/opentox.rb | 106 ++++-----
lib/overwrite.rb | 22 ++
lib/parser.rb | 208 +++++++++++------
lib/rest_client_wrapper.rb | 6 +-
lib/serializer.rb | 69 +++---
lib/task.rb | 6 +-
lib/utils.rb | 50 -----
14 files changed, 940 insertions(+), 761 deletions(-)
delete mode 100644 lib/utils.rb
(limited to 'lib')
diff --git a/lib/algorithm.rb b/lib/algorithm.rb
index e1d369a..711f63b 100644
--- a/lib/algorithm.rb
+++ b/lib/algorithm.rb
@@ -1,77 +1,122 @@
module OpenTox
+ # Wrapper for OpenTox Algorithms
module Algorithm
- include OtObject
+ include OpenTox
+ # Execute algorithm with parameters, please consult the OpenTox API and the webservice documentation for acceptable parameters
+ def run(params=nil)
+ RestClientWrapper.post(@uri, params)
+ end
+
+ # Get OWL-DL representation in RDF/XML format
+ # @return [application/rdf+xml] RDF/XML representation
+ def to_rdfxml
+ s = Serializer::Owl.new
+ s.add_algorithm(@uri,@metadata)
+ s.to_rdfxml
+ end
+
+ # Generic Algorithm class, should work with all OpenTox webservices
class Generic
include Algorithm
- #include OtObject
- protected
-# def initialize(owl)
-# @title = owl.get("title")
-# @date = owl.get("date")
-# @uri = owl.uri
-# end
-
end
- class Fminer < Generic
+ module Fminer
+ include Algorithm
- def self.create_feature_dataset(params)
- LOGGER.debug File.basename(__FILE__) + ": creating feature dataset"
- resource = RestClient::Resource.new(params[:feature_generation_uri])
- resource.post :dataset_uri => params[:dataset_uri], :feature_uri => params[:feature_uri]
+ class BBRC
+ include Fminer
+ # Initialize bbrc algorithm
+ def initialize
+ super File.join(CONFIG[:services]["opentox-algorithm"], "fminer/bbrc")
+ load_metadata
+ end
+ end
+
+ class LAST
+ include Fminer
+ # Initialize last algorithm
+ def initialize
+ super File.join(CONFIG[:services]["opentox-algorithm"], "fminer/last")
+ load_metadata
+ end
end
- def self.uri
- File.join(CONFIG[:services]["opentox-algorithm"], "fminer")
- end
end
- class Lazar
-
- def self.create_model(params)
- LOGGER.debug params
- LOGGER.debug File.basename(__FILE__) + ": creating model"
- LOGGER.debug File.join(CONFIG[:services]["opentox-algorithm"], "lazar")
- resource = RestClient::Resource.new(File.join(CONFIG[:services]["opentox-algorithm"], "lazar"), :content_type => "application/x-yaml")
- @uri = resource.post(:dataset_uri => params[:dataset_uri], :prediction_feature => params[:prediction_feature], :feature_generation_uri => File.join(CONFIG[:services]["opentox-algorithm"], "fminer")).body.chomp
- end
+ # Create lazar prediction model
+ class Lazar
+ include Algorithm
+ # Initialize lazar algorithm
+ def initialize
+ super File.join(CONFIG[:services]["opentox-algorithm"], "lazar")
+ load_metadata
+ end
+ end
- def self.uri
- File.join(CONFIG[:services]["opentox-algorithm"], "lazar")
- end
+ # Utility methods without dedicated webservices
- end
+ module Similarity
+ include Algorithm
- class Similarity
- def self.weighted_tanimoto(fp_a,fp_b,p)
- common_features = fp_a & fp_b
- all_features = (fp_a + fp_b).uniq
+ # Tanimoto similarity
+ #
+ # @param [Array] features_a Features of first compound
+ # @param [Array] features_b Features of second compound
+ # @param [optional, Hash] weights Weights for all features
+ # @return [Float] (Wighted) tanimoto similarity
+ def self.tanimoto(features_a,features_b,weights=nil)
+ common_features = features_a & features_b
+ all_features = (features_a + features_b).uniq
common_p_sum = 0.0
if common_features.size > 0
- common_features.each{|f| common_p_sum += OpenTox::Utils.gauss(p[f])}
- all_p_sum = 0.0
- all_features.each{|f| all_p_sum += OpenTox::Utils.gauss(p[f])}
- common_p_sum/all_p_sum
+ if weights
+ common_features.each{|f| common_p_sum += Algorithm.gauss(weights[f])}
+ all_p_sum = 0.0
+ all_features.each{|f| all_p_sum += Algorithm.gauss(weights[f])}
+ common_p_sum/all_p_sum
+ else
+ common_features.to_f/all_features
+ end
else
0.0
end
end
- def self.euclidean(prop_a,prop_b)
+
+ # Euclidean similarity
+ def self.euclidean(prop_a,prop_b,weights=nil)
common_properties = prop_a.keys & prop_b.keys
if common_properties.size > 1
dist_sum = 0
common_properties.each do |p|
- dist_sum += (prop_a[p] - prop_b[p])**2
+ if weights
+ dist_sum += ( (prop_a[p] - prop_b[p]) * Algorithm.gauss(weights[p]) )**2
+ else
+ dist_sum += (prop_a[p] - prop_b[p])**2
+ end
end
1/(1+Math.sqrt(dist_sum))
else
- nil
+ 0.0
end
end
end
+
+ # Gauss kernel
+ def self.gauss(sim, sigma = 0.3)
+ x = 1.0 - sim
+ Math.exp(-(x*x)/(2*sigma*sigma))
+ end
+
+ # Median of an array
+ def self.median(array)
+ return nil if array.empty?
+ array.sort!
+ m_pos = array.size / 2
+ return array.size % 2 == 1 ? array[m_pos] : (array[m_pos-1] + array[m_pos])/2
+ end
end
end
diff --git a/lib/compound.rb b/lib/compound.rb
index 699e4c1..6834860 100644
--- a/lib/compound.rb
+++ b/lib/compound.rb
@@ -4,41 +4,15 @@
module OpenTox
# Ruby wrapper for OpenTox Compound Webservices (http://opentox.org/dev/apis/api-1.2/structure).
- #
- # Examples:
- # require "opentox-ruby-api-wrapper"
- #
- # # Creating compounds
- #
- # # from smiles string
- # compound = OpenTox::Compound.from_smiles("c1ccccc1")
- # # from name
- # compound = OpenTox::Compound.from_name("Benzene")
- # # from uri
- # compound = OpenTox::Compound.new("http://webservices.in-silico.ch/compound/InChI=1S/C6H6/c1-2-4-6-5-3-1/h1-6H"")
- #
- # # Getting compound representations
- #
- # # get InChI
- # inchi = compound.inchi
- # # get all compound names
- # names = compound.names
- # # get png image
- # image = compound.png
- # # get uri
- # uri = compound.uri
- #
- # # SMARTS matching
- #
- # # match a smarts string
- # compound.match?("cN") # returns false
- # # match an array of smarts strings
- # compound.match(['cc','cN']) # returns ['cc']
class Compound
attr_accessor :inchi, :uri
# Create compound with optional uri
+ # @example
+ # compound = OpenTox::Compound.new("http://webservices.in-silico.ch/compound/InChI=1S/C6H6/c1-2-4-6-5-3-1/h1-6H"")
+ # @param [optional, String] uri Compound URI
+ # @return [OpenTox::Compound] Compound
def initialize(uri=nil)
@uri = uri
case @uri
@@ -50,6 +24,10 @@ module OpenTox
end
# Create a compound from smiles string
+ # @example
+ # compound = OpenTox::Compound.from_smiles("c1ccccc1")
+ # @param [String] smiles Smiles string
+ # @return [OpenTox::Compound] Compound
def self.from_smiles(smiles)
c = Compound.new
c.inchi = Compound.smiles2inchi(smiles)
@@ -58,6 +36,8 @@ module OpenTox
end
# Create a compound from inchi string
+ # @param [String] smiles InChI string
+ # @return [OpenTox::Compound] Compound
def self.from_inchi(inchi)
c = Compound.new
c.inchi = inchi
@@ -66,6 +46,8 @@ module OpenTox
end
# Create a compound from sdf string
+ # @param [String] smiles SDF string
+ # @return [OpenTox::Compound] Compound
def self.from_sdf(sdf)
c = Compound.new
c.inchi = Compound.sdf2inchi(sdf)
@@ -73,7 +55,11 @@ module OpenTox
c
end
- # Create a compound from name (name can be also an InChI/InChiKey, CAS number, etc)
+ # Create a compound from name. Relies on an external service for name lookups.
+ # @example
+ # compound = OpenTox::Compound.from_name("Benzene")
+ # @param [String] name name can be also an InChI/InChiKey, CAS number, etc
+ # @return [OpenTox::Compound] Compound
def self.from_name(name)
c = Compound.new
# paranoid URI encoding to keep SMILES charges and brackets
@@ -83,32 +69,42 @@ module OpenTox
end
# Get (canonical) smiles
- def smiles
+ # @return [String] Smiles string
+ def to_smiles
Compound.obconversion(@inchi,'inchi','can')
end
# Get sdf
- def sdf
+ # @return [String] SDF string
+ def to_sdf
Compound.obconversion(@inchi,'inchi','sdf')
end
# Get gif image
- def gif
+ # @return [image/gif] Image data
+ def to_gif
RestClientWrapper.get("#{@@cactus_uri}#{@inchi}/image")
end
# Get png image
- def png
+ # @example
+ # image = compound.to_png
+ # @return [image/png] Image data
+ def to_png
RestClientWrapper.get(File.join @uri, "image")
end
# Get URI of compound image
- def image_uri
+ # @return [String] Compound image URI
+ def to_image_uri
File.join @uri, "image"
end
- # Get all known compound names
- def names
+ # Get all known compound names. Relies on an external service for name lookups.
+ # @example
+ # names = compound.to_names
+ # @return [String] Compound names
+ def to_names
begin
RestClientWrapper.get("#{@@cactus_uri}#{@inchi}/names").split("\n")
rescue
@@ -117,6 +113,10 @@ module OpenTox
end
# Match a smarts string
+ # @example
+ # compound = OpenTox::Compound.from_name("Benzene")
+ # compound.match?("cN") # returns false
+ # @param [String] smarts Smarts string
def match?(smarts)
obconversion = OpenBabel::OBConversion.new
obmol = OpenBabel::OBMol.new
@@ -128,19 +128,34 @@ module OpenTox
end
# Match an array of smarts strings, returns array with matching smarts
+ # @example
+ # compound = OpenTox::Compound.from_name("Benzene")
+ # compound.match(['cc','cN']) # returns ['cc']
+ # @param [Array] smarts_array Array with Smarts strings
+ # @return [Array] Array with matching Smarts strings
def match(smarts_array)
- smarts_array.collect{|s| s if match?(s)}.compact
+ # avoid recreation of OpenBabel objects
+ obconversion = OpenBabel::OBConversion.new
+ obmol = OpenBabel::OBMol.new
+ obconversion.set_in_format('inchi')
+ obconversion.read_string(obmol,@inchi)
+ smarts_pattern = OpenBabel::OBSmartsPattern.new
+ smarts_array.collect do |smarts|
+ smarts_pattern.init(smarts)
+ smarts if smarts_pattern.match(obmol)
+ end.compact
+ #smarts_array.collect { |s| s if match?(s)}.compact
end
# Get URI of compound image with highlighted fragments
- def matching_smarts_image_uri(activating, deactivating, highlight = nil)
+ #
+ # @param [Array] activating Array with activating Smarts strings
+ # @param [Array] deactivating Array with deactivating Smarts strings
+ # @return [String] URI for compound image with highlighted fragments
+ def matching_smarts_image_uri(activating, deactivating)
activating_smarts = URI.encode "\"#{activating.join("\"/\"")}\""
deactivating_smarts = URI.encode "\"#{deactivating.join("\"/\"")}\""
- if highlight.nil?
- File.join CONFIG[:services]["opentox-compound"], "smiles", URI.encode(smiles), "smarts/activating", URI.encode(activating_smarts),"deactivating", URI.encode(deactivating_smarts)
- else
- File.join CONFIG[:services]["opentox-compound"], "smiles", URI.encode(smiles), "smarts/activating", URI.encode(activating_smarts),"deactivating", URI.encode(deactivating_smarts), "highlight", URI.encode(highlight)
- end
+ File.join @uri, "smarts/activating", URI.encode(activating_smarts),"deactivating", URI.encode(deactivating_smarts)
end
diff --git a/lib/dataset.rb b/lib/dataset.rb
index 7c8ce24..05b2ed3 100644
--- a/lib/dataset.rb
+++ b/lib/dataset.rb
@@ -1,74 +1,19 @@
module OpenTox
# Ruby wrapper for OpenTox Dataset Webservices (http://opentox.org/dev/apis/api-1.2/dataset).
- #
- # Examples:
- # require "opentox-ruby-api-wrapper"
- #
- # # Creating datasets
- #
- # # create an empty dataset
- # dataset = OpenTox::Dataset.new
- # # create an empty dataset with URI
- # # this does not load data from the dataset service - use one of the load_* methods
- # dataset = OpenTox::Dataset.new("http:://webservices.in-silico/ch/dataset/1")
- # # create new dataset and sav it to obtain a URI
- # dataset = OpenTox::Dataset.create
- # # create a new dataset from yaml representation
- # dataset = OpenTox::Dataset.from_yaml
- # # create a new dataset from CSV string
- # csv_string = "SMILES, Toxicity\nc1ccccc1N, true"
- # dataset = OpenTox::Dataset.from_csv(csv_string)
- #
- # # Loading data
- # # Datasets created with OpenTox::Dataset.new(uri) are empty by default
- # # Invoking one of the following functions will load data into the object
- #
- # # create an empty dataset with URI
- # dataset = OpenTox::Dataset.new("http:://webservices.in-silico/ch/dataset/1")
- # # loads (and returns) only metadata
- # dataset.load_metadata
- # # loads (and returns) only compounds
- # dataset.load_compounds
- # # loads (and returns) only features
- # dataset.load_features
- # # load all data from URI
- # dataset.load_all
- #
- # # Getting dataset representations
- #
- # dataset = OpenTox::Dataset.new("http:://webservices.in-silico/ch/dataset/1")
- # dataset.load_all
- # # OWL-DL (RDF/XML)
- # dataset.rdfxml
- # # OWL-DL (Ntriples)
- # dataset.ntriples
- # # YAML
- # dataset.yaml
- # # CSV
- # dataset.csv
- #
- # # Modifying datasets
- #
- # # insert a statement (compound_uri,feature_uri,value)
- # dataset.add "http://webservices.in-silico.ch/compound/InChI=1S/C6Cl6/c7-1-2(8)4(10)6(12)5(11)3(1)9", "http://webservices.in-silico.ch/dataset/1/feature/hamster_carcinogenicity", true
- #
- #
- # # Saving datasets
- # # save dataset at dataset service
- # dataset.save
- #
- # # Deleting datasets
- # # delete dataset (also at dataset service)
- # dataset.delete
class Dataset
- include OtObject
+ include OpenTox
attr_reader :features, :compounds, :data_entries, :metadata
- attr_writer :metadata
- # Create dataset with optional URI
+ # Create dataset with optional URI. Does not load data into the dataset - you will need to execute one of the load_* methods to pull data from a service or to insert it from other representations.
+ # @example Create an empty dataset
+ # dataset = OpenTox::Dataset.new
+ # @example Create an empty dataset with URI
+ # dataset = OpenTox::Dataset.new("http:://webservices.in-silico/ch/dataset/1")
+ # @param [optional, String] uri Dataset URI
+ # @return [OpenTox::Dataset] Dataset object
def initialize(uri=nil)
super uri
@features = {}
@@ -76,52 +21,79 @@ module OpenTox
@data_entries = {}
end
- # Create and save an empty dataset (assigns URI to dataset)
+ # Create an empty dataset and save it at the dataset service (assigns URI to dataset)
+ # @example Create new dataset and save it to obtain a URI
+ # dataset = OpenTox::Dataset.create
+ # @param [optional, String] uri Dataset URI
+ # @return [OpenTox::Dataset] Dataset object
def self.create(uri=CONFIG[:services]["opentox-dataset"])
dataset = Dataset.new
- dataset.uri = RestClientWrapper.post(uri,{}).to_s.chomp
+ dataset.save
+ dataset
+ end
+
+ # Find a dataset and load all data. This can be time consuming, use Dataset.new together with one of the load_* methods for a fine grained control over data loading.
+ # @param [String] uri Dataset URI
+ # @return [OpenTox::Dataset] Dataset object with all data
+ def self.find(uri)
+ dataset = Dataset.new(uri)
+ dataset.load_all
dataset
end
# Get all datasets from a service
-# def self.all(uri=CONFIG[:services]["opentox-dataset"])
-# RestClientWrapper.get(uri,:accept => "text/uri-list").to_s.each_line.collect{|u| Dataset.new(u)}
-# end
+ # @param [optional,String] uri URI of the dataset service, defaults to service specified in configuration
+ # @return [Array] Array of dataset object with all data
+ def self.all(uri=CONFIG[:services]["opentox-dataset"])
+ RestClientWrapper.get(uri,:accept => "text/uri-list").to_s.each_line.collect{|u| Dataset.new(u)}
+ end
- # Create a dataset from YAML string
- def self.from_yaml(yaml)
- dataset = Dataset.create
- dataset.copy YAML.load(yaml)
- dataset
+ # Load YAML representation into the dataset
+ # @param [String] yaml YAML representation of the dataset
+ # @return [OpenTox::Dataset] Dataset object with YAML data
+ def load_yaml(yaml)
+ copy YAML.load(yaml)
+ end
+
+ # Load RDF/XML representation from a file
+ # @param [String] file File with RDF/XML representation of the dataset
+ # @return [OpenTox::Dataset] Dataset object with RDF/XML data
+ def load_rdfxml_file(file)
+ parser = Parser::Owl::Dataset.new @uri
+ parser.uri = file.path
+ copy parser.load_uri
end
- # Create dataset from CSV string (format specification: http://toxcreate.org/help)
+ # Load CSV string (format specification: http://toxcreate.org/help)
# - loads data_entries, compounds, features
# - sets metadata (warnings) for parser errors
# - you will have to set remaining metadata manually
- def self.from_csv(csv)
- dataset = Dataset.create
- Parser::Spreadsheet.new(dataset).load_csv(csv)
- dataset
+ # @param [String] csv CSV representation of the dataset
+ # @return [OpenTox::Dataset] Dataset object with CSV data
+ def load_csv(csv)
+ save unless @uri # get a uri for creating features
+ parser = Parser::Spreadsheets.new
+ parser.dataset = self
+ parser.load_csv(csv)
end
- # Create dataset from Spreadsheet book (created with roo gem http://roo.rubyforge.org/, excel format specification: http://toxcreate.org/help))
+ # Load Spreadsheet book (created with roo gem http://roo.rubyforge.org/, excel format specification: http://toxcreate.org/help))
# - loads data_entries, compounds, features
# - sets metadata (warnings) for parser errors
# - you will have to set remaining metadata manually
- def self.from_spreadsheet(book)
- dataset = Dataset.create
- Parser::Spreadsheet.new(dataset).load_excel(book)
- dataset
+ # @param [Excel] book Excel workbook object (created with roo gem)
+ # @return [OpenTox::Dataset] Dataset object with Excel data
+ def load_spreadsheet(book)
+ save unless @uri # get a uri for creating features
+ parser = Parser::Spreadsheets.new
+ parser.dataset = self
+ parser.load_excel(book)
end
- # Load and return metadata of a Dataset object
+ # Load and return only metadata of a Dataset object
+ # @return [Hash] Metadata of the dataset
def load_metadata
- #if (CONFIG[:yaml_hosts].include?(URI.parse(@uri).host))
- #add_metadata YAML.load(RestClientWrapper.get(File.join(@uri,"metadata"), :accept => "application/x-yaml"))
- #else
- add_metadata Parser::Owl::Dataset.new(@uri).metadata
- #end
+ add_metadata Parser::Owl::Dataset.new(@uri).metadata
self.uri = @uri if @uri # keep uri
@metadata
end
@@ -136,7 +108,8 @@ module OpenTox
end
end
- # Load and return all compound URIs
+ # Load and return only compound URIs from the dataset service
+ # @return [Array] Compound URIs in the dataset
def load_compounds
RestClientWrapper.get(File.join(uri,"compounds"),:accept=> "text/uri-list").to_s.each_line do |compound_uri|
@compounds << compound_uri.chomp
@@ -144,44 +117,75 @@ module OpenTox
@compounds.uniq!
end
- # Load all feature URIs
+ # Load and return only features from the dataset service
+ # @return [Hash] Features of the dataset
def load_features
- RestClientWrapper.get(File.join(uri,"features"),:accept=> "text/uri-list").to_s.each_line do |feature_uri|
- @features[feature_uri.chomp] = Feature.new(feature_uri.chomp).load_metadata
- end
+ parser = Parser::Owl::Dataset.new(@uri)
+ @features = parser.load_features
@features
end
- # Get YAML representation
- def yaml
- self.to_yaml
+ # Detect feature type(s) in the dataset
+ # @return [String] `classification", "regression", "mixed" or unknown`
+ def feature_type
+ feature_types = @features.collect{|f,metadata| metadata[OT.isA]}.uniq
+ LOGGER.debug "FEATURES"
+ LOGGER.debug feature_types.inspect
+ if feature_types.size > 1
+ "mixed"
+ else
+ case feature_types.first
+ when /NominalFeature/
+ "classification"
+ when /NumericFeature/
+ "regression"
+ else
+ "unknown"
+ end
+ end
end
- # Get Excel representation, returns a Spreadsheet::Workbook which can be written with the 'spreadsheet' gem (data_entries only, metadata will )
- def excel
- Serializer::Spreadsheets.new(self).excel
+ # Get Excel representation
+ # @return [Spreadsheet::Workbook] Workbook which can be written with the spreadsheet gem (data_entries only, metadata will will be discarded))
+ def to_xls
+ Serializer::Spreadsheets.new(self).to_xls
end
# Get CSV string representation (data_entries only, metadata will be discarded)
- def csv
- Serializer::Spreadsheets.new(self).csv
+ # @return [String] CSV representation
+ def to_csv
+ Serializer::Spreadsheets.new(self).to_csv
end
# Get OWL-DL in ntriples format
- def ntriples
+ # @return [String] N-Triples representation
+ def to_ntriples
s = Serializer::Owl.new
s.add_dataset(self)
- s.ntriples
+ s.to_ntriples
end
# Get OWL-DL in RDF/XML format
- def rdfxml
+ # @return [String] RDF/XML representation
+ def to_rdfxml
s = Serializer::Owl.new
s.add_dataset(self)
- s.rdfxml
+ s.to_rdfxml
+ end
+
+ # Get name (DC.title) of a feature
+ # @param [String] feature Feature URI
+ # @return [String] Feture title
+ def feature_name(feature)
+ @features[feature][DC.title]
end
# Insert a statement (compound_uri,feature_uri,value)
+ # @example Insert a statement (compound_uri,feature_uri,value)
+ # dataset.add "http://webservices.in-silico.ch/compound/InChI=1S/C6Cl6/c7-1-2(8)4(10)6(12)5(11)3(1)9", "http://webservices.in-silico.ch/dataset/1/feature/hamster_carcinogenicity", true
+ # @param [String] compound Compound URI
+ # @param [String] feature Compound URI
+ # @param [Boolean,Float] value Feature value
def add (compound,feature,value)
@compounds << compound unless @compounds.include? compound
@features[feature] = {} unless @features[feature]
@@ -190,252 +194,62 @@ module OpenTox
@data_entries[compound][feature] << value
end
- # Add metadata (hash with predicate_uri => value)
+ # Add/modify metadata, existing entries will be overwritten
+ # @example
+ # dataset.add_metadata({DC.title => "any_title", DC.creator => "my_email"})
+ # @param [Hash] metadata Hash mapping predicate_uris to values
def add_metadata(metadata)
metadata.each { |k,v| @metadata[k] = v }
end
- # Copy a dataset (rewrites URI)
- def copy(dataset)
- @metadata = dataset.metadata
- @data_entries = dataset.data_entries
- @compounds = dataset.compounds
- @features = dataset.features
- if @uri
- self.uri = @uri
- else
- @uri = dataset.metadata[XSD.anyUri]
- end
+ # Add a feature
+ # @param [String] feature Feature URI
+ # @param [Hash] metadata Hash with feature metadata
+ def add_feature(feature,metadata={})
+ @features[feature] = metadata
end
- # save dataset (overwrites existing dataset)
+ # Add/modify metadata for a feature
+ # @param [String] feature Feature URI
+ # @param [Hash] metadata Hash with feature metadata
+ def add_feature_metadata(feature,metadata)
+ metadata.each { |k,v| @features[feature][k] = v }
+ end
+
+ # Save dataset at the dataset service
+ # - creates a new dataset if uri is not set
+ # - overwrites dataset if uri exists
+ # @return [String] Dataset URI
def save
# TODO: rewrite feature URI's ??
- # create dataset if uri empty
@compounds.uniq!
- RestClientWrapper.post(@uri,{:content_type => "application/x-yaml"},self.to_yaml)
+ if @uri
+ RestClientWrapper.post(@uri,{:content_type => "application/x-yaml"},self.to_yaml)
+ else
+ # create dataset if uri is empty
+ self.uri = RestClientWrapper.post(CONFIG[:services]["opentox-dataset"],{}).to_s.chomp
+ RestClientWrapper.post(@uri,{:content_type => "application/x-yaml"},self.to_yaml)
+ end
+ @uri
end
# Delete dataset at the dataset service
def delete
RestClientWrapper.delete @uri
end
- end
-end
-
- #########################################################
- # kept for backward compatibility, may have to be fixed #
- #########################################################
-
-=begin
- def from_owl(owl)
- # creates dataset object from Opentox::Owl object
- # use Dataset.find( ) to load dataset from rdf-supporting datasetservice
- # note: does not load all feature values, as this is time consuming
- raise "invalid param" unless owl.is_a?(OpenTox::Owl)
- @metadata[DC.title] = owl.get("title")
- @metadata[DC.creator] = owl.get("creator")
- @metadata[XSD.anyUri] = owl.uri
- # when loading a dataset from owl, only compound- and feature-uris are loaded
- owl.load_dataset(@compounds, @features)
- # all features are marked as dirty
- # as soon as a feature-value is requested all values for this feature are loaded from the rdf
- @dirty_features = @features.dclone
- @owl = owl
- end
-
- def self.find(uri, accept_header=nil)
-
- unless accept_header
- if (CONFIG[:yaml_hosts].include?(URI.parse(uri).host))
- accept_header = 'application/x-yaml'
- else
- accept_header = "application/rdf+xml"
- end
- end
-
- case accept_header
- when "application/x-yaml"
- LOGGER.debug "DATASET: "+ uri
- LOGGER.debug RestClientWrapper.get(uri.to_s.strip, :accept => 'application/x-yaml').to_s
- d = YAML.load RestClientWrapper.get(uri.to_s.strip, :accept => 'application/x-yaml').to_s
- #d.uri = @metadata[XSD.anyUri] unless d.uri
- when "application/rdf+xml"
- owl = OpenTox::Owl.from_uri(uri.to_s.strip, "Dataset")
- d = Dataset.new(owl)
- else
- raise "cannot get datset with accept header: "+accept_header.to_s
- end
- d
- end
- # converts a dataset represented in owl to yaml
- # (uses a temporary dataset)
- # note: to_yaml is overwritten, loads complete owl dataset values
- def self.owl_to_yaml( owl_data, uri)
- owl = OpenTox::Owl.from_data(owl_data, uri, "Dataset")
- d = Dataset.new(owl)
- d.to_yaml
- end
-
- # creates a new dataset, using only those compounsd specified in new_compounds
- # returns uri of new dataset
- def create_new_dataset( new_compounds, new_features, new_title, new_creator )
-
- LOGGER.debug "create new dataset with "+new_compounds.size.to_s+"/"+compounds.size.to_s+" compounds"
- raise "no new compounds selected" unless new_compounds and new_compounds.size>0
-
- # load require features
- if ((defined? @dirty_features) && (@dirty_features & new_features).size > 0)
- (@dirty_features & new_features).each{|f| load_feature_values(f)}
- end
-
- dataset = OpenTox::Dataset.new
- dataset.title = new_title
- dataset.creator = new_creator
- dataset.features = new_features
- dataset.compounds = new_compounds
-
- # Copy dataset data for compounds and features
- # PENDING: why storing feature values in an array?
- new_compounds.each do |c|
- data_c = []
- raise "no data for compound '"+c.to_s+"'" if @data[c]==nil
- @data[c].each do |d|
- m = {}
- new_features.each do |f|
- m[f] = d[f]
- end
- data_c << m
- end
- dataset.data[c] = data_c
- end
- return dataset.save
- end
-
- # returns classification value
- def get_predicted_class(compound, feature)
- v = get_value(compound, feature)
- if v.is_a?(Hash)
- k = v.keys.grep(/classification/).first
- unless k.empty?
- #if v.has_key?(:classification)
- return v[k]
- else
- return "no classification key"
- end
- elsif v.is_a?(Array)
- raise "predicted class value is an array\n"+
- "value "+v.to_s+"\n"+
- "value-class "+v.class.to_s+"\n"+
- "dataset "+self.uri.to_s+"\n"+
- "compound "+compound.to_s+"\n"+
- "feature "+feature.to_s+"\n"
- else
- return v
- end
- end
-
- # returns regression value
- def get_predicted_regression(compound, feature)
- v = get_value(compound, feature)
- if v.is_a?(Hash)
- k = v.keys.grep(/regression/).first
- unless k.empty?
- return v[k]
- else
- return "no regression key"
- end
- elsif v.is_a?(Array)
- raise "predicted regression value is an array\n"+
- "value "+v.to_s+"\n"+
- "value-class "+v.class.to_s+"\n"+
- "dataset "+self.uri.to_s+"\n"+
- "compound "+compound.to_s+"\n"+
- "feature "+feature.to_s+"\n"
- else
- return v
- end
- end
-
- # returns prediction confidence if available
- def get_prediction_confidence(compound, feature)
- v = get_value(compound, feature)
- if v.is_a?(Hash)
- k = v.keys.grep(/confidence/).first
- unless k.empty?
- #if v.has_key?(:confidence)
- return v[k].abs
- #return v["http://ot-dev.in-silico.ch/model/lazar#confidence"].abs
- else
- # PENDING: return nil isntead of raising an exception
- raise "no confidence key"
- end
- else
- LOGGER.warn "no confidence for compound: "+compound.to_s+", feature: "+feature.to_s
- return 1
- end
- end
-
- # return compound-feature value
- def get_value(compound, feature)
- if (defined? @dirty_features) && @dirty_features.include?(feature)
- load_feature_values(feature)
- end
-
- v = @data[compound]
- return nil if v == nil # missing values for all features
- if v.is_a?(Array)
- # PENDING: why using an array here?
- v.each do |e|
- if e.is_a?(Hash)
- if e.has_key?(feature)
- return e[feature]
- end
- else
- raise "invalid internal value type"
- end
- end
- return nil #missing value
- else
- raise "value is not an array\n"+
- "value "+v.to_s+"\n"+
- "value-class "+v.class.to_s+"\n"+
- "dataset "+self.uri.to_s+"\n"+
- "compound "+compound.to_s+"\n"+
- "feature "+feature.to_s+"\n"
- end
- end
-
- # loads specified feature and removes dirty-flag, loads all features if feature is nil
- def load_feature_values(feature=nil)
- if feature
- raise "feature already loaded" unless @dirty_features.include?(feature)
- @owl.load_dataset_feature_values(@compounds, @data, [feature])
- @dirty_features.delete(feature)
+ private
+ # Copy a dataset (rewrites URI)
+ def copy(dataset)
+ @metadata = dataset.metadata
+ @data_entries = dataset.data_entries
+ @compounds = dataset.compounds
+ @features = dataset.features
+ if @uri
+ self.uri = @uri
else
- @data = {} unless @data
- @owl.load_dataset_feature_values(@compounds, @data, @dirty_features)
- @dirty_features.clear
+ @uri = dataset.metadata[XSD.anyURI]
end
end
-
- # overwrite to yaml:
- # in case dataset is loaded from owl:
- # * load all values
- def to_yaml
- # loads all features
- if ((defined? @dirty_features) && @dirty_features.size > 0)
- load_feature_values
- end
- super
- end
-
- # * remove @owl from yaml, not necessary
- def to_yaml_properties
- super - ["@owl"]
- end
-
end
end
-=end
diff --git a/lib/environment.rb b/lib/environment.rb
index b16b62f..d66b062 100644
--- a/lib/environment.rb
+++ b/lib/environment.rb
@@ -61,3 +61,32 @@ FALSE_REGEXP = /^(false|inactive|0|0.0)$/i
# Task durations
DEFAULT_TASK_MAX_DURATION = 36000
EXTERNAL_TASK_MAX_DURATION = 36000
+
+# OWL Namespaces
+class OwlNamespace
+
+ def initialize(uri)
+ @uri = uri
+ end
+
+ def [](property)
+ @uri+property.to_s
+ end
+
+ def type # for RDF.type
+ "#{@uri}type"
+ end
+
+ def method_missing(property)
+ @uri+property.to_s
+ end
+
+end
+
+RDF = OwlNamespace.new 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'
+OWL = OwlNamespace.new 'http://www.w3.org/2002/07/owl#'
+DC = OwlNamespace.new 'http://purl.org/dc/elements/1.1/'
+OT = OwlNamespace.new 'http://www.opentox.org/api/1.1#'
+OTA = OwlNamespace.new 'http://www.opentox.org/algorithmTypes.owl#'
+XSD = OwlNamespace.new 'http://www.w3.org/2001/XMLSchema#'
+
diff --git a/lib/feature.rb b/lib/feature.rb
index 9616135..13d97a2 100644
--- a/lib/feature.rb
+++ b/lib/feature.rb
@@ -1,7 +1,5 @@
module OpenTox
-
class Feature
- include OtObject
+ include OpenTox
end
-
end
diff --git a/lib/model.rb b/lib/model.rb
index d0d6703..63013cb 100644
--- a/lib/model.rb
+++ b/lib/model.rb
@@ -1,143 +1,410 @@
module OpenTox
+
module Model
+ include OpenTox
+
+ def run(params)
+ if CONFIG[:yaml_hosts].include?(URI.parse(@uri).host)
+ accept = 'application/x-yaml'
+ else
+ accept = 'application/rdf+xml'
+ end
+ begin
+ params[:acccept] = accept
+ #TODO fix: REstClientWrapper does not accept accept header
+ #RestClientWrapper.post(@uri,params)#,{:accept => accept})
+ `curl -X POST -H "Accept:#{accept}" #{params.collect{|k,v| "-d #{k}=#{v}"}.join(" ")} #{@uri}`.to_s.chomp
+ rescue => e
+ LOGGER.error "Failed to run #{@uri} with #{params.inspect} (#{e.inspect})"
+ raise "Failed to run #{@uri} with #{params.inspect}"
+ end
+ end
+
+=begin
+ def classification?
+ #TODO replace with request to ontology server
+ if @metadata[DC.title] =~ /(?i)classification/
+ return true
+ elsif @metadata[DC.title] =~ /(?i)regression/
+ return false
+ elsif @uri =~/ntua/ and @metadata[DC.title] =~ /mlr/
+ return false
+ elsif @uri =~/tu-muenchen/ and @metadata[DC.title] =~ /regression|M5P|GaussP/
+ return false
+ elsif @uri =~/ambit2/ and @metadata[DC.title] =~ /pKa/ || @metadata[DC.title] =~ /Regression|Caco/
+ return false
+ elsif @uri =~/majority/
+ return (@uri =~ /class/) != nil
+ else
+ raise "unknown model, uri:'"+@uri+"' title:'"+@metadata[DC.title]+"'"
+ end
+ end
+=end
+
class Generic
+ include Model
+ end
+
+ class Lazar
+
+ include Model
+
+ #attr_accessor :prediction_type, :feature_type, :features, :effects, :activities, :p_values, :fingerprints, :parameters
+ attr_accessor :compound, :prediction_dataset, :features, :effects, :activities, :p_values, :fingerprints, :parameters, :feature_calculation_algorithm, :similarity_algorithm, :prediction_algorithm
+
+ def initialize(uri=nil)
+
+ if uri
+ super uri
+ else
+ super CONFIG[:services]["opentox-model"]
+ end
+
+ # TODO: fix metadata, add parameters
+ @metadata[OT.algorithm] = File.join(CONFIG[:services]["opentox-algorithm"],"lazar")
+
+ @features = []
+ @effects = {}
+ @activities = {}
+ @p_values = {}
+ @fingerprints = {}
+
+ @feature_calculation_algorithm = "substructure_match"
+ @similarity_algorithm = "weighted_tanimoto"
+ @prediction_algorithm = "weighted_majority_vote"
- MODEL_ATTRIBS = [:uri, :title, :creator, :date, :format, :predictedVariables, :independentVariables, :dependentVariables, :trainingDataset, :algorithm]
- MODEL_ATTRIBS.each{ |a| attr_accessor(a) }
+ @min_sim = 0.3
+
+ end
def self.find(uri)
- owl = OpenTox::Owl.from_uri(uri, "Model")
- return self.new(owl)
- end
-
- def self.to_rdf(model)
- owl = OpenTox::Owl.create 'Model', model.uri
- (MODEL_ATTRIBS - [:uri]).each do |a|
- owl.set(a.to_s,model.send(a.to_s))
+ YAML.load RestClientWrapper.get(uri,:content_type => 'application/x-yaml')
+ end
+
+ def self.create_from_dataset(dataset_uri,feature_dataset_uri,prediction_feature=nil)
+ training_activities = OpenTox::Dataset.find(dataset_uri)
+ training_features = OpenTox::Dataset.find(feature_dataset_uri)
+ unless prediction_feature # try to read prediction_feature from dataset
+ raise "#{training_activities.features.size} features in dataset #{dataset_uri}. Please provide a prediction_feature parameter." unless training_activities.features.size == 1
+ prediction_feature = training_activities.features.keys.first
+ params[:prediction_feature] = prediction_feature
+ end
+ lazar = Lazar.new
+ training_features = OpenTox::Dataset.new(feature_dataset_uri)
+ case training_features.feature_type
+ when "classification"
+ lazar.similarity_algorithm = "weighted_tanimoto"
+ when "regression"
+ lazar.similarity_algorithm = "weighted_euclid"
end
- owl.rdf
end
-
- protected
- def initialize(owl)
- MODEL_ATTRIBS.each do |a|
- self.send("#{a.to_s}=".to_sym, owl.get(a.to_s)) unless a==:uri
+
+ def self.create(dataset_uri,prediction_feature=nil,feature_generation_uri=File.join(CONFIG[:services]["opentox-algorithm"],"fminer/bbrc"),params=nil)
+
+ training_activities = OpenTox::Dataset.find(dataset_uri)
+
+ unless prediction_feature # try to read prediction_feature from dataset
+ raise "#{training_activities.features.size} features in dataset #{dataset_uri}. Please provide a prediction_feature parameter." unless training_activities.features.size == 1
+ prediction_feature = training_activities.features.keys.first
+ params[:prediction_feature] = prediction_feature
end
- @uri = owl.uri
- if ENV['RACK_ENV'] =~ /test|debug/
- begin
- raise "uri invalid" unless Utils.is_uri?(@uri)
- raise "no predicted variables" unless @predictedVariables and @predictedVariables.size>0
- rescue => ex
- RestClientWrapper.raise_uri_error "invalid model: '"+ex.message+"'\n"+self.to_yaml+"\n",@uri.to_s
+
+ lazar = Lazar.new
+ params[:feature_generation_uri] = feature_generation_uri
+ feature_dataset_uri = OpenTox::Algorithm::Generic.new(feature_generation_uri).run(params).to_s
+ training_features = OpenTox::Dataset.find(feature_dataset_uri)
+ raise "Dataset #{feature_dataset_uri} not found or empty." if training_features.nil?
+
+ # sorted features for index lookups
+ lazar.features = training_features.features.sort if training_features.feature_type == "regression"
+
+ training_features.data_entries.each do |compound,entry|
+ lazar.fingerprints[compound] = [] unless lazar.fingerprints[compound]
+ entry.keys.each do |feature|
+ case training_features.feature_type
+ when "fminer"
+ # fingerprints are sets
+ smarts = training_features.features[feature][OT.smarts]
+ lazar.fingerprints[compound] << smarts
+ unless lazar.features.include? smarts
+ lazar.features << smarts
+ lazar.p_values[smarts] = training_features.features[feature][OT.p_value]
+ lazar.effects[smarts] = training_features.features[feature][OT.effect]
+ end
+ when "classification"
+ # fingerprints are sets
+ if entry[feature].flatten.size == 1
+ lazar.fingerprints[compound] << feature if entry[feature].flatten.first.match(TRUE_REGEXP)
+ lazar.features << feature unless lazar.features.include? feature
+ else
+ LOGGER.warn "More than one entry (#{entry[feature].inspect}) for compound #{compound}, feature #{feature}"
+ end
+ when "regression"
+ # fingerprints are arrays
+ if entry[feature].flatten.size == 1
+ lazar.fingerprints[compound][lazar.features.index(feature)] = entry[feature].flatten.first
+ else
+ LOGGER.warn "More than one entry (#{entry[feature].inspect}) for compound #{compound}, feature #{feature}"
+ end
+ end
+ end
+
+ lazar.activities[compound] = [] unless lazar.activities[compound]
+ training_activities.data_entries[compound][params[:prediction_feature]].each do |value|
+ case value.to_s
+ when "true"
+ lazar.activities[compound] << true
+ when "false"
+ lazar.activities[compound] << false
+ else
+ lazar.activities[compound] << value.to_f
+ lazar.prediction_type = "regression"
+ end
end
- LOGGER.warn "model has no dependent variable" unless @dependentVariables and @dependentVariables.size>0
- LOGGER.warn "model has no algorithm" unless @algorithm and @algorithm.size>0
- LOGGER.warn "model has no indenpendent variables" unless @independentVariables
end
+
+ if feature_generation_uri.match(/fminer/)
+ lazar.feature_calculation_algorithm = "substructure_match"
+ else
+ halt 404, "External feature generation services not yet supported"
+ end
+
+ lazar.metadata[OT.dependentVariables] = params[:prediction_feature]
+ lazar.metadata[OT.trainingDataset] = dataset_uri
+ lazar.metadata[OT.featureDataset] = feature_dataset_uri
+
+ lazar.parameters = {
+ "dataset_uri" => dataset_uri,
+ "prediction_feature" => prediction_feature,
+ "feature_generation_uri" => feature_generation_uri
+ }
+
+ model_uri = lazar.save
+ LOGGER.info model_uri + " created #{Time.now}"
+ model_uri
end
- end
-
- class PredictionModel < Generic
-
- def self.build( algorithm_uri, algorithm_params )
-
- LOGGER.debug "Build model, algorithm_uri:"+algorithm_uri.to_s+", algorithm_parms: "+algorithm_params.inspect.to_s
- uri = OpenTox::RestClientWrapper.post(algorithm_uri,algorithm_params).to_s
- LOGGER.debug "Build model done: "+uri.to_s
- RestClientWrapper.raise_uri_error("Invalid build model result: '"+uri.to_s+"'", algorithm_uri, algorithm_params ) unless Utils.model_uri?(uri)
- return PredictionModel.find(uri)
- end
-
- def predict_dataset( dataset_uri )
-
- LOGGER.debug "Predict dataset: "+dataset_uri.to_s+" with model "+@uri.to_s
- uri = RestClientWrapper.post(@uri, {:accept => "text/uri-list", :dataset_uri=>dataset_uri})
- RestClientWrapper.raise_uri_error("Prediciton result no dataset uri: "+uri.to_s, @uri, {:dataset_uri=>dataset_uri} ) unless Utils.dataset_uri?(uri)
- uri
- end
-
- def classification?
- #HACK replace with request to ontology server
- if @title =~ /(?i)classification/
- return true
- elsif @title =~ /(?i)regression/
- return false
- elsif @uri =~/ntua/ and @title =~ /mlr/
- return false
- elsif @uri =~/tu-muenchen/ and @title =~ /regression|M5P|GaussP/
- return false
- elsif @uri =~/ambit2/ and @title =~ /pKa/ || @title =~ /Regression|Caco/
- return false
- elsif @uri =~/majority/
- return (@uri =~ /class/) != nil
+
+ def predict_dataset(dataset_uri)
+ @prediction_dataset = Dataset.create
+ @prediction_dataset.add_metadata({
+ OT.hasSource => @lazar.uri,
+ DC.creator => @lazar.uri,
+ DC.title => URI.decode(File.basename( @metadata[OT.dependentVariables] ))
+ })
+ @prediction_dataset.add_parameters({"dataset_uri" => dataset_uri})
+ Dataset.new(dataset_uri).load_compounds.each do |compound_uri|
+ predict(compound_uri,false)
+ end
+ @prediction_dataset.save
+ @prediction_dataset.uri
+ end
+
+ def predict(compound_uri,verbose=false)
+
+ @compound = Compound.new compound_uri
+
+ unless @prediction_dataset
+ @prediction_dataset = Dataset.create
+ @prediction_dataset.add_metadata( {
+ OT.hasSource => @lazar.uri,
+ DC.creator => @lazar.uri,
+ DC.title => URI.decode(File.basename( @metadata[OT.dependentVariables] ))
+ } )
+ @prediction_dataset.add_parameters( {"compound_uri" => compound_uri} )
+ end
+
+ neighbors
+ eval @prediction_algorithm
+
+ if @prediction
+
+ feature_uri = File.join( @prediction_dataset.uri, "feature", @prediction_dataset.compounds.size)
+ @prediction_dataset.add @compound.uri, feature_uri, @prediction
+
+ feature_metadata = @prediction_dataset.metadata
+ feature_metadata[DC.title] = File.basename(@metadata[OT.dependentVariables])
+ feature_metadata[OT.prediction] = @prediction
+ feature_metadata[OT.confidence] = @confidence
+ @prediction_dataset.add_feature(feature_uri, feature_metadata)
+
+ if verbose
+ if @compound_features
+ @compound_features.each do |feature|
+ @prediction_dataset.add @compound.uri, feature, true
+ end
+ end
+ n = 0
+ @neighbors.sort{|a,b| a[:similarity] <=> b[:similarity]}.each do |neighbor|
+ neighbor_uri = File.join( @prediction_dataset.uri, "feature/neighbor", n )
+ @prediction_dataset.add @compound.uri, neighbor_uri, true
+ @prediction_dataset.add_feature(neighbor, {
+ OT.compound => neighbor[:compound],
+ OT.similarity => neighbor[:similarity],
+ OT.activity => neighbor[:activity]
+ })
+ n+=1
+ end
+ end
+ end
+ @prediction_dataset.save
+ @prediction_dataset.uri
+ end
+
+ def weighted_majority_vote
+ conf = 0.0
+ @neighbors.each do |neighbor|
+ case neighbor[:activity].to_s
+ when 'true'
+ conf += OpenTox::Algorithm.gauss(neighbor[:similarity])
+ when 'false'
+ conf -= OpenTox::Algorithm.gauss(neighbor[:similarity])
+ end
+ end
+ if conf > 0.0
+ @prediction = true
+ elsif conf < 0.0
+ @prediction = false
else
- raise "unknown model, uri:'"+@uri.to_s+"' title:'"+@title.to_s+"'"
+ @prediction = nil
end
+ @confidence = conf/@neighbors.size if @neighbors.size > 0
end
- end
-
- class Lazar < Generic
-
- attr_accessor :feature_dataset_uri, :effects, :activities, :p_values, :fingerprints, :features
-
- def initialize
- @source = "http://github.com/helma/opentox-model"
- @algorithm = File.join(CONFIG[:services]["opentox-algorithm"],"lazar")
- #@independent_variables = File.join(CONFIG[:services]["opentox-algorithm"],"fminer#BBRC_representative")
- @features = []
- @effects = {}
- @activities = {}
- @p_values = {}
- @fingerprints = {}
+
+ def local_svm_regression
+ sims = @neighbors.collect{ |n| n[:similarity] } # similarity values between query and neighbors
+ conf = sims.inject{|sum,x| sum + x }
+ acts = @neighbors.collect do |n|
+ act = n[:activity]
+ # TODO: check this in model creation
+ raise "0 values not allowed in training dataset. log10 is calculated internally." if act.to_f == 0
+ Math.log10(act.to_f)
+ end # activities of neighbors for supervised learning
+
+ neighbor_matches = @neighbors.collect{ |n| n[:features] } # as in classification: URIs of matches
+ gram_matrix = [] # square matrix of similarities between neighbors; implements weighted tanimoto kernel
+ if neighbor_matches.size == 0
+ raise "No neighbors found"
+ else
+ # gram matrix
+ (0..(neighbor_matches.length-1)).each do |i|
+ gram_matrix[i] = []
+ # lower triangle
+ (0..(i-1)).each do |j|
+ sim = OpenTox::Algorithm.weighted_tanimoto(neighbor_matches[i], neighbor_matches[j], @lazar.p_values)
+ gram_matrix[i] << OpenTox::Algorithm.gauss(sim)
+ end
+ # diagonal element
+ gram_matrix[i][i] = 1.0
+ # upper triangle
+ ((i+1)..(neighbor_matches.length-1)).each do |j|
+ sim = OpenTox::Algorithm.weighted_tanimoto(neighbor_matches[i], neighbor_matches[j], @lazar.p_values) # double calculation?
+ gram_matrix[i] << OpenTox::Algorithm.gauss(sim)
+ end
+ end
+
+ @r = RinRuby.new(false,false) # global R instance leads to Socket errors after a large number of requests
+ @r.eval "library('kernlab')" # this requires R package "kernlab" to be installed
+ LOGGER.debug "Setting R data ..."
+ # set data
+ @r.gram_matrix = gram_matrix.flatten
+ @r.n = neighbor_matches.size
+ @r.y = acts
+ @r.sims = sims
+
+ LOGGER.debug "Preparing R data ..."
+ # prepare data
+ @r.eval "y<-as.vector(y)"
+ @r.eval "gram_matrix<-as.kernelMatrix(matrix(gram_matrix,n,n))"
+ @r.eval "sims<-as.vector(sims)"
+
+ # model + support vectors
+ LOGGER.debug "Creating SVM model ..."
+ @r.eval "model<-ksvm(gram_matrix, y, kernel=matrix, type=\"nu-svr\", nu=0.8)"
+ @r.eval "sv<-as.vector(SVindex(model))"
+ @r.eval "sims<-sims[sv]"
+ @r.eval "sims<-as.kernelMatrix(matrix(sims,1))"
+ LOGGER.debug "Predicting ..."
+ @r.eval "p<-predict(model,sims)[1,1]"
+ @prediction = 10**(@r.p.to_f)
+ LOGGER.debug "Prediction is: '" + prediction.to_s + "'."
+ @r.quit # free R
+ end
+ @confidence = conf/@neighbors.size if @neighbors.size > 0
+
end
- def save
- @features.uniq!
- resource = RestClient::Resource.new(CONFIG[:services]["opentox-model"])
- resource.post(self.to_yaml, :content_type => "application/x-yaml").chomp.to_s
+ def neighbors
+
+ @compound_features = eval(@feature_calculation_algorithm) if @feature_calculation_algorithm
+
+ @neighbors = {}
+ @activities.each do |training_compound,activities|
+ @training_compound = training_compound
+ sim = eval(@similarity_algorithm)
+ if sim > @min_sim
+ activities.each do |act|
+ @neighbors << {
+ :compound => @training_compound,
+ :similarity => sim,
+ :features => @fingerprints[@training_compound],
+ :activity => act
+ }
+ end
+ end
+ end
+
end
- def self.find_all
- RestClientWrapper.get(CONFIG[:services]["opentox-model"]).chomp.split("\n")
+ def tanimoto
+ OpenTox::Algorithm.tanimoto(@compound_features,@fingerprints[@training_compound])
end
- def self.predict(compound_uri,model_uri)
- #RestClientWrapper.post(model_uri,{:compound_uri => compound_uri, :accept => 'application/x-yaml'})
- `curl -X POST -d 'compound_uri=#{compound_uri}' -H 'Accept:application/x-yaml' #{model_uri}`
+ def weighted_tanimoto
+ OpenTox::Algorithm.tanimoto(@compound_features,@fingerprints[@training_compound],@p_values)
end
- end
-
- class PropertyLazar < Generic
-
- attr_accessor :feature_dataset_uri, :properties, :features, :activities#, :effects, :p_values
-
- def initialize
- @source = "http://github.com/helma/opentox-model"
- @algorithm = File.join(CONFIG[:services]["opentox-algorithm"],"property_lazar")
- #@independent_variables = File.join(CONFIG[:services]["opentox-algorithm"],"fminer#BBRC_representative")
- @features = []
- #@effects = {}
- @activities = {}
- #@p_values = {}
- @properties = {}
+
+ def euclid
+ OpenTox::Algorithm.tanimoto(@compound_features,@fingerprints[@training_compound])
+ end
+
+ def weighted_euclid
+ OpenTox::Algorithm.tanimoto(@compound_features,@fingerprints[@training_compound],@p_values)
+ end
+
+ def substructure_match
+ @compound.match(@features)
+ end
+
+ def database_search
+ #TODO add features method to dataset
+ Dataset.new(@metadata[OT.featureDataset]).features(@compound.uri)
+ end
+
+ def database_activity(compound_uri)
+ prediction = OpenTox::Dataset.new
+ # find database activities
+ if @activities[compound_uri]
+ @activities[compound_uri].each { |act| prediction.add compound_uri, @metadata[OT.dependentVariables], act }
+ prediction.add_metadata(OT.hasSource => @metadata[OT.trainingDataset])
+ prediction
+ else
+ nil
+ end
end
def save
- @features.uniq!
- resource = RestClient::Resource.new(CONFIG[:services]["opentox-model"])
- resource.post(self.to_yaml, :content_type => "application/x-yaml").chomp.to_s
+ RestClientWrapper.post(@uri,{:content_type => "application/x-yaml"},self.to_yaml)
end
- def self.find_all
- RestClientWrapper.get(CONFIG[:services]["opentox-model"]).chomp.split("\n")
+ def self.all
+ RestClientWrapper.get(CONFIG[:services]["opentox-model"]).to_s.split("\n")
end
- def self.predict(compound_uri,model_uri)
- #RestClientWrapper.post(model_uri,{:compound_uri => compound_uri, :accept => 'application/x-yaml'})
- `curl -X POST -d 'compound_uri=#{compound_uri}' -H 'Accept:application/x-yaml' #{model_uri}`
+ def delete
+ RestClientWrapper.delete @uri unless @uri == CONFIG[:services]["opentox-model"]
end
+
end
end
end
diff --git a/lib/opentox-ruby-api-wrapper.rb b/lib/opentox-ruby-api-wrapper.rb
index 2749899..9dc1372 100644
--- a/lib/opentox-ruby-api-wrapper.rb
+++ b/lib/opentox-ruby-api-wrapper.rb
@@ -8,6 +8,6 @@ rescue LoadError
puts "Please install Openbabel with 'rake openbabel:install' in the compound component"
end
-['opentox', 'compound','dataset', 'parser','serializer', 'algorithm','model','task','validation','utils','feature', 'ot-logger', 'overwrite', 'rest_client_wrapper'].each do |lib|
+['opentox', 'compound','dataset', 'parser','serializer', 'algorithm','model','task','validation','feature', 'ot-logger', 'overwrite', 'rest_client_wrapper'].each do |lib|
require lib
end
diff --git a/lib/opentox.rb b/lib/opentox.rb
index 453ca66..7e1deec 100644
--- a/lib/opentox.rb
+++ b/lib/opentox.rb
@@ -1,79 +1,49 @@
module OpenTox
- # Generic OpenTox class
- module OtObject
-
- attr_reader :uri
- attr_accessor :metadata
-
- # Initialize OpenTox object with optional uri
- def initialize(uri=nil)
- @metadata = {}
- self.uri = uri if uri
- end
-
- # Set URI
- def uri=(uri)
- @uri = uri
- @metadata[XSD.anyUri] = uri
- end
-
- # Get title
- def title
- load_metadata unless @metadata[DC.title]
- @metadata[DC.title]
- end
-
- # Set title
- def title=(title)
- @metadata[DC.title] = title
- end
-
- # Get all objects from a service
- def self.all(uri)
- #def OtObject.all(uri)
- RestClientWrapper.get(uri,:accept => "text/uri-list").to_s.split(/\n/)
- end
-
- # Load metadata from URI
- def load_metadata
- #if (CONFIG[:yaml_hosts].include?(URI.parse(@uri).host))
- # TODO: fix metadata retrie
- #@metadata = YAML.load(RestClientWrapper.get(@uri, :accept => "application/x-yaml"))
- #else
- @metadata = Parser::Owl::Generic.new(@uri).metadata
- #end
- @metadata
- #Parser::Owl::Generic.new(@uri).metadata
- end
-
+ attr_reader :uri
+ attr_accessor :metadata, :parameters
+
+ # Initialize OpenTox object with optional uri
+ # @param [optional, String] URI
+ def initialize(uri=nil)
+ @metadata = {}
+ self.uri = uri if uri
end
- module Owl
-
- class Namespace
-
- def initialize(uri)
- @uri = uri
- end
+ # Set URI
+ # @param [String] URI
+ def uri=(uri)
+ @uri = uri
+ @metadata[XSD.anyURI] = uri
+ end
- def [](property)
- @uri+property.to_s
- end
+ # Get all objects from a service
+ # @return [Array] List of available URIs
+ def self.all(uri)
+ RestClientWrapper.get(uri,:accept => "text/uri-list").to_s.split(/\n/)
+ end
- def method_missing(property)
- @uri+property.to_s
- end
+ # Load (and return) metadata from object URI
+ # @return [Hash] Metadata
+ def load_metadata
+ @metadata = Parser::Owl::Generic.new(@uri).metadata
+ @metadata
+ end
- end
+ # Load parameters from URI
+ #def load_parameters
+ #@parameters = Parser::Owl::Generic.new(@uri).parameters
+ #@parameters
+ #end
+
+ # Get OWL-DL representation in RDF/XML format
+ # @return [application/rdf+xml] RDF/XML representation
+ def to_rdfxml
+ s = Serializer::Owl.new
+ s.add_metadata(@uri,@metadata)
+ #s.add_parameters(@uri,@parameters) if @parameters
+ s.to_rdfxml
end
end
-#
-# OWL Namespaces
-RDF = OpenTox::Owl::Namespace.new 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'
-OWL = OpenTox::Owl::Namespace.new 'http://www.w3.org/2002/07/owl#'
-DC = OpenTox::Owl::Namespace.new 'http://purl.org/dc/elements/1.1/'
-OT = OpenTox::Owl::Namespace.new 'http://www.opentox.org/api/1.1#'
-XSD = OpenTox::Owl::Namespace.new 'http://www.w3.org/2001/XMLSchema#'
diff --git a/lib/overwrite.rb b/lib/overwrite.rb
index 1d0161b..2e4c396 100644
--- a/lib/overwrite.rb
+++ b/lib/overwrite.rb
@@ -12,3 +12,25 @@ class Sinatra::Base
end
end
+class String
+ def task_uri?
+ self.uri? && !self.match(/task/).nil?
+ end
+
+ def dataset_uri?
+ self.uri? && !self.match(/dataset/).nil?
+ end
+
+ def self.model_uri?
+ self.uri? && !self.match(/model/).nil?
+ end
+
+ def uri?
+ begin
+ u = URI::parse(self)
+ return (u.scheme!=nil and u.host!=nil)
+ rescue URI::InvalidURIError
+ return false
+ end
+ end
+end
diff --git a/lib/parser.rb b/lib/parser.rb
index e623bf5..8c173f9 100644
--- a/lib/parser.rb
+++ b/lib/parser.rb
@@ -1,5 +1,14 @@
require 'spreadsheet'
require 'roo'
+
+class String
+
+ def to_triple
+ self.chomp.split(' ',3).collect{|i| i.sub(/\s+.$/,'').gsub(/[<>"]/,'')}
+ end
+
+end
+
module OpenTox
module Parser
@@ -12,19 +21,28 @@ module OpenTox
end
def metadata
- # TODO: load parameters
+
if @dataset
uri = File.join(@uri,"metadata")
else
uri = @uri
end
+
statements = []
- `rapper -i rdfxml -o ntriples #{uri}`.each_line do |line|
- triple = line.chomp.split('> ')
- statements << triple.collect{|i| i.sub(/\s+.$/,'').gsub(/[<>"]/,'')}
- end
- statements.each do |triple|
+ parameter_ids = []
+ `rapper -i rdfxml -o ntriples #{uri} 2>/dev/null`.each_line do |line|
+ triple = line.to_triple
@metadata[triple[1]] = triple[2].split('^^').first if triple[0] == @uri and triple[1] != RDF['type']
+ statements << triple
+ parameter_ids << triple[2] if triple[1] == OT.parameters
+ end
+ unless parameter_ids.empty?
+ @metadata[OT.parameters] = []
+ parameter_ids.each do |p|
+ parameter = {}
+ statements.each{ |t| parameter[t[1]] = t[2] if t[0] == p and t[1] != RDF['type']}
+ @metadata[OT.parameters] << parameter
+ end
end
@metadata
end
@@ -37,6 +55,8 @@ module OpenTox
include Owl
+ attr_writer :uri
+
def initialize(uri)
super uri
@dataset = ::OpenTox::Dataset.new(@uri)
@@ -47,11 +67,10 @@ module OpenTox
feature_values = {}
feature = {}
other_statements = {}
- ntriples = `rapper -i rdfxml -o ntriples #{@uri}`
- ntriples.each_line do |line|
+ `rapper -i rdfxml -o ntriples #{@uri} 2>/dev/null`.each_line do |line|
triple = line.chomp.split(' ',3)
triple = triple[0..2].collect{|i| i.sub(/\s+.$/,'').gsub(/[<>"]/,'')}
- case triple[1] # Ambit namespaces are case insensitive
+ case triple[1]
when /#{OT.values}/i
data[triple[0]] = {:compound => "", :values => []} unless data[triple[0]]
data[triple[0]][:values] << triple[2]
@@ -77,76 +96,84 @@ module OpenTox
end
def load_features
- @dataset.features.keys.each do |feature|
- @dataset.features[feature] = Parser::Owl::Generic.new(feature).metadata
+ uri = File.join(@uri,"features")
+ statements = []
+ features = Set.new
+ `rapper -i rdfxml -o ntriples #{uri} 2>/dev/null`.each_line do |line|
+ triple = line.chomp.split('> ').collect{|i| i.sub(/\s+.$/,'').gsub(/[<>"]/,'')}[0..2]
+ statements << triple
+ features << triple[0] if triple[1] == RDF['type'] and triple[2] == OT.Feature
+ end
+ statements.each do |triple|
+ if features.include? triple[0]
+ @dataset.features[triple[0]] = {} unless @dataset.features[triple[0]]
+ @dataset.features[triple[0]][triple[1]] = triple[2].split('^^').first
+ end
end
+ @dataset.features
end
+
end
end
- class Spreadsheet
+ class Spreadsheets
+ # TODO: expand for multiple columns
+
+ attr_accessor :dataset
+ def initialize
+
+ # TODO: fix 2 datasets created
+ #@dataset = Dataset.create
+ #@dataset.save # get uri
+
+ @data = []
+ @features = []
+ @feature_types = {}
- def initialize(dataset)
- @dataset = dataset
@format_errors = ""
@smiles_errors = []
@activity_errors = []
@duplicates = {}
- @nr_compounds = 0
- @data = []
- @activities = []
- @type = "classification"
end
def load_excel(book)
book.default_sheet = 0
- 1.upto(book.last_row) do |row|
- if row == 1
- @feature = File.join(@dataset.uri,"feature",book.cell(row,2))
- else
- add( book.cell(row,1), book.cell(row,2), row ) # smiles, activity
- end
- end
- parse
+ add_features book.row(1)
+ 2.upto(book.last_row) { |i| add_values book.row(i) }
+ warnings
+ @dataset
end
def load_csv(csv)
row = 0
- csv.each_line do |line|
- row += 1
- raise "Invalid CSV format at line #{row}: #{line.chomp}" unless line.chomp.match(/^.+[,;].*$/) # check CSV format
- items = line.chomp.gsub(/["']/,'').split(/\s*[,;]\s*/) # remove quotes
- if row == 1
- @feature = File.join(@dataset.uri,"feature",items[1])
- else
- add(items[0], items[1], row)
- end
- end
- parse
+ input = csv.split("\n")
+ add_features split_row(input.shift)
+ input.each { |row| add_values split_row(row) }
+ warnings
+ @dataset
end
- def parse
+ private
- # create dataset
- @data.each do |items|
- case @type
- when "classification"
- case items[1].to_s
- when TRUE_REGEXP
- @dataset.add(items[0], @feature, true )
- when FALSE_REGEXP
- @dataset.add(items[0], @feature, false)
- end
- when "regression"
- if items[1].to_f == 0
- @activity_errors << "Row #{items[2]}: Zero values not allowed for regression datasets - entry ignored."
- else
- @dataset.add items[0], @feature, items[1].to_f
- end
+ def warnings
+
+ info = ''
+ @feature_types.each do |feature,types|
+ if types.uniq.size > 1
+ type = OT.NumericFeature
+ else
+ type = types.first
end
+ @dataset.add_feature_metadata(feature,{OT.isA => type})
+ info += "\"#{@dataset.feature_name(feature)}\" detected as #{type.split('#').last}."
+
+ # TODO: rewrite feature values
+ # TODO if value.to_f == 0 @activity_errors << "#{smiles} Zero values not allowed for regression datasets - entry ignored."
end
+ @dataset.metadata[OT.Info] = info
+
warnings = ''
warnings += "
" + @activity_errors.join(" ") unless @activity_errors.empty?
@@ -156,34 +183,75 @@ module OpenTox
@dataset.metadata[OT.Warnings] = warnings
- @dataset
+ end
+ def add_features(row)
+ row.shift # get rid of smiles entry
+ row.each do |feature_name|
+ feature_uri = File.join(@dataset.uri,"feature",URI.encode(feature_name))
+ @feature_types[feature_uri] = []
+ @features << feature_uri
+ @dataset.add_feature(feature_uri,{DC.title => feature_name})
+ end
end
- def add(smiles, act, row)
+ def add_values(row)
+
+ smiles = row.shift
compound = Compound.from_smiles(smiles)
if compound.nil? or compound.inchi.nil? or compound.inchi == ""
- @smiles_errors << "Row #{row}: " + [smiles,act].join(", ")
- return false
- end
- unless numeric?(act) or classification?(act)
- @activity_errors << "Row #{row}: " + [smiles,act].join(", ")
+ @smiles_errors << smiles+", "+row.join(", ")
return false
end
@duplicates[compound.inchi] = [] unless @duplicates[compound.inchi]
- @duplicates[compound.inchi] << "Row #{row}: " + [smiles, act].join(", ")
- @type = "regression" unless classification?(act)
- # TODO: set OT.NumericalFeature, ...
- @nr_compounds += 1
- @data << [ compound.uri, act , row ]
+ @duplicates[compound.inchi] << smiles+", "+row.join(", ")
+
+ row.each_index do |i|
+ value = row[i]
+ feature = @features[i]
+ type = feature_type(value)
+
+ @feature_types[feature] << type
+
+ case type
+ when OT.NominalFeature
+ case value.to_s
+ when TRUE_REGEXP
+ @dataset.add(compound.uri, feature, true )
+ when FALSE_REGEXP
+ @dataset.add(compound.uri, feature, false )
+ end
+ when OT.NumericFeature
+ @dataset.add compound.uri, feature, value.to_f
+ when OT.StringFeature
+ # TODO: insert ??
+ @dataset.add compound.uri, feature, value.to_s
+ @activity_errors << smiles+", "+row.join(", ")
+ #return false
+ end
+ end
+ end
+
+ def numeric?(value)
+ true if Float(value) rescue false
end
- def numeric?(object)
- true if Float(object) rescue false
+ def classification?(value)
+ !value.to_s.strip.match(TRUE_REGEXP).nil? or !value.to_s.strip.match(FALSE_REGEXP).nil?
+ end
+
+ def feature_type(value)
+ if classification? value
+ return OT.NominalFeature
+ elsif numeric? value
+ return OT.NumericFeature
+ else
+ return OT.StringFeature
+ end
end
- def classification?(object)
- !object.to_s.strip.match(TRUE_REGEXP).nil? or !object.to_s.strip.match(FALSE_REGEXP).nil?
+ def split_row(row)
+ row.chomp.gsub(/["']/,'').split(/\s*[,;]\s*/) # remove quotes
end
end
diff --git a/lib/rest_client_wrapper.rb b/lib/rest_client_wrapper.rb
index 82836d9..49549b5 100644
--- a/lib/rest_client_wrapper.rb
+++ b/lib/rest_client_wrapper.rb
@@ -1,5 +1,3 @@
-
-
module OpenTox
#PENDING: implement ot error api, move to own file
@@ -60,7 +58,7 @@ module OpenTox
def self.execute( rest_call, uri, headers, payload=nil, wait=true )
do_halt 400,"uri is null",uri,headers,payload unless uri
- do_halt 400,"not a uri",uri,headers,payload unless Utils.is_uri?(uri)
+ do_halt 400,"not a uri",uri,headers,payload unless uri.to_s.uri?
do_halt 400,"headers are no hash",uri,headers,payload unless headers==nil or headers.is_a?(Hash)
do_halt 400,"nil headers for post not allowed, use {}",uri,headers,payload if rest_call=="post" and headers==nil
headers.each{ |k,v| headers.delete(k) if v==nil } if headers #remove keys with empty values, as this can cause problems
@@ -115,7 +113,7 @@ module OpenTox
when /text\//
raise "uri list has more than one entry, should be a task" if res.content_type=~/text\/uri-list/ and
res.split("\n").size > 1 #if uri list contains more then one uri, its not a task
- task = OpenTox::Task.find(res.to_s) if Utils.task_uri?(res)
+ task = OpenTox::Task.find(res.to_s) if res.to_s.uri?
else
raise "unknown content-type for task: '"+res.content_type.to_s+"'" #+"' content: "+res[0..200].to_s
end
diff --git a/lib/serializer.rb b/lib/serializer.rb
index 3def252..3a9cb60 100644
--- a/lib/serializer.rb
+++ b/lib/serializer.rb
@@ -30,7 +30,6 @@ module OpenTox
OT.dataEntry => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
OT.acceptValue => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
OT.values => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
- #XSD.anyUri => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
OT.algorithm => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
OT.parameters => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
@@ -38,14 +37,15 @@ module OpenTox
DC.identifier => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
DC.contributor => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
DC.creator => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ DC.description => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
OT.isA => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.Warnings => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ XSD.anyURI => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
OT.hasSource => { RDF["type"] => [{ "type" => "uri", "value" => OWL.DatatypeProperty }] } ,
OT.value => { RDF["type"] => [{ "type" => "uri", "value" => OWL.DatatypeProperty }] } ,
OT.paramScope => { RDF["type"] => [{ "type" => "uri", "value" => OWL.DatatypeProperty }] } ,
OT.paramValue => { RDF["type"] => [{ "type" => "uri", "value" => OWL.DatatypeProperty }] } ,
-
- #Untyped Individual: http://localhost/algorithm
}
@data_entries = {}
@@ -61,15 +61,10 @@ module OpenTox
end
def add_compound(uri)
- #@classes << OT.Compound unless @classes.include? OT.Compound
@object[uri] = { RDF["type"] => [{ "type" => "uri", "value" => OT.Compound }] }
end
def add_feature(uri,metadata)
- #@classes << OT.Feature unless @classes.include? OT.Feature
- #@classes << OT.NominalFeature unless @classes.include? OT.NominalFeature
- #@classes << OT.NumericFeature unless @classes.include? OT.NumericFeature
- #@classes << OT.StringFeature unless @classes.include? OT.StringFeature
@object[uri] = { RDF["type"] => [{ "type" => "uri", "value" => OT.Feature }] }
add_metadata uri, metadata
end
@@ -94,32 +89,37 @@ module OpenTox
end
- def add_algorithm(uri,metadata,parameters)
+ def add_algorithm(uri,metadata)
@object[uri] = { RDF["type"] => [{ "type" => "uri", "value" => OT.Algorithm }] }
+ LOGGER.debug @object[uri]
add_metadata uri, metadata
- add_parameters uri, parameters
- #metadata.each { |u,v| @object[uri][u] = [{"type" => type(v), "value" => v }] }
+ LOGGER.debug @object[uri]
end
- def add_model(uri,metadata)
+ def add_model(uri,metadata,parameters)
+ @object[uri] = { RDF["type"] => [{ "type" => "uri", "value" => OT.Model }] }
+ add_metadata uri, metadata
+ add_parameters uri, parameters
end
def add_metadata(uri,metadata)
- #@object[uri] = { RDF["type"] => [{ "type" => "uri", "value" => OT[type] }] }
+ id = 0
metadata.each do |u,v|
- @object[uri][u] = [{"type" => type(v), "value" => v }]
- end
- end
-
- def add_parameters(uri,parameters)
- #@object[uri] = { RDF["type"] => [{ "type" => "uri", "value" => OT[type] }] }
- @object[uri][OT.parameters] = [] unless @object[uri][OT.parameters]
- parameters.each do |p|
- parameter = "_:parameter#{@parameter_id}"
- @parameter_id += 1
- @object[uri][OT.parameters] << {"type" => "bnode", "value" => parameter}
- @object[parameter] = { RDF["type"] => [{ "type" => "uri", "value" => OT.Parameter }] }
- add_metadata parameter, p
+ if v.is_a? String
+ @object[uri] = {} unless @object[uri]
+ @object[uri][u] = [{"type" => type(v), "value" => v }]
+ elsif v.is_a? Array and u == OT.parameters
+ @object[uri][u] = [] unless @object[uri][u]
+ v.each do |value|
+ id+=1
+ genid = "_:genid#{id}"
+ @object[uri][u] << {"type" => "bnode", "value" => genid}
+ @object[genid] = { RDF["type"] => [{ "type" => "uri", "value" => OT.Parameter}] }
+ value.each do |name,entry|
+ @object[genid][name] = [{"type" => type(entry), "value" => entry }]
+ end
+ end
+ end
end
end
@@ -158,10 +158,11 @@ module OpenTox
# Serializers
- def ntriples
+ def to_ntriples
#rdf_types
@triples = Set.new
+ #LOGGER.debug @object.to_yaml
@object.each do |s,entry|
s = url(s) if type(s) == "uri"
entry.each do |p,objects|
@@ -182,12 +183,12 @@ module OpenTox
@triples.sort.collect{ |s| s.join(' ').concat(" .") }.join("\n")+"\n"
end
- def rdfxml
- Tempfile.open("owl-serializer"){|f| f.write(ntriples); @path = f.path}
- `rapper -i ntriples -o rdfxml #{@path}`
+ def to_rdfxml
+ Tempfile.open("owl-serializer"){|f| f.write(self.to_ntriples); @path = f.path}
+ `rapper -i ntriples -o rdfxml #{@path} 2>/dev/null`
end
- def json
+ def to_json
#rdf_types
Yajl::Encoder.encode(@object)
end
@@ -258,7 +259,7 @@ module OpenTox
@rows.first << features
@rows.first.flatten!
dataset.data_entries.each do |compound,entries|
- smiles = Compound.new(compound).smiles
+ smiles = Compound.new(compound).to_smiles
row = Array.new(@rows.first.size)
row[0] = smiles
entries.each do |feature, values|
@@ -271,11 +272,11 @@ module OpenTox
end
end
- def csv
+ def to_csv
@rows.collect{|r| r.join(", ")}.join("\n")
end
- def excel
+ def to_xls
Spreadsheet.client_encoding = 'UTF-8'
book = Spreadsheet::Workbook.new
sheet = book.create_worksheet(:name => '')
diff --git a/lib/task.rb b/lib/task.rb
index 50f0347..96ee719 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -3,6 +3,7 @@ $self_task=nil
module OpenTox
class Task
+ attr_accessor :uri, :date, :title, :creator, :description, :hasStatus, :percentageCompleted, :resultURI, :due_to_time, :http_code
# due_to_time is only set in local tasks
TASK_ATTRIBS = [ :uri, :date, :title, :creator, :description, :hasStatus, :percentageCompleted, :resultURI, :due_to_time ]
@@ -124,14 +125,14 @@ module OpenTox
def check_state
begin
raise "illegal task state, task is completed, resultURI is no URI: '"+@resultURI.to_s+
- "'" unless @resultURI and Utils.is_uri?(@resultURI) if completed?
+ "'" unless @resultURI and @resultURI.to_s.uri? if completed?
if @http_code == 202
raise "illegal task state, code is 202, but hasStatus is not Running: '"+@hasStatus+"'" unless running?
elsif @http_code == 201
raise "illegal task state, code is 201, but hasStatus is not Completed: '"+@hasStatus+"'" unless completed?
raise "illegal task state, code is 201, resultURI is no task-URI: '"+@resultURI.to_s+
- "'" unless @resultURI and Utils.task_uri?(@resultURI)
+ "'" unless @resultURI and @resultURI.to_s.uri?
end
rescue => ex
RestClientWrapper.raise_uri_error(ex.message, @uri)
@@ -171,6 +172,7 @@ module OpenTox
LOGGER.debug "Started task: "+task.uri.to_s
task.uri
end
+
end
end
diff --git a/lib/utils.rb b/lib/utils.rb
deleted file mode 100644
index a0e0cbe..0000000
--- a/lib/utils.rb
+++ /dev/null
@@ -1,50 +0,0 @@
-module OpenTox
- module Utils
- # gauss kernel
- def self.gauss(sim, sigma = 0.3)
- x = 1.0 - sim
- Math.exp(-(x*x)/(2*sigma*sigma))
- end
-
- def self.task_uri?(uri)
- is_uri?(uri) && uri.to_s =~ /task/
- end
-
- def self.dataset_uri?(uri)
- is_uri?(uri) && uri.to_s =~ /dataset/
- end
-
- def self.model_uri?(uri)
- is_uri?(uri) && uri.to_s =~ /model/
- end
-
-
- def self.is_uri?(uri)
- return false if uri==nil || uri.to_s.size==0
- begin
- u = URI::parse(uri)
- return (u.scheme!=nil and u.host!=nil)
- rescue URI::InvalidURIError
- return false
- end
- end
-
- def self.median(array)
- return nil if array.empty?
- array.sort!
- m_pos = array.size / 2
- return array.size % 2 == 1 ? array[m_pos] : (array[m_pos-1] + array[m_pos])/2
- end
-
- end
-
-# ['rubygems', 'rest_client'].each do |r|
-# require r
-# end
-# ["bla", "google.de", "http://google.de"].each do |u|
-# puts u+"? "+Utils.is_uri?(u).to_s
-# end
-
-
-end
-
--
cgit v1.2.3
From 91c95f8dc8f60a8f0029b970ef881eecee28401b Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Thu, 11 Nov 2010 10:42:48 +0100
Subject: Documentation and API fixes for serializer and parser
---
lib/dataset.rb | 10 +++++-----
lib/opentox.rb | 2 +-
lib/parser.rb | 45 +++++++++++++++++++++++++++++++++++++--------
lib/serializer.rb | 37 +++++++++++++++++++++++++++++++++----
4 files changed, 76 insertions(+), 18 deletions(-)
(limited to 'lib')
diff --git a/lib/dataset.rb b/lib/dataset.rb
index 05b2ed3..6e270e9 100644
--- a/lib/dataset.rb
+++ b/lib/dataset.rb
@@ -77,7 +77,7 @@ module OpenTox
parser.load_csv(csv)
end
- # Load Spreadsheet book (created with roo gem http://roo.rubyforge.org/, excel format specification: http://toxcreate.org/help))
+ # Load Spreadsheet book (created with roo gem http://roo.rubyforge.org/, excel format specification: http://toxcreate.org/help)
# - loads data_entries, compounds, features
# - sets metadata (warnings) for parser errors
# - you will have to set remaining metadata manually
@@ -87,13 +87,13 @@ module OpenTox
save unless @uri # get a uri for creating features
parser = Parser::Spreadsheets.new
parser.dataset = self
- parser.load_excel(book)
+ parser.load_spreadsheet(book)
end
# Load and return only metadata of a Dataset object
# @return [Hash] Metadata of the dataset
def load_metadata
- add_metadata Parser::Owl::Dataset.new(@uri).metadata
+ add_metadata Parser::Owl::Dataset.new(@uri).load_metadata
self.uri = @uri if @uri # keep uri
@metadata
end
@@ -147,8 +147,8 @@ module OpenTox
# Get Excel representation
# @return [Spreadsheet::Workbook] Workbook which can be written with the spreadsheet gem (data_entries only, metadata will will be discarded))
- def to_xls
- Serializer::Spreadsheets.new(self).to_xls
+ def to_spreadsheet
+ Serializer::Spreadsheets.new(self).to_spreadsheet
end
# Get CSV string representation (data_entries only, metadata will be discarded)
diff --git a/lib/opentox.rb b/lib/opentox.rb
index 7e1deec..3b7fa65 100644
--- a/lib/opentox.rb
+++ b/lib/opentox.rb
@@ -26,7 +26,7 @@ module OpenTox
# Load (and return) metadata from object URI
# @return [Hash] Metadata
def load_metadata
- @metadata = Parser::Owl::Generic.new(@uri).metadata
+ @metadata = Parser::Owl::Generic.new(@uri).load_metadata
@metadata
end
diff --git a/lib/parser.rb b/lib/parser.rb
index 8c173f9..4d8e729 100644
--- a/lib/parser.rb
+++ b/lib/parser.rb
@@ -3,6 +3,8 @@ require 'roo'
class String
+ # Split RDF statement into triples
+ # @return [Array] Array with [subject,predicate,object]
def to_triple
self.chomp.split(' ',3).collect{|i| i.sub(/\s+.$/,'').gsub(/[<>"]/,'')}
end
@@ -11,16 +13,23 @@ end
module OpenTox
+ # Parser for various input formats
module Parser
+ # OWL-DL parser
module Owl
+ # Create a new OWL-DL parser
+ # @param uri URI of OpenTox object
+ # @return [OpenTox::Parser::Owl] OWL-DL parser
def initialize(uri)
@uri = uri
@metadata = {}
end
- def metadata
+ # Read metadata from opentox service
+ # @return [Hash] Object metadata
+ def load_metadata
if @dataset
uri = File.join(@uri,"metadata")
@@ -47,21 +56,37 @@ module OpenTox
@metadata
end
+ # Generic parser for all OpenTox classes
class Generic
include Owl
end
+ # OWL-DL parser for datasets
class Dataset
include Owl
attr_writer :uri
+ # Create a new OWL-DL dataset parser
+ # @param uri Dataset URI
+ # @return [OpenTox::Parser::Owl::Dataset] OWL-DL parser
def initialize(uri)
super uri
@dataset = ::OpenTox::Dataset.new(@uri)
end
+ # Read data from dataset service. Files can be parsed by setting #uri to a filename (after initialization with a real URI)
+ # @example Read data from an external service
+ # parser = OpenTox::Parser::Owl::Dataaset.new "http://wwbservices.in-silico.ch/dataset/1"
+ # dataset = parser.load_uri
+ # @example Create dataset from RDF/XML file
+ # dataset = OpenTox::Dataset.create
+ # parser = OpenTox::Parser::Owl::Dataaset.new dataset.uri
+ # parser.uri = "dataset.rdfxml" # insert your input file
+ # dataset = parser.load_uri
+ # dataset.save
+ # @return [Hash] Internal dataset representation
def load_uri
data = {}
feature_values = {}
@@ -95,6 +120,8 @@ module OpenTox
@dataset
end
+ # Read only features from a dataset service.
+ # @return [Hash] Internal features representation
def load_features
uri = File.join(@uri,"features")
statements = []
@@ -117,16 +144,12 @@ module OpenTox
end
+ # Parser for getting spreadsheet data into a dataset
class Spreadsheets
- # TODO: expand for multiple columns
attr_accessor :dataset
- def initialize
-
- # TODO: fix 2 datasets created
- #@dataset = Dataset.create
- #@dataset.save # get uri
+ def initialize
@data = []
@features = []
@feature_types = {}
@@ -137,7 +160,10 @@ module OpenTox
@duplicates = {}
end
- def load_excel(book)
+ # Load Spreadsheet book (created with roo gem http://roo.rubyforge.org/, excel format specification: http://toxcreate.org/help)
+ # @param [Excel] book Excel workbook object (created with roo gem)
+ # @return [OpenTox::Dataset] Dataset object with Excel data
+ def load_spreadsheet(book)
book.default_sheet = 0
add_features book.row(1)
2.upto(book.last_row) { |i| add_values book.row(i) }
@@ -145,6 +171,9 @@ module OpenTox
@dataset
end
+ # Load CSV string (format specification: http://toxcreate.org/help)
+ # @param [String] csv CSV representation of the dataset
+ # @return [OpenTox::Dataset] Dataset object with CSV data
def load_csv(csv)
row = 0
input = csv.split("\n")
diff --git a/lib/serializer.rb b/lib/serializer.rb
index 3a9cb60..31aa0d1 100644
--- a/lib/serializer.rb
+++ b/lib/serializer.rb
@@ -3,9 +3,10 @@ require 'yajl'
module OpenTox
+ # Serialzer for various oputput formats
module Serializer
- # modelled according to to http://n2.talis.com/wiki/RDF_JSON_Specification
+ # OWL-DL Serializer, modelled according to to http://n2.talis.com/wiki/RDF_JSON_Specification
class Owl
attr_accessor :object
@@ -60,15 +61,21 @@ module OpenTox
@objects = Set.new
end
+ # Add a compound
+ # @param [String] uri Compound URI
def add_compound(uri)
@object[uri] = { RDF["type"] => [{ "type" => "uri", "value" => OT.Compound }] }
end
+ # Add a feature
+ # @param [String] uri Feature URI
def add_feature(uri,metadata)
@object[uri] = { RDF["type"] => [{ "type" => "uri", "value" => OT.Feature }] }
add_metadata uri, metadata
end
+ # Add a dataset
+ # @param [String] uri Dataset URI
def add_dataset(dataset)
@dataset = dataset.uri
@@ -89,6 +96,8 @@ module OpenTox
end
+ # Add a algorithm
+ # @param [String] uri Algorithm URI
def add_algorithm(uri,metadata)
@object[uri] = { RDF["type"] => [{ "type" => "uri", "value" => OT.Algorithm }] }
LOGGER.debug @object[uri]
@@ -96,12 +105,16 @@ module OpenTox
LOGGER.debug @object[uri]
end
+ # Add a model
+ # @param [String] uri Model URI
def add_model(uri,metadata,parameters)
@object[uri] = { RDF["type"] => [{ "type" => "uri", "value" => OT.Model }] }
add_metadata uri, metadata
add_parameters uri, parameters
end
+ # Add metadata
+ # @param [Hash] metadata
def add_metadata(uri,metadata)
id = 0
metadata.each do |u,v|
@@ -123,6 +136,10 @@ module OpenTox
end
end
+ # Add a data entry
+ # @param [String] compound Compound URI
+ # @param [String] feature Feature URI
+ # @param [Boolead,Float] value Feature value
def add_data_entry(compound,feature,value)
add_compound(compound) unless @object[compound]
add_feature(feature,{}) unless @object[feature]
@@ -158,11 +175,11 @@ module OpenTox
# Serializers
+ # Convert to N-Triples
+ # @return [text/plain] Object OWL-DL in N-Triples format
def to_ntriples
- #rdf_types
@triples = Set.new
- #LOGGER.debug @object.to_yaml
@object.each do |s,entry|
s = url(s) if type(s) == "uri"
entry.each do |p,objects|
@@ -183,11 +200,16 @@ module OpenTox
@triples.sort.collect{ |s| s.join(' ').concat(" .") }.join("\n")+"\n"
end
+ # Convert to RDF/XML
+ # @return [text/plain] Object OWL-DL in RDF/XML format
def to_rdfxml
Tempfile.open("owl-serializer"){|f| f.write(self.to_ntriples); @path = f.path}
`rapper -i ntriples -o rdfxml #{@path} 2>/dev/null`
end
+ # Convert to JSON as specified in http://n2.talis.com/wiki/RDF_JSON_Specification
+ # (Ambit services use a different JSON representation)
+ # @return [text/plain] Object OWL-DL in JSON format
def to_json
#rdf_types
Yajl::Encoder.encode(@object)
@@ -250,8 +272,11 @@ module OpenTox
end
+ # Serializer for spreadsheet formats
class Spreadsheets # to avoid nameclash with Spreadsheet gem
+ # Create a new spreadsheet serializer
+ # @param [OpenTox::Dataset] dataset Dataset object
def initialize(dataset)
@rows = []
@rows << ["SMILES"]
@@ -272,11 +297,15 @@ module OpenTox
end
end
+ # Convert to CSV string
+ # @return [String] CSV string
def to_csv
@rows.collect{|r| r.join(", ")}.join("\n")
end
- def to_xls
+ # Convert to spreadsheet workbook
+ # @return [Spreadsheet::Workbook] Workbook object (use the spreadsheet gemc to write a file)
+ def to_spreadsheet
Spreadsheet.client_encoding = 'UTF-8'
book = Spreadsheet::Workbook.new
sheet = book.create_worksheet(:name => '')
--
cgit v1.2.3
From f8552611c2dbe25d76474f51e4e895bf9c2b5c5e Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Fri, 19 Nov 2010 16:53:21 +0100
Subject: lazar predictions for toxcreate working
---
lib/algorithm.rb | 154 +++++++++++--
lib/dataset.rb | 72 ++++++-
lib/environment.rb | 8 +-
lib/feature.rb | 10 +
lib/model.rb | 466 ++++++++++++++++------------------------
lib/opentox-ruby-api-wrapper.rb | 4 +-
lib/opentox.rb | 10 +-
lib/ot-logger.rb | 48 -----
lib/overwrite.rb | 50 +++++
lib/parser.rb | 4 +-
lib/rest_client_wrapper.rb | 16 +-
lib/serializer.rb | 23 +-
lib/task.rb | 278 +++++++++++++++---------
lib/validation.rb | 64 +++++-
14 files changed, 720 insertions(+), 487 deletions(-)
delete mode 100644 lib/ot-logger.rb
(limited to 'lib')
diff --git a/lib/algorithm.rb b/lib/algorithm.rb
index 711f63b..a6fa4a7 100644
--- a/lib/algorithm.rb
+++ b/lib/algorithm.rb
@@ -1,3 +1,9 @@
+# R integration
+# workaround to initialize R non-interactively (former rinruby versions did this by default)
+# avoids compiling R with X
+R = nil
+require "rinruby"
+
module OpenTox
# Wrapper for OpenTox Algorithms
@@ -6,8 +12,10 @@ module OpenTox
include OpenTox
# Execute algorithm with parameters, please consult the OpenTox API and the webservice documentation for acceptable parameters
+ # @param [optional,Hash] params Algorithm parameters
+ # @return [String] URI of new resource (dataset, model, ...)
def run(params=nil)
- RestClientWrapper.post(@uri, params)
+ RestClientWrapper.post(@uri, params).to_s
end
# Get OWL-DL representation in RDF/XML format
@@ -23,9 +31,11 @@ module OpenTox
include Algorithm
end
+ # Fminer algorithms (https://github.com/amaunz/fminer2)
module Fminer
include Algorithm
+ # Backbone Refinement Class mining (http://bbrc.maunz.de/)
class BBRC
include Fminer
# Initialize bbrc algorithm
@@ -35,6 +45,7 @@ module OpenTox
end
end
+ # LAtent STructure Pattern Mining (http://last-pm.maunz.de)
class LAST
include Fminer
# Initialize last algorithm
@@ -58,15 +69,15 @@ module OpenTox
# Utility methods without dedicated webservices
+ # Similarity calculations
module Similarity
include Algorithm
# Tanimoto similarity
- #
# @param [Array] features_a Features of first compound
# @param [Array] features_b Features of second compound
# @param [optional, Hash] weights Weights for all features
- # @return [Float] (Wighted) tanimoto similarity
+ # @return [Float] (Weighted) tanimoto similarity
def self.tanimoto(features_a,features_b,weights=nil)
common_features = features_a & features_b
all_features = (features_a + features_b).uniq
@@ -86,15 +97,19 @@ module OpenTox
end
# Euclidean similarity
- def self.euclidean(prop_a,prop_b,weights=nil)
- common_properties = prop_a.keys & prop_b.keys
+ # @param [Hash] properties_a Properties of first compound
+ # @param [Hash] properties_b Properties of second compound
+ # @param [optional, Hash] weights Weights for all properties
+ # @return [Float] (Weighted) euclidean similarity
+ def self.euclidean(properties_a,properties_b,weights=nil)
+ common_properties = properties_a.keys & properties_b.keys
if common_properties.size > 1
dist_sum = 0
common_properties.each do |p|
if weights
- dist_sum += ( (prop_a[p] - prop_b[p]) * Algorithm.gauss(weights[p]) )**2
+ dist_sum += ( (properties_a[p] - properties_b[p]) * Algorithm.gauss(weights[p]) )**2
else
- dist_sum += (prop_a[p] - prop_b[p])**2
+ dist_sum += (properties_a[p] - properties_b[p])**2
end
end
1/(1+Math.sqrt(dist_sum))
@@ -103,14 +118,129 @@ module OpenTox
end
end
end
+
+ module Neighbors
+
+ # Classification with majority vote from neighbors weighted by similarity
+ # @param [Array] neighbors, each neighbor is a hash with keys `:similarity, :activity`
+ # @param [optional] params Ignored (only for compatibility with local_svm_regression)
+ # @return [Hash] Hash with keys `:prediction, :confidence`
+ def self.weighted_majority_vote(neighbors,params={})
+ conf = 0.0
+ confidence = 0.0
+ neighbors.each do |neighbor|
+ case neighbor[:activity].to_s
+ when 'true'
+ conf += Algorithm.gauss(neighbor[:similarity])
+ when 'false'
+ conf -= Algorithm.gauss(neighbor[:similarity])
+ end
+ end
+ if conf > 0.0
+ prediction = true
+ elsif conf < 0.0
+ prediction = false
+ else
+ prediction = nil
+ end
+ confidence = conf/neighbors.size if neighbors.size > 0
+ {:prediction => prediction, :confidence => confidence.abs}
+ end
+
+ # Local support vector regression from neighbors
+ # @param [Array] neighbors, each neighbor is a hash with keys `:similarity, :activity, :features`
+ # @param [Hash] params Keys `:similarity_algorithm,:p_values` are required
+ # @return [Hash] Hash with keys `:prediction, :confidence`
+ def self.local_svm_regression(neighbors,params )
+ sims = neighbors.collect{ |n| n[:similarity] } # similarity values between query and neighbors
+ conf = sims.inject{|sum,x| sum + x }
+ acts = neighbors.collect do |n|
+ act = n[:activity]
+ Math.log10(act.to_f)
+ end # activities of neighbors for supervised learning
+
+ neighbor_matches = neighbors.collect{ |n| n[:features] } # as in classification: URIs of matches
+ gram_matrix = [] # square matrix of similarities between neighbors; implements weighted tanimoto kernel
+ if neighbor_matches.size == 0
+ raise "No neighbors found"
+ else
+ # gram matrix
+ (0..(neighbor_matches.length-1)).each do |i|
+ gram_matrix[i] = [] unless gram_matrix[i]
+ # upper triangle
+ ((i+1)..(neighbor_matches.length-1)).each do |j|
+ sim = eval("#{params[:similarity_algorithm]}(neighbor_matches[i], neighbor_matches[j], params[:p_values])")
+ gram_matrix[i][j] = Algorithm.gauss(sim)
+ gram_matrix[j] = [] unless gram_matrix[j]
+ gram_matrix[j][i] = gram_matrix[i][j] # lower triangle
+ end
+ gram_matrix[i][i] = 1.0
+ end
+
+ LOGGER.debug gram_matrix.to_yaml
+
+ @r = RinRuby.new(false,false) # global R instance leads to Socket errors after a large number of requests
+ @r.eval "library('kernlab')" # this requires R package "kernlab" to be installed
+ LOGGER.debug "Setting R data ..."
+ # set data
+ @r.gram_matrix = gram_matrix.flatten
+ @r.n = neighbor_matches.size
+ @r.y = acts
+ @r.sims = sims
+
+ LOGGER.debug "Preparing R data ..."
+ # prepare data
+ @r.eval "y<-as.vector(y)"
+ @r.eval "gram_matrix<-as.kernelMatrix(matrix(gram_matrix,n,n))"
+ @r.eval "sims<-as.vector(sims)"
+
+ # model + support vectors
+ LOGGER.debug "Creating SVM model ..."
+ @r.eval "model<-ksvm(gram_matrix, y, kernel=matrix, type=\"nu-svr\", nu=0.8)"
+ @r.eval "sv<-as.vector(SVindex(model))"
+ @r.eval "sims<-sims[sv]"
+ @r.eval "sims<-as.kernelMatrix(matrix(sims,1))"
+ LOGGER.debug "Predicting ..."
+ @r.eval "p<-predict(model,sims)[1,1]"
+ prediction = 10**(@r.p.to_f)
+ LOGGER.debug "Prediction is: '" + @prediction.to_s + "'."
+ @r.quit # free R
+ end
+ confidence = conf/neighbors.size if neighbors.size > 0
+ {:prediction => prediction, :confidence => confidence}
+
+ end
+
+ end
+
+ module Substructure
+ include Algorithm
+ # Substructure matching
+ # @param [OpenTox::Compound] compound Compound
+ # @param [Array] features Array with Smarts strings
+ # @return [Array] Array with matching Smarts
+ def self.match(compound,features)
+ compound.match(features)
+ end
+ end
+
+ module Dataset
+ include Algorithm
+ # API should match Substructure.match
+ def features(dataset_uri,compound_uri)
+ end
+ end
- # Gauss kernel
- def self.gauss(sim, sigma = 0.3)
- x = 1.0 - sim
- Math.exp(-(x*x)/(2*sigma*sigma))
- end
+ # Gauss kernel
+ # @return [Float]
+ def self.gauss(x, sigma = 0.3)
+ d = 1.0 - x
+ Math.exp(-(d*d)/(2*sigma*sigma))
+ end
# Median of an array
+ # @param [Array] Array with values
+ # @return [Float] Median
def self.median(array)
return nil if array.empty?
array.sort!
diff --git a/lib/dataset.rb b/lib/dataset.rb
index 6e270e9..4737ea1 100644
--- a/lib/dataset.rb
+++ b/lib/dataset.rb
@@ -43,7 +43,7 @@ module OpenTox
# Get all datasets from a service
# @param [optional,String] uri URI of the dataset service, defaults to service specified in configuration
- # @return [Array] Array of dataset object with all data
+ # @return [Array] Array of dataset object without data (use one of the load_* methods to pull data from the server)
def self.all(uri=CONFIG[:services]["opentox-dataset"])
RestClientWrapper.get(uri,:accept => "text/uri-list").to_s.each_line.collect{|u| Dataset.new(u)}
end
@@ -55,6 +55,10 @@ module OpenTox
copy YAML.load(yaml)
end
+ def load_rdfxml(rdfxml)
+ load_rdfxml_file Tempfile.open("ot-rdfxml"){|f| f.write(rdfxml)}.path
+ end
+
# Load RDF/XML representation from a file
# @param [String] file File with RDF/XML representation of the dataset
# @return [OpenTox::Dataset] Dataset object with RDF/XML data
@@ -129,8 +133,6 @@ module OpenTox
# @return [String] `classification", "regression", "mixed" or unknown`
def feature_type
feature_types = @features.collect{|f,metadata| metadata[OT.isA]}.uniq
- LOGGER.debug "FEATURES"
- LOGGER.debug feature_types.inspect
if feature_types.size > 1
"mixed"
else
@@ -145,12 +147,18 @@ module OpenTox
end
end
- # Get Excel representation
+ # Get Spreadsheet representation
# @return [Spreadsheet::Workbook] Workbook which can be written with the spreadsheet gem (data_entries only, metadata will will be discarded))
def to_spreadsheet
Serializer::Spreadsheets.new(self).to_spreadsheet
end
+ # Get Excel representation (alias for to_spreadsheet)
+ # @return [Spreadsheet::Workbook] Workbook which can be written with the spreadsheet gem (data_entries only, metadata will will be discarded))
+ def to_xls
+ to_spreadsheet
+ end
+
# Get CSV string representation (data_entries only, metadata will be discarded)
# @return [String] CSV representation
def to_csv
@@ -180,6 +188,10 @@ module OpenTox
@features[feature][DC.title]
end
+ def title
+ @metadata[DC.title]
+ end
+
# Insert a statement (compound_uri,feature_uri,value)
# @example Insert a statement (compound_uri,feature_uri,value)
# dataset.add "http://webservices.in-silico.ch/compound/InChI=1S/C6Cl6/c7-1-2(8)4(10)6(12)5(11)3(1)9", "http://webservices.in-silico.ch/dataset/1/feature/hamster_carcinogenicity", true
@@ -224,11 +236,18 @@ module OpenTox
# TODO: rewrite feature URI's ??
@compounds.uniq!
if @uri
- RestClientWrapper.post(@uri,{:content_type => "application/x-yaml"},self.to_yaml)
+ if (CONFIG[:yaml_hosts].include?(URI.parse(@uri).host))
+ RestClientWrapper.post(@uri,{:content_type => "application/x-yaml"},self.to_yaml)
+ else
+ File.open("ot-post-file.rdf","w+") { |f| f.write(self.to_rdfxml); @path = f.path }
+ task_uri = RestClient.post(@uri, {:file => File.new(@path)},{:accept => "text/uri-list"}).to_s.chomp
+ #task_uri = `curl -X POST -H "Accept:text/uri-list" -F "file=@#{@path};type=application/rdf+xml" http://apps.ideaconsult.net:8080/ambit2/dataset`
+ Task.find(task_uri).wait_for_completion
+ self.uri = RestClientWrapper.get(task_uri,:accept => 'text/uri-list')
+ end
else
# create dataset if uri is empty
self.uri = RestClientWrapper.post(CONFIG[:services]["opentox-dataset"],{}).to_s.chomp
- RestClientWrapper.post(@uri,{:content_type => "application/x-yaml"},self.to_yaml)
end
@uri
end
@@ -252,4 +271,45 @@ module OpenTox
end
end
end
+
+ # Class with special methods for lazar prediction datasets
+ class LazarPrediction < Dataset
+
+ # Find a prediction dataset and load all data.
+ # @param [String] uri Prediction dataset URI
+ # @return [OpenTox::Dataset] Prediction dataset object with all data
+ def self.find(uri)
+ prediction = LazarPrediction.new(uri)
+ prediction.load_all
+ prediction
+ end
+
+ def value(compound)
+ @data_entries[compound.uri].collect{|f,v| v.first if f.match(/prediction/)}.compact.first
+ end
+
+ def confidence(compound)
+ feature_uri = @data_entries[compound.uri].collect{|f,v| f if f.match(/prediction/)}.compact.first
+ @features[feature_uri][OT.confidence]
+ end
+
+ def descriptors(compound)
+ @data_entries[compound.uri].collect{|f,v| @features[f] if f.match(/descriptor/)}.compact if @data_entries[compound.uri]
+ end
+
+ def measured_activities(compound)
+ source = @metadata[OT.hasSource]
+ @data_entries[compound.uri].collect{|f,v| v if f.match(/#{source}/)}.compact
+ end
+
+ def neighbors(compound)
+ @data_entries[compound.uri].collect{|f,v| @features[f] if f.match(/neighbor/)}.compact
+ end
+
+# def errors(compound)
+# features = @data_entries[compound.uri].keys
+# features.collect{|f| @features[f][OT.error]}.join(" ") if features
+# end
+
+ end
end
diff --git a/lib/environment.rb b/lib/environment.rb
index d66b062..4f1cc80 100644
--- a/lib/environment.rb
+++ b/lib/environment.rb
@@ -1,4 +1,3 @@
-require "ot-logger"
# set default environment
ENV['RACK_ENV'] = 'production' unless ENV['RACK_ENV']
@@ -45,8 +44,8 @@ end
load File.join config_dir,"mail.rb" if File.exists?(File.join config_dir,"mail.rb")
logfile = "#{LOG_DIR}/#{ENV["RACK_ENV"]}.log"
-#LOGGER = MyLogger.new(logfile,'daily') # daily rotation
-LOGGER = MyLogger.new(logfile) # no rotation
+#LOGGER = OTLogger.new(logfile,'daily') # daily rotation
+LOGGER = OTLogger.new(logfile) # no rotation
LOGGER.formatter = Logger::Formatter.new #this is neccessary to restore the formating in case active-record is loaded
if CONFIG[:logger] and CONFIG[:logger] == "debug"
LOGGER.level = Logger::DEBUG
@@ -60,11 +59,12 @@ FALSE_REGEXP = /^(false|inactive|0|0.0)$/i
# Task durations
DEFAULT_TASK_MAX_DURATION = 36000
-EXTERNAL_TASK_MAX_DURATION = 36000
+#EXTERNAL_TASK_MAX_DURATION = 36000
# OWL Namespaces
class OwlNamespace
+ attr_accessor :uri
def initialize(uri)
@uri = uri
end
diff --git a/lib/feature.rb b/lib/feature.rb
index 13d97a2..9e28077 100644
--- a/lib/feature.rb
+++ b/lib/feature.rb
@@ -1,5 +1,15 @@
module OpenTox
class Feature
include OpenTox
+
+ def self.find(uri)
+ feature = Feature.new uri
+ if (CONFIG[:yaml_hosts].include?(URI.parse(uri).host))
+ feature.add_metadata YAML.load(RestClientWrapper.get(uri,:accept => "application/x-yaml"))
+ else
+ feature.add_metadata Parser::Owl::Dataset.new(uri).load_metadata
+ end
+ feature
+ end
end
end
diff --git a/lib/model.rb b/lib/model.rb
index 63013cb..c6a2cf4 100644
--- a/lib/model.rb
+++ b/lib/model.rb
@@ -4,6 +4,9 @@ module OpenTox
include OpenTox
+ # Run a model with parameters
+ # @param [Hash] params Parameters for OpenTox model
+ # @return [text/uri-list] Task or resource URI
def run(params)
if CONFIG[:yaml_hosts].include?(URI.parse(@uri).host)
accept = 'application/x-yaml'
@@ -11,47 +14,25 @@ module OpenTox
accept = 'application/rdf+xml'
end
begin
- params[:acccept] = accept
- #TODO fix: REstClientWrapper does not accept accept header
- #RestClientWrapper.post(@uri,params)#,{:accept => accept})
- `curl -X POST -H "Accept:#{accept}" #{params.collect{|k,v| "-d #{k}=#{v}"}.join(" ")} #{@uri}`.to_s.chomp
+ RestClientWrapper.post(@uri,{:accept => accept},params).to_s
rescue => e
LOGGER.error "Failed to run #{@uri} with #{params.inspect} (#{e.inspect})"
raise "Failed to run #{@uri} with #{params.inspect}"
end
end
-
-=begin
- def classification?
- #TODO replace with request to ontology server
- if @metadata[DC.title] =~ /(?i)classification/
- return true
- elsif @metadata[DC.title] =~ /(?i)regression/
- return false
- elsif @uri =~/ntua/ and @metadata[DC.title] =~ /mlr/
- return false
- elsif @uri =~/tu-muenchen/ and @metadata[DC.title] =~ /regression|M5P|GaussP/
- return false
- elsif @uri =~/ambit2/ and @metadata[DC.title] =~ /pKa/ || @metadata[DC.title] =~ /Regression|Caco/
- return false
- elsif @uri =~/majority/
- return (@uri =~ /class/) != nil
- else
- raise "unknown model, uri:'"+@uri+"' title:'"+@metadata[DC.title]+"'"
- end
- end
-=end
+ # Generic OpenTox model class for all API compliant services
class Generic
include Model
end
+ # Lazy Structure Activity Relationship class
class Lazar
include Model
+ include Algorithm
- #attr_accessor :prediction_type, :feature_type, :features, :effects, :activities, :p_values, :fingerprints, :parameters
- attr_accessor :compound, :prediction_dataset, :features, :effects, :activities, :p_values, :fingerprints, :parameters, :feature_calculation_algorithm, :similarity_algorithm, :prediction_algorithm
+ attr_accessor :compound, :prediction_dataset, :features, :effects, :activities, :p_values, :fingerprints, :feature_calculation_algorithm, :similarity_algorithm, :prediction_algorithm, :min_sim
def initialize(uri=nil)
@@ -61,7 +42,6 @@ module OpenTox
super CONFIG[:services]["opentox-model"]
end
- # TODO: fix metadata, add parameters
@metadata[OT.algorithm] = File.join(CONFIG[:services]["opentox-algorithm"],"lazar")
@features = []
@@ -70,284 +50,192 @@ module OpenTox
@p_values = {}
@fingerprints = {}
- @feature_calculation_algorithm = "substructure_match"
- @similarity_algorithm = "weighted_tanimoto"
- @prediction_algorithm = "weighted_majority_vote"
+ @feature_calculation_algorithm = "Substructure.match"
+ @similarity_algorithm = "Similarity.tanimoto"
+ @prediction_algorithm = "Neighbors.weighted_majority_vote"
@min_sim = 0.3
end
- def self.find(uri)
- YAML.load RestClientWrapper.get(uri,:content_type => 'application/x-yaml')
+ # Get URIs of all lazar models
+ # @return [Array] List of lazar model URIs
+ def self.all
+ RestClientWrapper.get(CONFIG[:services]["opentox-model"]).to_s.split("\n")
end
- def self.create_from_dataset(dataset_uri,feature_dataset_uri,prediction_feature=nil)
- training_activities = OpenTox::Dataset.find(dataset_uri)
- training_features = OpenTox::Dataset.find(feature_dataset_uri)
- unless prediction_feature # try to read prediction_feature from dataset
- raise "#{training_activities.features.size} features in dataset #{dataset_uri}. Please provide a prediction_feature parameter." unless training_activities.features.size == 1
- prediction_feature = training_activities.features.keys.first
- params[:prediction_feature] = prediction_feature
- end
- lazar = Lazar.new
- training_features = OpenTox::Dataset.new(feature_dataset_uri)
- case training_features.feature_type
- when "classification"
- lazar.similarity_algorithm = "weighted_tanimoto"
- when "regression"
- lazar.similarity_algorithm = "weighted_euclid"
- end
+ # Find a lazar model
+ # @param [String] uri Model URI
+ # @return [OpenTox::Model::Lazar] lazar model
+ def self.find(uri)
+ YAML.load RestClientWrapper.get(uri,:accept => 'application/x-yaml')
end
- def self.create(dataset_uri,prediction_feature=nil,feature_generation_uri=File.join(CONFIG[:services]["opentox-algorithm"],"fminer/bbrc"),params=nil)
-
- training_activities = OpenTox::Dataset.find(dataset_uri)
-
- unless prediction_feature # try to read prediction_feature from dataset
- raise "#{training_activities.features.size} features in dataset #{dataset_uri}. Please provide a prediction_feature parameter." unless training_activities.features.size == 1
- prediction_feature = training_activities.features.keys.first
- params[:prediction_feature] = prediction_feature
- end
-
- lazar = Lazar.new
- params[:feature_generation_uri] = feature_generation_uri
- feature_dataset_uri = OpenTox::Algorithm::Generic.new(feature_generation_uri).run(params).to_s
- training_features = OpenTox::Dataset.find(feature_dataset_uri)
- raise "Dataset #{feature_dataset_uri} not found or empty." if training_features.nil?
-
- # sorted features for index lookups
- lazar.features = training_features.features.sort if training_features.feature_type == "regression"
-
- training_features.data_entries.each do |compound,entry|
- lazar.fingerprints[compound] = [] unless lazar.fingerprints[compound]
- entry.keys.each do |feature|
- case training_features.feature_type
- when "fminer"
- # fingerprints are sets
- smarts = training_features.features[feature][OT.smarts]
- lazar.fingerprints[compound] << smarts
- unless lazar.features.include? smarts
- lazar.features << smarts
- lazar.p_values[smarts] = training_features.features[feature][OT.p_value]
- lazar.effects[smarts] = training_features.features[feature][OT.effect]
- end
- when "classification"
- # fingerprints are sets
- if entry[feature].flatten.size == 1
- lazar.fingerprints[compound] << feature if entry[feature].flatten.first.match(TRUE_REGEXP)
- lazar.features << feature unless lazar.features.include? feature
- else
- LOGGER.warn "More than one entry (#{entry[feature].inspect}) for compound #{compound}, feature #{feature}"
- end
- when "regression"
- # fingerprints are arrays
- if entry[feature].flatten.size == 1
- lazar.fingerprints[compound][lazar.features.index(feature)] = entry[feature].flatten.first
- else
- LOGGER.warn "More than one entry (#{entry[feature].inspect}) for compound #{compound}, feature #{feature}"
- end
- end
- end
-
- lazar.activities[compound] = [] unless lazar.activities[compound]
- training_activities.data_entries[compound][params[:prediction_feature]].each do |value|
- case value.to_s
- when "true"
- lazar.activities[compound] << true
- when "false"
- lazar.activities[compound] << false
- else
- lazar.activities[compound] << value.to_f
- lazar.prediction_type = "regression"
- end
- end
- end
-
- if feature_generation_uri.match(/fminer/)
- lazar.feature_calculation_algorithm = "substructure_match"
- else
- halt 404, "External feature generation services not yet supported"
- end
-
- lazar.metadata[OT.dependentVariables] = params[:prediction_feature]
- lazar.metadata[OT.trainingDataset] = dataset_uri
- lazar.metadata[OT.featureDataset] = feature_dataset_uri
+ # Create a new lazar model
+ # @param [optional,Hash] params Parameters for the lazar algorithm (OpenTox::Algorithm::Lazar)
+ # @return [OpenTox::Model::Lazar] lazar model
+ def self.create(params)
+ lazar_algorithm = OpenTox::Algorithm::Generic.new File.join( CONFIG[:services]["opentox-algorithm"],"lazar")
+ model_uri = lazar_algorithm.run(params)
+ OpenTox::Model::Lazar.find(model_uri)
+ end
- lazar.parameters = {
- "dataset_uri" => dataset_uri,
- "prediction_feature" => prediction_feature,
- "feature_generation_uri" => feature_generation_uri
- }
-
- model_uri = lazar.save
- LOGGER.info model_uri + " created #{Time.now}"
- model_uri
+=begin
+ # Create a new lazar model and return task
+ # @param [optional,Hash] params Parameters for the lazar algorithm (OpenTox::Algorithm::Lazar)
+ # @return [OpenTox::Task] Task for lazar model creation
+ def self.create_task(params)
+ task_uri = RestClientWrapper.post(File.join(CONFIG[:services]["opentox-algorithm"],"lazar"), {}, params, false)
+ Task.find(task_uri)
+ #model_uri = lazar_algorithm.run(params)
+ #OpenTox::Model::Lazar.new(model_uri)
+ end
+=end
+ def parameter(param)
+ @metadata[OT.parameters].collect{|p| p[OT.paramValue] if p[DC.title] == param}.compact.first
end
def predict_dataset(dataset_uri)
@prediction_dataset = Dataset.create
@prediction_dataset.add_metadata({
- OT.hasSource => @lazar.uri,
- DC.creator => @lazar.uri,
- DC.title => URI.decode(File.basename( @metadata[OT.dependentVariables] ))
+ OT.hasSource => @uri,
+ DC.creator => @uri,
+ DC.title => URI.decode(File.basename( @metadata[OT.dependentVariables] )),
+ OT.parameters => [{DC.title => "dataset_uri", OT.paramValue => dataset_uri}]
})
- @prediction_dataset.add_parameters({"dataset_uri" => dataset_uri})
- Dataset.new(dataset_uri).load_compounds.each do |compound_uri|
+ d = Dataset.new(dataset_uri)
+ d.load_compounds
+ d.compounds.each do |compound_uri|
predict(compound_uri,false)
end
@prediction_dataset.save
- @prediction_dataset.uri
+ @prediction_dataset
end
+ # Predict a compound
+ # @param [String] compound_uri Compound URI
+ # @param [optinal,Boolean] verbose Verbose prediction (output includes neighbors and features)
+ # @return [OpenTox::Dataset] Dataset with prediction
def predict(compound_uri,verbose=false)
@compound = Compound.new compound_uri
+ features = {}
unless @prediction_dataset
+ #@prediction_dataset = cached_prediction
+ #return @prediction_dataset if cached_prediction
@prediction_dataset = Dataset.create
@prediction_dataset.add_metadata( {
- OT.hasSource => @lazar.uri,
- DC.creator => @lazar.uri,
- DC.title => URI.decode(File.basename( @metadata[OT.dependentVariables] ))
+ OT.hasSource => @uri,
+ DC.creator => @uri,
+ # TODO: fix dependentVariable
+ DC.title => URI.decode(File.basename( @metadata[OT.dependentVariables] )),
+ OT.parameters => [{DC.title => "compound_uri", OT.paramValue => compound_uri}]
} )
- @prediction_dataset.add_parameters( {"compound_uri" => compound_uri} )
end
- neighbors
- eval @prediction_algorithm
-
- if @prediction
+ return @prediction_dataset if database_activity
- feature_uri = File.join( @prediction_dataset.uri, "feature", @prediction_dataset.compounds.size)
- @prediction_dataset.add @compound.uri, feature_uri, @prediction
+ neighbors
+ prediction = eval("#{@prediction_algorithm}(@neighbors,{:similarity_algorithm => @similarity_algorithm, :p_values => @p_values})")
+
+ prediction_feature_uri = File.join( @prediction_dataset.uri, "feature", "prediction", File.basename(@metadata[OT.dependentVariables]),@prediction_dataset.compounds.size.to_s)
+ # TODO: fix dependentVariable
+ @prediction_dataset.metadata[OT.dependentVariables] = prediction_feature_uri
+
+ if @neighbors.size == 0
+ @prediction_dataset.add_feature(prediction_feature_uri, {
+ OT.hasSource => @uri,
+ DC.creator => @uri,
+ DC.title => URI.decode(File.basename( @metadata[OT.dependentVariables] )),
+ OT.error => "No similar compounds in training dataset.",
+ OT.parameters => [{DC.title => "compound_uri", OT.paramValue => compound_uri}]
+ })
+ @prediction_dataset.add @compound.uri, prediction_feature_uri, prediction[:prediction]
- feature_metadata = @prediction_dataset.metadata
- feature_metadata[DC.title] = File.basename(@metadata[OT.dependentVariables])
- feature_metadata[OT.prediction] = @prediction
- feature_metadata[OT.confidence] = @confidence
- @prediction_dataset.add_feature(feature_uri, feature_metadata)
+ else
+ @prediction_dataset.add_feature(prediction_feature_uri, {
+ OT.hasSource => @uri,
+ DC.creator => @uri,
+ DC.title => URI.decode(File.basename( @metadata[OT.dependentVariables] )),
+ OT.prediction => prediction[:prediction],
+ OT.confidence => prediction[:confidence],
+ OT.parameters => [{DC.title => "compound_uri", OT.paramValue => compound_uri}]
+ })
+ @prediction_dataset.add @compound.uri, prediction_feature_uri, prediction[:prediction]
if verbose
- if @compound_features
+ if @feature_calculation_algorithm == "Substructure.match"
+ f = 0
+ @compound_features.each do |feature|
+ feature_uri = File.join( @prediction_dataset.uri, "feature", "descriptor", f.to_s)
+ features[feature] = feature_uri
+ @prediction_dataset.add_feature(feature_uri, {
+ OT.smarts => feature,
+ OT.p_value => @p_values[feature],
+ OT.effect => @effects[feature]
+ })
+ @prediction_dataset.add @compound.uri, feature_uri, true
+ f+=1
+ end
+ else
@compound_features.each do |feature|
+ features[feature] = feature
@prediction_dataset.add @compound.uri, feature, true
end
end
n = 0
- @neighbors.sort{|a,b| a[:similarity] <=> b[:similarity]}.each do |neighbor|
- neighbor_uri = File.join( @prediction_dataset.uri, "feature/neighbor", n )
- @prediction_dataset.add @compound.uri, neighbor_uri, true
- @prediction_dataset.add_feature(neighbor, {
+ @neighbors.each do |neighbor|
+ neighbor_uri = File.join( @prediction_dataset.uri, "feature", "neighbor", n.to_s )
+ @prediction_dataset.add_feature(neighbor_uri, {
OT.compound => neighbor[:compound],
OT.similarity => neighbor[:similarity],
OT.activity => neighbor[:activity]
})
+ @prediction_dataset.add @compound.uri, neighbor_uri, true
+ f = 0 unless f
+ neighbor[:features].each do |feature|
+ if @feature_calculation_algorithm == "Substructure.match"
+ feature_uri = File.join( @prediction_dataset.uri, "feature", "descriptor", f.to_s) unless feature_uri = features[feature]
+ else
+ feature_uri = feature
+ end
+ @prediction_dataset.add neighbor[:compound], feature_uri, true
+ unless features.has_key? feature
+ features[feature] = feature_uri
+ @prediction_dataset.add_feature(feature_uri, {
+ OT.smarts => feature,
+ OT.p_value => @p_values[feature],
+ OT.effect => @effects[feature]
+ })
+ f+=1
+ end
+ end
n+=1
end
+ # what happens with dataset predictions?
end
end
- @prediction_dataset.save
- @prediction_dataset.uri
- end
-
- def weighted_majority_vote
- conf = 0.0
- @neighbors.each do |neighbor|
- case neighbor[:activity].to_s
- when 'true'
- conf += OpenTox::Algorithm.gauss(neighbor[:similarity])
- when 'false'
- conf -= OpenTox::Algorithm.gauss(neighbor[:similarity])
- end
- end
- if conf > 0.0
- @prediction = true
- elsif conf < 0.0
- @prediction = false
- else
- @prediction = nil
- end
- @confidence = conf/@neighbors.size if @neighbors.size > 0
- end
-
- def local_svm_regression
- sims = @neighbors.collect{ |n| n[:similarity] } # similarity values between query and neighbors
- conf = sims.inject{|sum,x| sum + x }
- acts = @neighbors.collect do |n|
- act = n[:activity]
- # TODO: check this in model creation
- raise "0 values not allowed in training dataset. log10 is calculated internally." if act.to_f == 0
- Math.log10(act.to_f)
- end # activities of neighbors for supervised learning
-
- neighbor_matches = @neighbors.collect{ |n| n[:features] } # as in classification: URIs of matches
- gram_matrix = [] # square matrix of similarities between neighbors; implements weighted tanimoto kernel
- if neighbor_matches.size == 0
- raise "No neighbors found"
- else
- # gram matrix
- (0..(neighbor_matches.length-1)).each do |i|
- gram_matrix[i] = []
- # lower triangle
- (0..(i-1)).each do |j|
- sim = OpenTox::Algorithm.weighted_tanimoto(neighbor_matches[i], neighbor_matches[j], @lazar.p_values)
- gram_matrix[i] << OpenTox::Algorithm.gauss(sim)
- end
- # diagonal element
- gram_matrix[i][i] = 1.0
- # upper triangle
- ((i+1)..(neighbor_matches.length-1)).each do |j|
- sim = OpenTox::Algorithm.weighted_tanimoto(neighbor_matches[i], neighbor_matches[j], @lazar.p_values) # double calculation?
- gram_matrix[i] << OpenTox::Algorithm.gauss(sim)
- end
- end
- @r = RinRuby.new(false,false) # global R instance leads to Socket errors after a large number of requests
- @r.eval "library('kernlab')" # this requires R package "kernlab" to be installed
- LOGGER.debug "Setting R data ..."
- # set data
- @r.gram_matrix = gram_matrix.flatten
- @r.n = neighbor_matches.size
- @r.y = acts
- @r.sims = sims
-
- LOGGER.debug "Preparing R data ..."
- # prepare data
- @r.eval "y<-as.vector(y)"
- @r.eval "gram_matrix<-as.kernelMatrix(matrix(gram_matrix,n,n))"
- @r.eval "sims<-as.vector(sims)"
-
- # model + support vectors
- LOGGER.debug "Creating SVM model ..."
- @r.eval "model<-ksvm(gram_matrix, y, kernel=matrix, type=\"nu-svr\", nu=0.8)"
- @r.eval "sv<-as.vector(SVindex(model))"
- @r.eval "sims<-sims[sv]"
- @r.eval "sims<-as.kernelMatrix(matrix(sims,1))"
- LOGGER.debug "Predicting ..."
- @r.eval "p<-predict(model,sims)[1,1]"
- @prediction = 10**(@r.p.to_f)
- LOGGER.debug "Prediction is: '" + prediction.to_s + "'."
- @r.quit # free R
- end
- @confidence = conf/@neighbors.size if @neighbors.size > 0
-
+ @prediction_dataset.save
+ @prediction_dataset
end
+ # Find neighbors and store them as object variable
def neighbors
- @compound_features = eval(@feature_calculation_algorithm) if @feature_calculation_algorithm
+ @compound_features = eval("#{@feature_calculation_algorithm}(@compound,@features)") if @feature_calculation_algorithm
- @neighbors = {}
- @activities.each do |training_compound,activities|
- @training_compound = training_compound
- sim = eval(@similarity_algorithm)
+ @neighbors = []
+ @fingerprints.each do |training_compound,training_features|
+ #@activities.each do |training_compound,activities|
+ sim = eval("#{@similarity_algorithm}(@compound_features,training_features,@p_values)")
if sim > @min_sim
- activities.each do |act|
+ @activities[training_compound].each do |act|
@neighbors << {
- :compound => @training_compound,
+ :compound => training_compound,
:similarity => sim,
- :features => @fingerprints[@training_compound],
+ :features => training_features,
:activity => act
}
end
@@ -356,55 +244,63 @@ module OpenTox
end
- def tanimoto
- OpenTox::Algorithm.tanimoto(@compound_features,@fingerprints[@training_compound])
- end
-
- def weighted_tanimoto
- OpenTox::Algorithm.tanimoto(@compound_features,@fingerprints[@training_compound],@p_values)
- end
-
- def euclid
- OpenTox::Algorithm.tanimoto(@compound_features,@fingerprints[@training_compound])
- end
-
- def weighted_euclid
- OpenTox::Algorithm.tanimoto(@compound_features,@fingerprints[@training_compound],@p_values)
- end
-
- def substructure_match
- @compound.match(@features)
- end
-
- def database_search
- #TODO add features method to dataset
- Dataset.new(@metadata[OT.featureDataset]).features(@compound.uri)
+=begin
+ def cached_prediction
+ dataset_uri = PredictionCache.find(:model_uri => @uri, :compound_uri => @compound.uri).dataset_uri)
+ return false unless dataset_uri
+ @prediction_dataset = Dataset.find(dataset_uri)
+ return false unless @prediction_dataset
+ LOGGER.debug "Serving cached prediction"
+ true
end
+=end
- def database_activity(compound_uri)
- prediction = OpenTox::Dataset.new
- # find database activities
- if @activities[compound_uri]
- @activities[compound_uri].each { |act| prediction.add compound_uri, @metadata[OT.dependentVariables], act }
- prediction.add_metadata(OT.hasSource => @metadata[OT.trainingDataset])
- prediction
+ # Find database activities and store them in @prediction_dataset
+ # @return [Boolean] true if compound has databasse activities, false if not
+ def database_activity
+ if @activities[@compound.uri]
+ @activities[@compound.uri].each { |act| @prediction_dataset.add @compound.uri, @metadata[OT.dependentVariables], act }
+ @prediction_dataset.add_metadata(OT.hasSource => @metadata[OT.trainingDataset])
+ @prediction_dataset.save
+ true
else
- nil
+ false
end
end
+ # Save model at model service
def save
- RestClientWrapper.post(@uri,{:content_type => "application/x-yaml"},self.to_yaml)
- end
-
- def self.all
- RestClientWrapper.get(CONFIG[:services]["opentox-model"]).to_s.split("\n")
+ self.uri = RestClientWrapper.post(@uri,{:content_type => "application/x-yaml"},self.to_yaml)
end
+ # Delete model at model service
def delete
RestClientWrapper.delete @uri unless @uri == CONFIG[:services]["opentox-model"]
end
+=begin
+=end
+
+=begin
+ def self.create_from_dataset(dataset_uri,feature_dataset_uri,prediction_feature=nil)
+ training_activities = OpenTox::Dataset.find(dataset_uri)
+ training_features = OpenTox::Dataset.find(feature_dataset_uri)
+ unless prediction_feature # try to read prediction_feature from dataset
+ raise "#{training_activities.features.size} features in dataset #{dataset_uri}. Please provide a prediction_feature parameter." unless training_activities.features.size == 1
+ prediction_feature = training_activities.features.keys.first
+ params[:prediction_feature] = prediction_feature
+ end
+ lazar = Lazar.new
+ training_features = OpenTox::Dataset.new(feature_dataset_uri)
+ case training_features.feature_type
+ when "classification"
+ lazar.similarity_algorithm = "weighted_tanimoto"
+ when "regression"
+ lazar.similarity_algorithm = "weighted_euclid"
+ end
+ end
+=end
+
end
end
end
diff --git a/lib/opentox-ruby-api-wrapper.rb b/lib/opentox-ruby-api-wrapper.rb
index 9dc1372..9f9ff26 100644
--- a/lib/opentox-ruby-api-wrapper.rb
+++ b/lib/opentox-ruby-api-wrapper.rb
@@ -1,4 +1,4 @@
-['rubygems', 'sinatra', 'sinatra/url_for', 'rest_client', 'yaml', 'cgi', 'spork', 'environment'].each do |lib|
+['rubygems', 'sinatra', 'sinatra/url_for', 'rest_client', 'yaml', 'cgi', 'spork', 'overwrite', 'environment'].each do |lib|
require lib
end
@@ -8,6 +8,6 @@ rescue LoadError
puts "Please install Openbabel with 'rake openbabel:install' in the compound component"
end
-['opentox', 'compound','dataset', 'parser','serializer', 'algorithm','model','task','validation','feature', 'ot-logger', 'overwrite', 'rest_client_wrapper'].each do |lib|
+['opentox', 'compound','dataset', 'parser','serializer', 'algorithm','model','task','validation','feature', 'rest_client_wrapper'].each do |lib|
require lib
end
diff --git a/lib/opentox.rb b/lib/opentox.rb
index 3b7fa65..90683e5 100644
--- a/lib/opentox.rb
+++ b/lib/opentox.rb
@@ -1,7 +1,7 @@
module OpenTox
attr_reader :uri
- attr_accessor :metadata, :parameters
+ attr_accessor :metadata
# Initialize OpenTox object with optional uri
# @param [optional, String] URI
@@ -30,11 +30,9 @@ module OpenTox
@metadata
end
- # Load parameters from URI
- #def load_parameters
- #@parameters = Parser::Owl::Generic.new(@uri).parameters
- #@parameters
- #end
+ def add_metadata(metadata)
+ metadata.each { |k,v| @metadata[k] = v }
+ end
# Get OWL-DL representation in RDF/XML format
# @return [application/rdf+xml] RDF/XML representation
diff --git a/lib/ot-logger.rb b/lib/ot-logger.rb
deleted file mode 100644
index df38d77..0000000
--- a/lib/ot-logger.rb
+++ /dev/null
@@ -1,48 +0,0 @@
-require 'logger'
-# logging
-class MyLogger < Logger
-
- def pwd
- path = Dir.pwd.to_s
- index = path.rindex(/\//)
- return path if index==nil
- path[(index+1)..-1]
- end
-
- def trace()
- lines = caller(0)
- n = 2
- line = lines[n]
-
- while (line =~ /spork.rb/ or line =~ /as_task/ or line =~ /ot-logger.rb/)
- n += 1
- line = lines[n]
- end
-
- index = line.rindex(/\/.*\.rb/)
- return line if index==nil
- line[index..-1]
- end
-
- def format(msg)
- pwd.ljust(18)+" :: "+msg.to_s+" :: "+trace+" :: "+($sinatra ? $sinatra.request.env['REMOTE_ADDR'] : nil).to_s
- end
-
- def debug(msg)
- super format(msg)
- end
-
- def info(msg)
- super format(msg)
- end
-
- def warn(msg)
- super format(msg)
- end
-
- def error(msg)
- super format(msg)
- end
-
-end
-
diff --git a/lib/overwrite.rb b/lib/overwrite.rb
index 2e4c396..f39fec3 100644
--- a/lib/overwrite.rb
+++ b/lib/overwrite.rb
@@ -34,3 +34,53 @@ class String
end
end
end
+
+require 'logger'
+# logging
+#class Logger
+class OTLogger < Logger
+
+ def pwd
+ path = Dir.pwd.to_s
+ index = path.rindex(/\//)
+ return path if index==nil
+ path[(index+1)..-1]
+ end
+
+ def trace()
+ lines = caller(0)
+ n = 2
+ line = lines[n]
+
+ while (line =~ /spork.rb/ or line =~ /create/ or line =~ /ot-logger.rb/)
+ n += 1
+ line = lines[n]
+ end
+
+ index = line.rindex(/\/.*\.rb/)
+ return line if index==nil
+ line[index..-1]
+ end
+
+ def format(msg)
+ pwd.ljust(18)+" :: "+msg.to_s+" :: "+trace+" :: "+($sinatra ? $sinatra.request.env['REMOTE_ADDR'] : nil).to_s
+ end
+
+ def debug(msg)
+ super format(msg)
+ end
+
+ def info(msg)
+ super format(msg)
+ end
+
+ def warn(msg)
+ super format(msg)
+ end
+
+ def error(msg)
+ super format(msg)
+ end
+
+end
+
diff --git a/lib/parser.rb b/lib/parser.rb
index 4d8e729..b727412 100644
--- a/lib/parser.rb
+++ b/lib/parser.rb
@@ -116,7 +116,7 @@ module OpenTox
end
end
load_features
- @dataset.metadata = metadata
+ @dataset.metadata = load_metadata
@dataset
end
@@ -253,10 +253,8 @@ module OpenTox
when OT.NumericFeature
@dataset.add compound.uri, feature, value.to_f
when OT.StringFeature
- # TODO: insert ??
@dataset.add compound.uri, feature, value.to_s
@activity_errors << smiles+", "+row.join(", ")
- #return false
end
end
end
diff --git a/lib/rest_client_wrapper.rb b/lib/rest_client_wrapper.rb
index 49549b5..5f5273b 100644
--- a/lib/rest_client_wrapper.rb
+++ b/lib/rest_client_wrapper.rb
@@ -80,6 +80,7 @@ module OpenTox
raise "content-type not set" unless res.content_type
res.code = result.code
+ # TODO: Ambit returns task representation with 200 instead of result URI
return res if res.code==200 || !wait
while (res.code==201 || res.code==202)
@@ -108,11 +109,12 @@ module OpenTox
task = nil
case res.content_type
- when /application\/rdf\+xml|application\/x-yaml/
- task = OpenTox::Task.from_data(res, res.content_type, res.code, base_uri)
+ when /application\/rdf\+xml/
+ task = OpenTox::Task.from_rdfxml(res)
+ when /yaml/
+ task = OpenTox::Task.from_yaml(res)
when /text\//
- raise "uri list has more than one entry, should be a task" if res.content_type=~/text\/uri-list/ and
- res.split("\n").size > 1 #if uri list contains more then one uri, its not a task
+ raise "uri list has more than one entry, should be a task" if res.content_type=~/text\/uri-list/ and res.split("\n").size > 1 #if uri list contains more then one uri, its not a task
task = OpenTox::Task.find(res.to_s) if res.to_s.uri?
else
raise "unknown content-type for task: '"+res.content_type.to_s+"'" #+"' content: "+res[0..200].to_s
@@ -122,7 +124,7 @@ module OpenTox
task.wait_for_completion
raise task.description unless task.completed? # maybe task was cancelled / error
- res = WrapperResult.new task.resultURI
+ res = WrapperResult.new task.result_uri
res.code = task.http_code
res.content_type = "text/uri-list"
return res
@@ -152,8 +154,8 @@ module OpenTox
# we are either in a task, or in sinatra
# PENDING: always return yaml for now
- if $self_task #this global var in Task.as_task to mark that the current process is running in a task
- raise error.to_yaml # the error is caught, logged, and task state is set to error in Task.as_task
+ if $self_task #this global var in Task.create to mark that the current process is running in a task
+ raise error.to_yaml # the error is caught, logged, and task state is set to error in Task.create
#elsif $sinatra #else halt sinatra
#$sinatra.halt(502,error.to_yaml)
elsif defined?(halt)
diff --git a/lib/serializer.rb b/lib/serializer.rb
index 31aa0d1..9b3af39 100644
--- a/lib/serializer.rb
+++ b/lib/serializer.rb
@@ -25,6 +25,7 @@ module OpenTox
OT.FeatureValue => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
OT.Algorithm => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
OT.Parameter => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
+ OT.Task => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
OT.compound => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
OT.feature => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
@@ -42,6 +43,8 @@ module OpenTox
OT.isA => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
OT.Warnings => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
XSD.anyURI => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.hasStatus => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.resultURI => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
OT.hasSource => { RDF["type"] => [{ "type" => "uri", "value" => OWL.DatatypeProperty }] } ,
OT.value => { RDF["type"] => [{ "type" => "uri", "value" => OWL.DatatypeProperty }] } ,
@@ -100,17 +103,21 @@ module OpenTox
# @param [String] uri Algorithm URI
def add_algorithm(uri,metadata)
@object[uri] = { RDF["type"] => [{ "type" => "uri", "value" => OT.Algorithm }] }
- LOGGER.debug @object[uri]
add_metadata uri, metadata
- LOGGER.debug @object[uri]
end
# Add a model
# @param [String] uri Model URI
- def add_model(uri,metadata,parameters)
+ def add_model(uri,metadata)
@object[uri] = { RDF["type"] => [{ "type" => "uri", "value" => OT.Model }] }
add_metadata uri, metadata
- add_parameters uri, parameters
+ end
+
+ # Add a task
+ # @param [String] uri Model URI
+ def add_task(uri,metadata)
+ @object[uri] = { RDF["type"] => [{ "type" => "uri", "value" => OT.Task }] }
+ add_metadata uri, metadata
end
# Add metadata
@@ -204,7 +211,7 @@ module OpenTox
# @return [text/plain] Object OWL-DL in RDF/XML format
def to_rdfxml
Tempfile.open("owl-serializer"){|f| f.write(self.to_ntriples); @path = f.path}
- `rapper -i ntriples -o rdfxml #{@path} 2>/dev/null`
+ `rapper -i ntriples -f 'xmlns:ot="#{OT.uri}"' -f 'xmlns:dc="#{DC.uri}"' -f 'xmlns:rdf="#{RDF.uri}"' -f 'xmlns:owl="#{OWL.uri}"' -o rdfxml #{@path} 2>/dev/null`
end
# Convert to JSON as specified in http://n2.talis.com/wiki/RDF_JSON_Specification
@@ -290,7 +297,11 @@ module OpenTox
entries.each do |feature, values|
i = features.index(feature)+1
values.each do |value|
- row[i] = value #TODO overwrites duplicated values
+ if row[i]
+ row[i] = "#{row[i]} #{value}" # multiple values
+ else
+ row[i] = value
+ end
end
end
@rows << row
diff --git a/lib/task.rb b/lib/task.rb
index 96ee719..5b2b5d9 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -2,39 +2,183 @@ $self_task=nil
module OpenTox
+ # Class for handling asynchronous tasks
class Task
- attr_accessor :uri, :date, :title, :creator, :description, :hasStatus, :percentageCompleted, :resultURI, :due_to_time, :http_code
-
- # due_to_time is only set in local tasks
- TASK_ATTRIBS = [ :uri, :date, :title, :creator, :description, :hasStatus, :percentageCompleted, :resultURI, :due_to_time ]
- TASK_ATTRIBS.each{ |a| attr_accessor(a) }
- attr_accessor :http_code
+ include OpenTox
+ attr_accessor :http_code, :due_to_time
- private
- def initialize(uri)
- @uri = uri.to_s.strip
+ def initialize(uri=nil)
+ super uri
+ @metadata = {
+ DC.title => "",
+ DC.date => "",
+ OT.hasStatus => "Running",
+ OT.percentageCompleted => "0",
+ OT.resultURI => "",
+ DC.creator => "", # not mandatory according to API
+ DC.description => "", # not mandatory according to API
+ }
end
-
- # create is private now, use OpenTox::Task.as_task
- def self.create( params )
+
+ # Create a new task for the code in the block. Catches halts and exceptions and sets task state to error if necessary. The block has to return the URI of the created resource.
+ # @example
+ # task = OpenTox::Task.create do
+ # # this code will be executed as a task
+ # model = OpenTox::Algorithm.run(params) # this can be time consuming
+ # model.uri # Important: return URI of the created resource
+ # end
+ # task.status # returns "Running", because tasks are forked
+ # @param [String] title Task title
+ # @param [String] creator Task creator
+ # @return [OPenTox::Task] Task
+ def self.create( title=nil, creator=nil, max_duration=DEFAULT_TASK_MAX_DURATION, description=nil )
+
+ # measure current memory consumption
+ memory = `free -m|sed -n '2p'`.split
+ free_memory = memory[3].to_i + memory[6].to_i # include cache
+ if free_memory < 20 # require at least 200 M free memory
+ LOGGER.warn "Cannot start task - not enough memory left (#{free_memory} M free)"
+ raise "Insufficient memory to start a new task"
+ end
+
+ cpu_load = `cat /proc/loadavg`.split(/\s+/)[0..2].collect{|c| c.to_f}
+ nr_cpu_cores = `cat /proc/cpuinfo |grep "cpu cores"|cut -d ":" -f2|tr -d " "`.split("\n").collect{|c| c.to_i}.inject{|sum,n| sum+n}
+ if cpu_load[0] > nr_cpu_cores and cpu_load[0] > cpu_load[1] and cpu_load[1] > cpu_load[2] # average CPU load of the last minute is high and CPU load is increasing
+ LOGGER.warn "Cannot start task - CPU load too high (#{cpu_load.join(", ")})"
+ raise "Server too busy to start a new task"
+ end
+
+ params = {:title=>title, :creator=>creator, :max_duration=>max_duration, :description=>description }
task_uri = RestClientWrapper.post(CONFIG[:services]["opentox-task"], params, nil, false).to_s
- Task.find(task_uri.chomp)
- end
+ task = Task.new(task_uri.chomp)
+
+ task_pid = Spork.spork(:logger => LOGGER) do
+ LOGGER.debug "Task #{task.uri} started #{Time.now}"
+ $self_task = task
+
+ begin
+ result = catch(:halt) do
+ yield task
+ end
+ # catching halt, set task state to error
+ if result && result.is_a?(Array) && result.size==2 && result[0]>202
+ LOGGER.error "task was halted: "+result.inspect
+ task.error(result[1])
+ return
+ end
+ LOGGER.debug "Task #{task.uri} done #{Time.now} -> "+result.to_s
+ task.completed(result)
+ rescue => ex
+ LOGGER.error "task failed: "+ex.message
+ LOGGER.error ": "+ex.backtrace.join("\n")
+ task.error(ex.message)
+ end
+ end
+ task.pid = task_pid
+ LOGGER.debug "Started task: "+task.uri.to_s
+ task
+ end
- public
- def self.find( uri, accept_header=nil )
+ # Find a task for querying, status changes
+ # @param [String] uri Task URI
+ # @return [OpenTox::Task] Task object
+ def self.find(uri)
task = Task.new(uri)
- task.reload( accept_header )
- return task
+ task.load_metadata
+ task
+ end
+
+ # Get a list of all tasks
+ # @param [optional, String] uri URI of task service
+ # @return [text/uri-list] Task URIs
+ def self.all(uri=CONFIG[:services]["opentox-task"])
+ OpenTox.all uri
+ end
+
+ def self.from_yaml(yaml)
+ @metadata = YAML.load(yaml)
+ end
+
+ def self.from_rdfxml(rdfxml)
+ file = Tempfile.open("ot-rdfxml"){|f| f.write(rdfxml)}.path
+ parser = Parser::Owl::Generic.new file
+ @metadata = parser.load_metadata
+ end
+
+ def to_rdfxml
+ s = Serializer::Owl.new
+ s.add_task(@uri,@metadata)
+ s.to_rdfxml
+ end
+
+ def status
+ @metadata[OT.hasStatus]
+ end
+
+ def result_uri
+ @metadata[OT.resultURI]
+ end
+
+ def description
+ @metadata[DC.description]
+ end
+
+ def cancel
+ RestClientWrapper.put(File.join(@uri,'Cancelled'))
+ load_metadata
+ end
+
+ def completed(uri)
+ RestClientWrapper.put(File.join(@uri,'Completed'),{:resultURI => uri})
+ load_metadata
+ end
+
+ def error(description)
+ RestClientWrapper.put(File.join(@uri,'Error'),{:description => description.to_s[0..2000]})
+ load_metadata
+ end
+
+ def pid=(pid)
+ RestClientWrapper.put(File.join(@uri,'pid'), {:pid => pid})
+ end
+
+ def running?
+ @metadata[OT.hasStatus] == 'Running'
+ end
+
+ def completed?
+ @metadata[OT.hasStatus] == 'Completed'
+ end
+
+ def error?
+ @metadata[OT.hasStatus] == 'Error'
+ end
+
+ def load_metadata
+ if (CONFIG[:yaml_hosts].include?(URI.parse(uri).host))
+ result = RestClientWrapper.get(@uri, {:accept => 'application/x-yaml'}, false)
+ @metadata = YAML.load result.to_s
+ @http_code = result.code
+ else
+ @metadata = Parser::Owl::Generic.new(@uri).load_metadata
+ @http_code = RestClientWrapper.get(uri, {:accept => 'application/rdf+xml'}, false).code
+ end
end
+ # create is private now, use OpenTox::Task.as_task
+ #def self.create( params )
+ #task_uri = RestClientWrapper.post(CONFIG[:services]["opentox-task"], params, nil, false).to_s
+ #Task.find(task_uri.chomp)
+ #end
+
+=begin
def self.from_data(data, content_type, code, base_uri)
task = Task.new(nil)
task.http_code = code
task.reload_from_data(data, content_type, base_uri)
return task
end
-
+
def reload( accept_header=nil )
unless accept_header
if (CONFIG[:yaml_hosts].include?(URI.parse(uri).host))
@@ -65,113 +209,45 @@ module OpenTox
end
raise "uri is null after loading" unless @uri and @uri.to_s.strip.size>0
end
-
- def cancel
- RestClientWrapper.put(File.join(@uri,'Cancelled'))
- reload
- end
-
- def completed(uri)
- RestClientWrapper.put(File.join(@uri,'Completed'),{:resultURI => uri})
- reload
- end
-
- def error(description)
- RestClientWrapper.put(File.join(@uri,'Error'),{:description => description.to_s[0..2000]})
- reload
- end
-
- def pid=(pid)
- RestClientWrapper.put(File.join(@uri,'pid'), {:pid => pid})
- end
-
- def running?
- @hasStatus.to_s == 'Running'
- end
-
- def completed?
- @hasStatus.to_s == 'Completed'
- end
-
- def error?
- @hasStatus.to_s == 'Error'
- end
+=end
# waits for a task, unless time exceeds or state is no longer running
def wait_for_completion(dur=0.3)
- if (@uri.match(CONFIG[:services]["opentox-task"]))
- due_to_time = (@due_to_time.is_a?(Time) ? @due_to_time : Time.parse(@due_to_time))
- running_time = due_to_time - (@date.is_a?(Time) ? @date : Time.parse(@date))
- else
- # the date of the external task cannot be trusted, offest to local time might be to big
- due_to_time = Time.new + EXTERNAL_TASK_MAX_DURATION
- running_time = EXTERNAL_TASK_MAX_DURATION
- end
+ due_to_time = Time.new + DEFAULT_TASK_MAX_DURATION
LOGGER.debug "start waiting for task "+@uri.to_s+" at: "+Time.new.to_s+", waiting at least until "+due_to_time.to_s
+ load_metadata # for extremely fast tasks
+ check_state
while self.running?
sleep dur
- reload
+ load_metadata
check_state
if (Time.new > due_to_time)
- raise "max wait time exceeded ("+running_time.to_s+"sec), task: '"+@uri.to_s+"'"
+ raise "max wait time exceeded ("+DEFAULT_TASK_MAX_DURATION.to_s+"sec), task: '"+@uri.to_s+"'"
end
end
- LOGGER.debug "Task '"+@hasStatus+"': "+@uri.to_s+", Result: "+@resultURI.to_s
+ LOGGER.debug "Task '"+@metadata[OT.hasStatus]+"': "+@uri.to_s+", Result: "+@metadata[OT.resultURI].to_s
end
+ private
def check_state
begin
- raise "illegal task state, task is completed, resultURI is no URI: '"+@resultURI.to_s+
- "'" unless @resultURI and @resultURI.to_s.uri? if completed?
+ raise "illegal task state, task is completed, resultURI is no URI: '"+@metadata[OT.resultURI].to_s+
+ "'" unless @metadata[OT.resultURI] and @metadata[OT.resultURI].to_s.uri? if completed?
if @http_code == 202
- raise "illegal task state, code is 202, but hasStatus is not Running: '"+@hasStatus+"'" unless running?
+ raise "illegal task state, code is 202, but hasStatus is not Running: '"+@metadata[OT.hasStatus]+"'" unless running?
elsif @http_code == 201
- raise "illegal task state, code is 201, but hasStatus is not Completed: '"+@hasStatus+"'" unless completed?
- raise "illegal task state, code is 201, resultURI is no task-URI: '"+@resultURI.to_s+
- "'" unless @resultURI and @resultURI.to_s.uri?
+ raise "illegal task state, code is 201, but hasStatus is not Completed: '"+@metadata[OT.hasStatus]+"'" unless completed?
+ raise "illegal task state, code is 201, resultURI is no task-URI: '"+@metadata[OT.resultURI].to_s+
+ "'" unless @metadata[OT.resultURI] and @metadata[OT.resultURI].to_s.uri?
end
rescue => ex
RestClientWrapper.raise_uri_error(ex.message, @uri)
end
end
-
- # returns the task uri
- # catches halts and exceptions, task state is set to error then
- def self.as_task( title, creator, max_duration=DEFAULT_TASK_MAX_DURATION, description=nil )
- #return yield nil
-
- params = {:title=>title, :creator=>creator, :max_duration=>max_duration, :description=>description }
- task = ::OpenTox::Task.create(params)
- task_pid = Spork.spork(:logger => LOGGER) do
- LOGGER.debug "Task #{task.uri} started #{Time.now}"
- $self_task = task
-
- begin
- result = catch(:halt) do
- yield task
- end
- # catching halt, set task state to error
- if result && result.is_a?(Array) && result.size==2 && result[0]>202
- LOGGER.error "task was halted: "+result.inspect
- task.error(result[1])
- return
- end
- LOGGER.debug "Task #{task.uri} done #{Time.now} -> "+result.to_s
- task.completed(result)
- rescue => ex
- LOGGER.error "task failed: "+ex.message
- LOGGER.error ": "+ex.backtrace.join("\n")
- task.error(ex.message)
- end
- end
- task.pid = task_pid
- LOGGER.debug "Started task: "+task.uri.to_s
- task.uri
- end
end
diff --git a/lib/validation.rb b/lib/validation.rb
index 340332a..76c4529 100644
--- a/lib/validation.rb
+++ b/lib/validation.rb
@@ -1,20 +1,70 @@
module OpenTox
class Validation
+ include OpenTox
- attr_accessor :uri
-
- def initialize(params)
- @uri = OpenTox::RestClientWrapper.post(File.join(CONFIG[:services]["opentox-validation"],"/crossvalidation"),params,nil,false)
- end
+ attr_accessor :report_uri, :qmrf_report_uri
- def self.crossvalidation(params)
+ def self.create_crossvalidation(params)
params[:uri] = File.join(CONFIG[:services]['opentox-validation'], "crossvalidation")
params[:num_folds] = 10 unless params[:num_folds]
params[:random_seed] = 2 unless params[:random_seed]
params[:stratified] = false unless params[:stratified]
- OpenTox::Validation.new(params)
+ uri = OpenTox::RestClientWrapper.post(File.join(CONFIG[:services]["opentox-validation"],"/crossvalidation"),params,nil,false)
+ OpenTox::Validation.new(uri)
end
+ def create_report
+ @report_uri = RestClientWrapper.post(File.join(CONFIG[:services]["opentox-validation"],"/report/crossvalidation"), :validation_uris => @uri).to_s
+ @report_uri
+ end
+
+ def create_qmrf_report
+ @qmrf_report_uri = RestClientWrapper.post(File.join(CONFIG[:services]["opentox-validation"],"/reach_report/qmrf"), :model_uri => @uri).to_s
+ @qmrf_report_uri
+ end
+
+ def summary(type)
+ v = YAML.load RestClientWrappper.get(File.join(@uri, 'statistics'),:accept => "application/x-yaml").to_s
+
+ case type
+ when "classification"
+ tp=0; tn=0; fp=0; fn=0; n=0
+ v[:classification_statistics][:confusion_matrix][:confusion_matrix_cell].each do |cell|
+ if cell[:confusion_matrix_predicted] == "true" and cell[:confusion_matrix_actual] == "true"
+ tp = cell[:confusion_matrix_value]
+ n += tp
+ elsif cell[:confusion_matrix_predicted] == "false" and cell[:confusion_matrix_actual] == "false"
+ tn = cell[:confusion_matrix_value]
+ n += tn
+ elsif cell[:confusion_matrix_predicted] == "false" and cell[:confusion_matrix_actual] == "true"
+ fn = cell[:confusion_matrix_value]
+ n += fn
+ elsif cell[:confusion_matrix_predicted] == "true" and cell[:confusion_matrix_actual] == "false"
+ fp = cell[:confusion_matrix_value]
+ n += fp
+ end
+ end
+ {
+ :nr_predictions => n,
+ :true_positives => tp,
+ :false_positives => fp,
+ :true_negatives => tn,
+ :false_negatives => fn,
+ :correct_predictions => 100*(tp+tn).to_f/n,
+ :weighted_area_under_roc => v[:classification_statistics][:weighted_area_under_roc].to_f,
+ :sensitivity => tp.to_f/(tp+fn),
+ :specificity => tn.to_f/(tn+fp),
+ }
+ when "regression"
+ {
+ :nr_predictions => v[:num_instances] - v[:num_unpredicted],
+ :r_square => v[:regression_statistics][:r_square],
+ :root_mean_squared_error => v[:regression_statistics][:root_mean_squared_error],
+ :mean_absolute_error => v[:regression_statistics][:mean_absolute_error],
+ }
+ end
+ end
+
end
end
--
cgit v1.2.3
From 7067bd44d5c97618ec6a968bbdfe6d6bda12a1cd Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Wed, 24 Nov 2010 13:13:40 +0100
Subject: opentox-ruby-api-wrapper renamed to opentox-ruby
---
lib/dataset.rb | 17 ++++++++++-
lib/model.rb | 63 +++++++++--------------------------------
lib/opentox-ruby-api-wrapper.rb | 13 ---------
lib/opentox-ruby.rb | 13 +++++++++
lib/serializer.rb | 10 ++++---
lib/task.rb | 15 ++++++----
6 files changed, 59 insertions(+), 72 deletions(-)
delete mode 100644 lib/opentox-ruby-api-wrapper.rb
create mode 100644 lib/opentox-ruby.rb
(limited to 'lib')
diff --git a/lib/dataset.rb b/lib/dataset.rb
index 4737ea1..c5704ae 100644
--- a/lib/dataset.rb
+++ b/lib/dataset.rb
@@ -32,6 +32,21 @@ module OpenTox
dataset
end
+ # Create dataset from CSV file (format specification: http://toxcreate.org/help)
+ # - loads data_entries, compounds, features
+ # - sets metadata (warnings) for parser errors
+ # - you will have to set remaining metadata manually
+ # @param [String] file CSV file path
+ # @return [OpenTox::Dataset] Dataset object with CSV data
+ def self.create_from_csv_file(file)
+ dataset = Dataset.create
+ parser = Parser::Spreadsheets.new
+ parser.dataset = dataset
+ parser.load_csv(File.open(file).read)
+ dataset.save
+ dataset
+ end
+
# Find a dataset and load all data. This can be time consuming, use Dataset.new together with one of the load_* methods for a fine grained control over data loading.
# @param [String] uri Dataset URI
# @return [OpenTox::Dataset] Dataset object with all data
@@ -299,7 +314,7 @@ module OpenTox
def measured_activities(compound)
source = @metadata[OT.hasSource]
- @data_entries[compound.uri].collect{|f,v| v if f.match(/#{source}/)}.compact
+ @data_entries[compound.uri].collect{|f,v| v if f.match(/#{source}/)}.compact.flatten
end
def neighbors(compound)
diff --git a/lib/model.rb b/lib/model.rb
index c6a2cf4..5654bcc 100644
--- a/lib/model.rb
+++ b/lib/model.rb
@@ -80,21 +80,16 @@ module OpenTox
OpenTox::Model::Lazar.find(model_uri)
end
-=begin
- # Create a new lazar model and return task
- # @param [optional,Hash] params Parameters for the lazar algorithm (OpenTox::Algorithm::Lazar)
- # @return [OpenTox::Task] Task for lazar model creation
- def self.create_task(params)
- task_uri = RestClientWrapper.post(File.join(CONFIG[:services]["opentox-algorithm"],"lazar"), {}, params, false)
- Task.find(task_uri)
- #model_uri = lazar_algorithm.run(params)
- #OpenTox::Model::Lazar.new(model_uri)
- end
-=end
+ # Get a parameter value
+ # @param [String] param Parameter name
+ # @return [String] Parameter value
def parameter(param)
@metadata[OT.parameters].collect{|p| p[OT.paramValue] if p[DC.title] == param}.compact.first
end
+ # Predict a dataset
+ # @param [String] dataset_uri Dataset URI
+ # @return [OpenTox::Dataset] Dataset with predictions
def predict_dataset(dataset_uri)
@prediction_dataset = Dataset.create
@prediction_dataset.add_metadata({
@@ -145,6 +140,7 @@ module OpenTox
if @neighbors.size == 0
@prediction_dataset.add_feature(prediction_feature_uri, {
+ OT.isA => OT.MeasuredFeature,
OT.hasSource => @uri,
DC.creator => @uri,
DC.title => URI.decode(File.basename( @metadata[OT.dependentVariables] )),
@@ -155,6 +151,7 @@ module OpenTox
else
@prediction_dataset.add_feature(prediction_feature_uri, {
+ OT.isA => OT.ModelPrediction,
OT.hasSource => @uri,
DC.creator => @uri,
DC.title => URI.decode(File.basename( @metadata[OT.dependentVariables] )),
@@ -171,8 +168,9 @@ module OpenTox
feature_uri = File.join( @prediction_dataset.uri, "feature", "descriptor", f.to_s)
features[feature] = feature_uri
@prediction_dataset.add_feature(feature_uri, {
+ OT.isA => OT.Substructure,
OT.smarts => feature,
- OT.p_value => @p_values[feature],
+ OT.pValue => @p_values[feature],
OT.effect => @effects[feature]
})
@prediction_dataset.add @compound.uri, feature_uri, true
@@ -190,7 +188,8 @@ module OpenTox
@prediction_dataset.add_feature(neighbor_uri, {
OT.compound => neighbor[:compound],
OT.similarity => neighbor[:similarity],
- OT.activity => neighbor[:activity]
+ OT.measuredActivity => neighbor[:activity],
+ OT.isA => OT.Neighbor
})
@prediction_dataset.add @compound.uri, neighbor_uri, true
f = 0 unless f
@@ -204,8 +203,9 @@ module OpenTox
unless features.has_key? feature
features[feature] = feature_uri
@prediction_dataset.add_feature(feature_uri, {
+ OT.isA => OT.Substructure,
OT.smarts => feature,
- OT.p_value => @p_values[feature],
+ OT.pValue => @p_values[feature],
OT.effect => @effects[feature]
})
f+=1
@@ -228,7 +228,6 @@ module OpenTox
@neighbors = []
@fingerprints.each do |training_compound,training_features|
- #@activities.each do |training_compound,activities|
sim = eval("#{@similarity_algorithm}(@compound_features,training_features,@p_values)")
if sim > @min_sim
@activities[training_compound].each do |act|
@@ -244,17 +243,6 @@ module OpenTox
end
-=begin
- def cached_prediction
- dataset_uri = PredictionCache.find(:model_uri => @uri, :compound_uri => @compound.uri).dataset_uri)
- return false unless dataset_uri
- @prediction_dataset = Dataset.find(dataset_uri)
- return false unless @prediction_dataset
- LOGGER.debug "Serving cached prediction"
- true
- end
-=end
-
# Find database activities and store them in @prediction_dataset
# @return [Boolean] true if compound has databasse activities, false if not
def database_activity
@@ -278,29 +266,6 @@ module OpenTox
RestClientWrapper.delete @uri unless @uri == CONFIG[:services]["opentox-model"]
end
-=begin
-=end
-
-=begin
- def self.create_from_dataset(dataset_uri,feature_dataset_uri,prediction_feature=nil)
- training_activities = OpenTox::Dataset.find(dataset_uri)
- training_features = OpenTox::Dataset.find(feature_dataset_uri)
- unless prediction_feature # try to read prediction_feature from dataset
- raise "#{training_activities.features.size} features in dataset #{dataset_uri}. Please provide a prediction_feature parameter." unless training_activities.features.size == 1
- prediction_feature = training_activities.features.keys.first
- params[:prediction_feature] = prediction_feature
- end
- lazar = Lazar.new
- training_features = OpenTox::Dataset.new(feature_dataset_uri)
- case training_features.feature_type
- when "classification"
- lazar.similarity_algorithm = "weighted_tanimoto"
- when "regression"
- lazar.similarity_algorithm = "weighted_euclid"
- end
- end
-=end
-
end
end
end
diff --git a/lib/opentox-ruby-api-wrapper.rb b/lib/opentox-ruby-api-wrapper.rb
deleted file mode 100644
index 9f9ff26..0000000
--- a/lib/opentox-ruby-api-wrapper.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-['rubygems', 'sinatra', 'sinatra/url_for', 'rest_client', 'yaml', 'cgi', 'spork', 'overwrite', 'environment'].each do |lib|
- require lib
-end
-
-begin
- require 'openbabel'
-rescue LoadError
- puts "Please install Openbabel with 'rake openbabel:install' in the compound component"
-end
-
-['opentox', 'compound','dataset', 'parser','serializer', 'algorithm','model','task','validation','feature', 'rest_client_wrapper'].each do |lib|
- require lib
-end
diff --git a/lib/opentox-ruby.rb b/lib/opentox-ruby.rb
new file mode 100644
index 0000000..9f9ff26
--- /dev/null
+++ b/lib/opentox-ruby.rb
@@ -0,0 +1,13 @@
+['rubygems', 'sinatra', 'sinatra/url_for', 'rest_client', 'yaml', 'cgi', 'spork', 'overwrite', 'environment'].each do |lib|
+ require lib
+end
+
+begin
+ require 'openbabel'
+rescue LoadError
+ puts "Please install Openbabel with 'rake openbabel:install' in the compound component"
+end
+
+['opentox', 'compound','dataset', 'parser','serializer', 'algorithm','model','task','validation','feature', 'rest_client_wrapper'].each do |lib|
+ require lib
+end
diff --git a/lib/serializer.rb b/lib/serializer.rb
index 9b3af39..495702a 100644
--- a/lib/serializer.rb
+++ b/lib/serializer.rb
@@ -40,11 +40,13 @@ module OpenTox
DC.contributor => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
DC.creator => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
DC.description => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ DC.date => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
OT.isA => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
OT.Warnings => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
XSD.anyURI => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
OT.hasStatus => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
OT.resultURI => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.percentageCompleted => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
OT.hasSource => { RDF["type"] => [{ "type" => "uri", "value" => OWL.DatatypeProperty }] } ,
OT.value => { RDF["type"] => [{ "type" => "uri", "value" => OWL.DatatypeProperty }] } ,
@@ -125,10 +127,7 @@ module OpenTox
def add_metadata(uri,metadata)
id = 0
metadata.each do |u,v|
- if v.is_a? String
- @object[uri] = {} unless @object[uri]
- @object[uri][u] = [{"type" => type(v), "value" => v }]
- elsif v.is_a? Array and u == OT.parameters
+ if v.is_a? Array and u == OT.parameters
@object[uri][u] = [] unless @object[uri][u]
v.each do |value|
id+=1
@@ -139,6 +138,9 @@ module OpenTox
@object[genid][name] = [{"type" => type(entry), "value" => entry }]
end
end
+ else # v.is_a? String
+ @object[uri] = {} unless @object[uri]
+ @object[uri][u] = [{"type" => type(v), "value" => v }]
end
end
end
diff --git a/lib/task.rb b/lib/task.rb
index 5b2b5d9..5b59395 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -33,24 +33,29 @@ module OpenTox
# @return [OPenTox::Task] Task
def self.create( title=nil, creator=nil, max_duration=DEFAULT_TASK_MAX_DURATION, description=nil )
+ params = {:title=>title, :creator=>creator, :max_duration=>max_duration, :description=>description }
+ task_uri = RestClientWrapper.post(CONFIG[:services]["opentox-task"], params, nil, false).to_s
+ task = Task.new(task_uri.chomp)
+
# measure current memory consumption
memory = `free -m|sed -n '2p'`.split
free_memory = memory[3].to_i + memory[6].to_i # include cache
if free_memory < 20 # require at least 200 M free memory
LOGGER.warn "Cannot start task - not enough memory left (#{free_memory} M free)"
- raise "Insufficient memory to start a new task"
+ task.cancel
+ return task
+ #raise "Insufficient memory to start a new task"
end
cpu_load = `cat /proc/loadavg`.split(/\s+/)[0..2].collect{|c| c.to_f}
nr_cpu_cores = `cat /proc/cpuinfo |grep "cpu cores"|cut -d ":" -f2|tr -d " "`.split("\n").collect{|c| c.to_i}.inject{|sum,n| sum+n}
if cpu_load[0] > nr_cpu_cores and cpu_load[0] > cpu_load[1] and cpu_load[1] > cpu_load[2] # average CPU load of the last minute is high and CPU load is increasing
LOGGER.warn "Cannot start task - CPU load too high (#{cpu_load.join(", ")})"
- raise "Server too busy to start a new task"
+ task.cancel
+ return task
+ #raise "Server too busy to start a new task"
end
- params = {:title=>title, :creator=>creator, :max_duration=>max_duration, :description=>description }
- task_uri = RestClientWrapper.post(CONFIG[:services]["opentox-task"], params, nil, false).to_s
- task = Task.new(task_uri.chomp)
task_pid = Spork.spork(:logger => LOGGER) do
LOGGER.debug "Task #{task.uri} started #{Time.now}"
--
cgit v1.2.3
From d3190ba5fd87db05bdf3219dae00afaf31257718 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Tue, 30 Nov 2010 12:43:04 +0100
Subject: Accept: text/uri-list for running algoritms
---
lib/algorithm.rb | 2 +-
lib/task.rb | 6 +++---
2 files changed, 4 insertions(+), 4 deletions(-)
(limited to 'lib')
diff --git a/lib/algorithm.rb b/lib/algorithm.rb
index a6fa4a7..a2f7786 100644
--- a/lib/algorithm.rb
+++ b/lib/algorithm.rb
@@ -15,7 +15,7 @@ module OpenTox
# @param [optional,Hash] params Algorithm parameters
# @return [String] URI of new resource (dataset, model, ...)
def run(params=nil)
- RestClientWrapper.post(@uri, params).to_s
+ RestClientWrapper.post(@uri, {:accept => 'text/uri-list'}, params).to_s
end
# Get OWL-DL representation in RDF/XML format
diff --git a/lib/task.rb b/lib/task.rb
index 5b59395..17f95e6 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -243,10 +243,10 @@ module OpenTox
"'" unless @metadata[OT.resultURI] and @metadata[OT.resultURI].to_s.uri? if completed?
if @http_code == 202
- raise "illegal task state, code is 202, but hasStatus is not Running: '"+@metadata[OT.hasStatus]+"'" unless running?
+ raise "#{@uri}: illegal task state, code is 202, but hasStatus is not Running: '"+@metadata[OT.hasStatus]+"'" unless running?
elsif @http_code == 201
- raise "illegal task state, code is 201, but hasStatus is not Completed: '"+@metadata[OT.hasStatus]+"'" unless completed?
- raise "illegal task state, code is 201, resultURI is no task-URI: '"+@metadata[OT.resultURI].to_s+
+ raise "#{@uri}: illegal task state, code is 201, but hasStatus is not Completed: '"+@metadata[OT.hasStatus]+"'" unless completed?
+ raise "#{@uri}: illegal task state, code is 201, resultURI is no task-URI: '"+@metadata[OT.resultURI].to_s+
"'" unless @metadata[OT.resultURI] and @metadata[OT.resultURI].to_s.uri?
end
rescue => ex
--
cgit v1.2.3
From 64e5d2890f42cef112fbe768f6bfd54b746686de Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Fri, 3 Dec 2010 14:37:09 +0100
Subject: underscore method added to String class
---
lib/compound.rb | 6 ++++++
lib/overwrite.rb | 44 ++++++++++++++++++++++++++------------------
2 files changed, 32 insertions(+), 18 deletions(-)
(limited to 'lib')
diff --git a/lib/compound.rb b/lib/compound.rb
index 6834860..a85507b 100644
--- a/lib/compound.rb
+++ b/lib/compound.rb
@@ -68,6 +68,12 @@ module OpenTox
c
end
+ # Get InChI
+ # @return [String] InChI string
+ def to_inchi
+ @inchi
+ end
+
# Get (canonical) smiles
# @return [String] Smiles string
def to_smiles
diff --git a/lib/overwrite.rb b/lib/overwrite.rb
index f39fec3..8d787a6 100644
--- a/lib/overwrite.rb
+++ b/lib/overwrite.rb
@@ -13,26 +13,34 @@ class Sinatra::Base
end
class String
- def task_uri?
- self.uri? && !self.match(/task/).nil?
- end
-
- def dataset_uri?
- self.uri? && !self.match(/dataset/).nil?
- end
-
- def self.model_uri?
- self.uri? && !self.match(/model/).nil?
- end
+ def task_uri?
+ self.uri? && !self.match(/task/).nil?
+ end
+
+ def dataset_uri?
+ self.uri? && !self.match(/dataset/).nil?
+ end
+
+ def self.model_uri?
+ self.uri? && !self.match(/model/).nil?
+ end
- def uri?
- begin
- u = URI::parse(self)
- return (u.scheme!=nil and u.host!=nil)
- rescue URI::InvalidURIError
- return false
- end
+ def uri?
+ begin
+ u = URI::parse(self)
+ return (u.scheme!=nil and u.host!=nil)
+ rescue URI::InvalidURIError
+ return false
end
+ end
+
+ def underscore
+ self.gsub(/::/, '/').
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
+ tr("-", "_").
+ downcase
+ end
end
require 'logger'
--
cgit v1.2.3
From bb99bb49636db1d3f07b6f540dc8624a677ade2f Mon Sep 17 00:00:00 2001
From: mr
Date: Mon, 6 Dec 2010 12:09:06 +0100
Subject: insert basic a&a libs to development branch
---
lib/authorization.rb | 291 +++++++++++++++++++++++++++++++++++++++++++++++++++
lib/environment.rb | 2 +
lib/helper.rb | 72 ++++++++++---
lib/opentox-ruby.rb | 2 +-
lib/policy.rb | 242 ++++++++++++++++++++++++++++++++++++++++++
5 files changed, 592 insertions(+), 17 deletions(-)
create mode 100644 lib/authorization.rb
create mode 100644 lib/policy.rb
(limited to 'lib')
diff --git a/lib/authorization.rb b/lib/authorization.rb
new file mode 100644
index 0000000..0cba96a
--- /dev/null
+++ b/lib/authorization.rb
@@ -0,0 +1,291 @@
+module OpenTox
+
+ #Module for Authorization and Authentication
+ #@example Authentication
+ # require "opentox-ruby-api-wrapper"
+ # OpenTox::Authorization::AA_SERVER = "https://opensso.in-silico.ch" #if not set in .opentox/conf/[environment].yaml
+ # token = OpenTox::Authorization.authenticate("benutzer", "passwort")
+ #@see http://www.opentox.org/dev/apis/api-1.2/AA OpenTox A&A API 1.2 specification
+
+ module Authorization
+
+ #Helper Class AA to create and send default policies out of xml templates
+ #@example Creating a default policy to a URI
+ # aa=OpenTox::Authorization::AA.new(tok)
+ # xml=aa.get_xml('http://uri....')
+ # OpenTox::Authorization.create_policy(xml,tok)
+
+ class AA
+ attr_accessor :user, :token_id, :policy
+
+ #Generates AA object - requires token_id
+ # @param [String] token_id
+ def initialize(token_id)
+ @user = Authorization.get_user(token_id)
+ @token_id = token_id
+ @policy = Policies.new()
+ end
+
+ #Cleans AA Policies and loads default xml file into policy attribute
+ #set uri and user, returns Policyfile(XML) for open-sso
+ # @param [String] URI to create a policy for
+ def get_xml(uri)
+ @policy.drop_policies
+ @policy.load_default_policy(@user, uri)
+ return @policy.to_xml
+ end
+
+ #Loads and sends Policyfile(XML) to open-sso server
+ # @param [String] URI to create a policy for
+ def send(uri)
+ xml = get_xml(uri)
+ ret = false
+ ret = Authorization.create_policy(xml, @token_id)
+ LOGGER.debug "Policy send with token_id: #{@token_id}"
+ LOGGER.warn "Not created Policy is: #{xml}" if !ret
+ ret
+ end
+
+ end
+
+ #Returns the open-sso server set in the config file .opentox/config/[environment].yaml
+ # @return [String, nil] the openSSO server URI or nil
+ def self.server
+ return AA_SERVER
+ end
+
+ #Authentication against OpenSSO. Returns token. Requires Username and Password.
+ # @param [String, String]Username,Password
+ # @return [String, nil] gives token_id or nil
+ def self.authenticate(user, pw)
+ return true if !AA_SERVER
+ begin
+ resource = RestClient::Resource.new("#{AA_SERVER}/auth/authenticate")
+ out = resource.post(:username=>user, :password => pw).sub("token.id=","").sub("\n","")
+ return out
+ rescue
+ return nil
+ end
+ end
+
+ #Logout on opensso. Make token invalid. Requires token
+ # @param [String]token_id the token_id
+ # @return [Boolean] true if logout is OK
+ def self.logout(token_id)
+ begin
+ resource = RestClient::Resource.new("#{AA_SERVER}/auth/logout")
+ resource.post(:subjectid => token_id)
+ return true
+ rescue
+ return false
+ end
+ end
+
+ #Authorization against OpenSSO for a URI with request-method (action) [GET/POST/PUT/DELETE]
+ # @param [String,String,String]uri,action,token_id
+ # @return [Boolean, nil] returns true, false or nil (if authorization-request fails).
+ def self.authorize(uri, action, token_id)
+ return true if !AA_SERVER
+ begin
+ resource = RestClient::Resource.new("#{AA_SERVER}/auth/authorize")
+ return true if resource.post(:uri => uri, :action => action, :subjectid => token_id) == "boolean=true\n"
+ rescue
+ return nil
+ end
+ end
+
+ #Checks if a token is a valid token
+ # @param [String]token_id token_id from openSSO session
+ # @return [Boolean] token_id is valid or not.
+ def self.is_token_valid(token_id)
+ return true if !AA_SERVER
+ begin
+ resource = RestClient::Resource.new("#{AA_SERVER}/auth/isTokenValid")
+ return true if resource.post(:tokenid => token_id) == "boolean=true\n"
+ rescue
+ return false
+ end
+ end
+
+ #Returns array with all policies of the token owner
+ # @param [String]token_id requires token_id
+ # @return [Array, nil] returns an Array of policy names or nil if request fails
+ def self.list_policies(token_id)
+ begin
+ resource = RestClient::Resource.new("#{AA_SERVER}/pol")
+ out = resource.get(:subjectid => token_id)
+ return out.split("\n")
+ rescue
+ return nil
+ end
+ end
+
+ #Returns a policy in xml-format
+ # @param [String, String]policy,token_id
+ # @return [String] XML of the policy
+ def self.list_policy(policy, token_id)
+ begin
+ resource = RestClient::Resource.new("#{AA_SERVER}/pol")
+ return resource.get(:subjectid => token_id,:id => policy)
+ rescue
+ return nil
+ end
+ end
+
+ #Returns the owner (who created the first policy) of an URI
+ # @param [String, String]uri,token_id
+ # return [String, nil]owner,nil returns owner of the URI
+ def self.get_uri_owner(uri, token_id)
+ begin
+ resource = RestClient::Resource.new("#{AA_SERVER}/pol")
+ return resource.get(:uri => uri, :subjectid => token_id).sub("\n","")
+ rescue
+ return nil
+ end
+ end
+
+ #Checks if a policy exists to a URI. Requires URI and token.
+ # @param [String, String]uri,token_id
+ # return [Boolean]
+ def self.uri_has_policy(uri, token_id)
+ owner = get_uri_owner(uri, token_id)
+ return true if owner and owner != "null"
+ false
+ end
+
+ #List all policynames for a URI. Requires URI and token.
+ # @param [String, String]uri,token_id
+ # return [Array, nil] returns an Array of policy names or nil if request fails
+ def self.list_uri_policies(uri, token_id)
+ begin
+ resource = RestClient::Resource.new("#{AA_SERVER}/pol")
+ out = resource.get(:uri => uri, :polnames => true, :subjectid => token_id)
+ policies = []; notfirstline = false
+ out.split("\n").each do |line|
+ policies << line if notfirstline
+ notfirstline = true
+ end
+ return policies
+ rescue
+ return nil
+ end
+ end
+
+ #Sends a policy in xml-format to opensso server. Requires policy-xml and token.
+ # @param [String, String]policyxml,token_id
+ # return [Boolean] returns true if policy is created
+ def self.create_policy(policy, token_id)
+ begin
+# resource = RestClient::Resource.new("#{AA_SERVER}/Pol/opensso-pol")
+ LOGGER.debug "OpenTox::Authorization.create_policy policy: #{policy[168,43]} with token:" + token_id.to_s + " length: " + token_id.length.to_s
+# return true if resource.post(policy, :subjectid => token_id, :content_type => "application/xml")
+ return true if RestClientWrapper.post("#{AA_SERVER}/pol", {:subjectid => token_id, :content_type => "application/xml"}, policy)
+ rescue
+ return false
+ end
+ end
+
+ #Deletes a policy
+ # @param [String, String]policyname,token_id
+ # @return [Boolean,nil]
+ def self.delete_policy(policy, token_id)
+ begin
+ resource = RestClient::Resource.new("#{AA_SERVER}/pol")
+ LOGGER.debug "OpenTox::Authorization.delete_policy policy: #{policy} with token: #{token_id}"
+ return true if resource.delete(:subjectid => token_id, :id => policy)
+ rescue
+ return nil
+ end
+ end
+
+ #Returns array of all possible LDAP-Groups
+ # @param [String]token_id
+ # @return [Array]
+ def self.list_groups(token_id)
+ begin
+ resource = RestClient::Resource.new("#{AA_SERVER}/opensso/identity/search")
+ grps = resource.post(:admin => token_id, :attributes_names => "objecttype", :attributes_values_objecttype => "group")
+ grps.split("\n").collect{|x| x.sub("string=","")}
+ rescue
+ []
+ end
+ end
+
+ #Returns array of the LDAP-Groups of an user
+ # @param [String]token_id
+ # @return [Array] gives array of LDAP groups of a user
+ def self.list_user_groups(user, token_id)
+ begin
+ resource = RestClient::Resource.new("#{AA_SERVER}/opensso/identity/read")
+ out = resource.post(:name => user, :admin => token_id, :attributes_names => "group")
+ grps = []
+ out.split("\n").each do |line|
+ grps << line.sub("identitydetails.group=","") if line.include?("identitydetails.group=")
+ end
+ return grps
+ rescue
+ []
+ end
+ end
+
+ #Returns the owner (user id) of a token
+ # @param [String]token_id
+ # @return [String]user
+ def self.get_user(token_id)
+ begin
+ resource = RestClient::Resource.new("#{AA_SERVER}/opensso/identity/attributes")
+ out = resource.post(:subjectid => token_id, :attributes_names => "uid")
+ user = ""; check = false
+ out.split("\n").each do |line|
+ if check
+ user = line.sub("userdetails.attribute.value=","") if line.include?("userdetails.attribute.value=")
+ check = false
+ end
+ check = true if line.include?("userdetails.attribute.name=uid")
+ end
+ return user
+ rescue
+ nil
+ end
+ end
+
+ #Send default policy with Authorization::AA class
+ # @param [String, String]URI,token_id
+ def self.send_policy(uri, token_id)
+ return true if !AA_SERVER
+ aa = Authorization::AA.new(token_id)
+ ret = aa.send(uri)
+ LOGGER.debug "OpenTox::Authorization send policy for URI: #{uri} | token_id: #{token_id} - policy created: #{ret}"
+ ret
+ end
+
+ #Deletes all policies of an URI
+ # @param [String, String]URI,token_id
+ # @return [Boolean]
+ def self.delete_policies_from_uri(uri, token_id)
+ policies = list_uri_policies(uri, token_id)
+ policies.each do |policy|
+ ret = delete_policy(policy, token_id)
+ LOGGER.debug "OpenTox::Authorization delete policy: #{policy} - with result: #{ret}"
+ end
+ return true
+ end
+
+ #Checks (if token_id is valid) if a policy exist and create default policy if not
+ def self.check_policy(uri, token_id)
+ token_valid = OpenTox::Authorization.is_token_valid(token_id)
+ LOGGER.debug "OpenTox::Authorization.check_policy with uri: #{uri}, token_id: #{token_id} is valid: #{token_valid}"
+ if uri and token_valid
+ if !uri_has_policy(uri, token_id)
+ return send_policy(uri, token_id)
+ else
+ LOGGER.debug "OpenTox::Authorization.check_policy URI: #{uri} has already a Policy."
+ end
+ end
+ true
+ end
+
+ end
+end
+
+
diff --git a/lib/environment.rb b/lib/environment.rb
index 4f1cc80..1761d92 100644
--- a/lib/environment.rb
+++ b/lib/environment.rb
@@ -83,6 +83,8 @@ class OwlNamespace
end
+AA_SERVER = CONFIG[:authorization] ? (CONFIG[:authorization][:server] ? CONFIG[:authorization][:server] : nil) : nil
+
RDF = OwlNamespace.new 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'
OWL = OwlNamespace.new 'http://www.w3.org/2002/07/owl#'
DC = OwlNamespace.new 'http://purl.org/dc/elements/1.1/'
diff --git a/lib/helper.rb b/lib/helper.rb
index a9f451e..b69f9b4 100644
--- a/lib/helper.rb
+++ b/lib/helper.rb
@@ -1,26 +1,66 @@
helpers do
# Authentification
- def protected!
- response['WWW-Authenticate'] = %(Basic realm="Testing HTTP Auth") and \
+ def protected!(token_id)
+ if env["session"]
+ flash[:notice] = "You don't have access to this section: " and \
+ redirect back and \
+ return unless authorized?(token_id)
+ end
throw(:halt, [401, "Not authorized\n"]) and \
- return unless authorized?
+ return unless authorized?(token_id)
end
-
- def authorized?
- @auth ||= Rack::Auth::Basic::Request.new(request.env)
- @auth.provided? && @auth.basic? && @auth.credentials && @auth.credentials == ['api', API_KEY]
+
+ def authorized?(token_id)
+ case request.env['REQUEST_METHOD']
+ when "DELETE", "PUT"
+ ret = OpenTox::Authorization.authorize(request.env['SCRIPT_URI'], request.env['REQUEST_METHOD'], token_id)
+ LOGGER.debug "OpenTox helpers OpenTox::Authorization authorized? method: #{request.env['REQUEST_METHOD']} , URI: #{request.env['SCRIPT_URI']}, token_id: #{token_id} with return #{ret}."
+ return ret
+ when "POST"
+ if OpenTox::Authorization.is_token_valid(token_id)
+ LOGGER.debug "OpenTox helpers OpenTox::Authorization.is_token_valid: true"
+ return true
+ end
+ LOGGER.warn "OpenTox helpers POST on #{request.env['SCRIPT_URI']} with token_id: #{token_id} false."
+ end
+ LOGGER.debug "Not authorized for: 1. #{request['SCRIPT_URI']} 2. #{request.env['SCRIPT_URI']} with Method: #{request.env['REQUEST_METHOD']} with Token #{token_id}"
+ LOGGER.debug "Request infos: #{request.inspect}"
+ return false
end
-
-=begin
- def xml(object)
- builder do |xml|
- xml.instruct!
- object.to_xml
- end
- end
-=end
+ def unprotected_requests
+ case env['REQUEST_URI']
+ when /\/login$|\/logout$|\/predict$|\/upload$/
+ return true
+ when /\/compound|\/feature|\/task|\/toxcreate/ #to fix: read from config | validation should be protected
+ return true
+ else
+ return false
+ end
+ end
+
+ def check_token_id(token_id)
+ return false if !token_id
+ return true if token_id.size > 62
+ false
+ end
+end
+before do
+
+ unless unprotected_requests or env['REQUEST_METHOD'] == "GET"
+ begin
+ token_id = session[:token_id] if session[:token_id]
+ token_id = params[:token_id] if params[:token_id] and !check_token_id(token_id)
+ token_id = request.env['HTTP_TOKEN_ID'] if request.env['HTTP_TOKEN_ID'] and !check_token_id(token_id)
+ # see http://rack.rubyforge.org/doc/SPEC.html
+ rescue
+ LOGGER.debug "OpenTox api wrapper: helper before filter: NO token_id."
+ token_id = ""
+ end
+ protected!(token_id) if AA_SERVER
+ end
+
end
diff --git a/lib/opentox-ruby.rb b/lib/opentox-ruby.rb
index 9f9ff26..c0bff95 100644
--- a/lib/opentox-ruby.rb
+++ b/lib/opentox-ruby.rb
@@ -8,6 +8,6 @@ rescue LoadError
puts "Please install Openbabel with 'rake openbabel:install' in the compound component"
end
-['opentox', 'compound','dataset', 'parser','serializer', 'algorithm','model','task','validation','feature', 'rest_client_wrapper'].each do |lib|
+['opentox', 'compound','dataset', 'parser','serializer', 'algorithm','model','task','validation','feature', 'rest_client_wrapper', 'authorization', 'policy', 'helper'].each do |lib|
require lib
end
diff --git a/lib/policy.rb b/lib/policy.rb
new file mode 100644
index 0000000..0ef8298
--- /dev/null
+++ b/lib/policy.rb
@@ -0,0 +1,242 @@
+module OpenTox
+ require "rexml/document"
+
+ #Module for policy-processing
+ # @see also http://www.opentox.org/dev/apis/api-1.2/AA for opentox API specs
+ # Class Policies corresponds to container of an xml-policy-fle
+ class Policies
+
+ attr_accessor :name, :policies
+
+ def initialize()
+ @policies = {}
+ end
+
+ #create new policy instance with name
+ # @param [String]name of the policy
+ def new_policy(name)
+ @policies[name] = Policy.new(name)
+ end
+
+ #drop a specific policy in a policies instance
+ # @param [String]name of the policy
+ # @return [Boolean]
+ def drop_policy(name)
+ return true if @policies.delete(name)
+ end
+
+ #drop all policies in a policies instance
+ def drop_policies
+ @policies.each do |name, policy|
+ drop_policy(name)
+ end
+ return true
+ end
+
+ #loads a default policy template in policies instance
+ def load_default_policy(user, uri, group="member")
+ template = case user
+ when "guest", "anonymous" then "default_guest_policy"
+ else "default_policy"
+ end
+ xml = File.read(File.join(File.dirname(__FILE__), "templates/#{template}.xml"))
+ self.load_xml(xml)
+ datestring = Time.now.strftime("%Y-%m-%d-%H-%M-%S-x") + rand(1000).to_s
+
+ @policies["policy_user"].name = "policy_user_#{user}_#{datestring}"
+ @policies["policy_user"].rules["rule_user"].uri = uri
+ @policies["policy_user"].rules["rule_user"].name = "rule_user_#{user}_#{datestring}"
+ @policies["policy_user"].subjects["subject_user"].name = "subject_user_#{user}_#{datestring}"
+ @policies["policy_user"].subjects["subject_user"].value = "uid=#{user},ou=people,dc=opentox,dc=org"
+ @policies["policy_user"].subject_group = "subjects_user_#{user}_#{datestring}"
+
+ @policies["policy_group"].name = "policy_group_#{group}_#{datestring}"
+ @policies["policy_group"].rules["rule_group"].uri = uri
+ @policies["policy_group"].rules["rule_group"].name = "rule_group_#{group}_#{datestring}"
+ @policies["policy_group"].subjects["subject_group"].name = "subject_group_#{group}_#{datestring}"
+ @policies["policy_group"].subjects["subject_group"].value = "cn=#{group},ou=groups,dc=opentox,dc=org"
+ @policies["policy_group"].subject_group = "subjects_#{group}_#{datestring}"
+ return true
+ end
+
+ #loads a xml template
+ def load_xml(xml)
+ rexml = REXML::Document.new(xml)
+ rexml.elements.each("Policies/Policy") do |pol| #Policies
+ policy_name = pol.attributes["name"]
+ new_policy(policy_name)
+ #@policies[policy_name] = Policy.new(policy_name)
+ rexml.elements.each("Policies/Policy[@name='#{policy_name}']/Rule") do |r| #Rules
+ rule_name = r.attributes["name"]
+ uri = rexml.elements["Policies/Policy[@name='#{policy_name}']/Rule[@name='#{rule_name}']/ResourceName"].attributes["name"]
+ @policies[policy_name].rules[rule_name] = @policies[policy_name].new_rule(rule_name, uri)
+ rexml.elements.each("Policies/Policy[@name='#{policy_name}']/Rule[@name='#{rule_name}']/AttributeValuePair") do |attribute_pairs|
+ action=nil; value=nil;
+ attribute_pairs.each_element do |elem|
+ action = elem.attributes["name"] if elem.attributes["name"]
+ value = elem.text if elem.text
+ end
+ if action and value
+ case action
+ when "GET"
+ @policies[policy_name].rules[rule_name].get = value
+ when "POST"
+ @policies[policy_name].rules[rule_name].post = value
+ when "PUT"
+ @policies[policy_name].rules[rule_name].put = value
+ when "DELETE"
+ @policies[policy_name].rules[rule_name].delete = value
+ end
+ end
+ end
+ end
+ rexml.elements.each("Policies/Policy[@name='#{policy_name}']/Subjects") do |subjects| #Subjects
+ @policies[policy_name].subject_group = subjects.attributes["name"]
+ rexml.elements.each("Policies/Policy[@name='#{policy_name}']/Subjects[@name='#{@policies[policy_name].subject_group}']/Subject") do |s| #Subject
+ subject_name = s.attributes["name"]
+ subject_type = s.attributes["type"]
+ subject_value = rexml.elements["Policies/Policy[@name='#{policy_name}']/Subjects[@name='#{@policies[policy_name].subject_group}']/Subject[@name='#{subject_name}']/AttributeValuePair/Value"].text
+ @policies[policy_name].new_subject(subject_name, subject_type, subject_value) if subject_name and subject_type and subject_value
+ end
+ end
+ end
+ end
+
+ #generates xml from policies instance
+ def to_xml
+ doc = REXML::Document.new()
+ doc << REXML::DocType.new("Policies", "PUBLIC \"-//Sun Java System Access Manager7.1 2006Q3\n Admin CLI DTD//EN\" \"jar://com/sun/identity/policy/policyAdmin.dtd\"")
+ doc.add_element(REXML::Element.new("Policies"))
+
+ @policies.each do |name, pol|
+ policy = REXML::Element.new("Policy")
+ policy.attributes["name"] = pol.name
+ policy.attributes["referralPolicy"] = false
+ policy.attributes["active"] = true
+ @policies[name].rules.each do |r,rl|
+ rule = @policies[name].rules[r]
+ out_rule = REXML::Element.new("Rule")
+ out_rule.attributes["name"] = rule.name
+ servicename = REXML::Element.new("ServiceName")
+ servicename.attributes["name"]="iPlanetAMWebAgentService"
+ out_rule.add_element(servicename)
+ rescourcename = REXML::Element.new("ResourceName")
+ rescourcename.attributes["name"] = rule.uri
+ out_rule.add_element(rescourcename)
+
+ ["get","post","delete","put"].each do |act|
+ if rule.method(act).call
+ attribute = REXML::Element.new("Attribute")
+ attribute.attributes["name"] = act.upcase
+ attributevaluepair = REXML::Element.new("AttributeValuePair")
+ attributevaluepair.add_element(attribute)
+ attributevalue = REXML::Element.new("Value")
+ attributevaluepair.add_element(attributevalue)
+ attributevalue.add_text REXML::Text.new(rule.method(act).call)
+ out_rule.add_element(attributevaluepair)
+
+ end
+ end
+ policy.add_element(out_rule)
+ end
+
+ subjects = REXML::Element.new("Subjects")
+ subjects.attributes["name"] = pol.subject_group
+ subjects.attributes["description"] = ""
+ @policies[name].subjects.each do |subj, subjs|
+ subject = REXML::Element.new("Subject")
+ subject.attributes["name"] = pol.subjects[subj].name
+ subject.attributes["type"] = pol.subjects[subj].type
+ subject.attributes["includeType"] = "inclusive"
+ attributevaluepair = REXML::Element.new("AttributeValuePair")
+ attribute = REXML::Element.new("Attribute")
+ attribute.attributes["name"] = "Values"
+ attributevaluepair.add_element(attribute)
+ attributevalue = REXML::Element.new("Value")
+ attributevalue.add_text REXML::Text.new(pol.subjects[subj].value)
+ attributevaluepair.add_element(attributevalue)
+ subject.add_element(attributevaluepair)
+ subjects.add_element(subject)
+ end
+ policy.add_element(subjects)
+ doc.root.add_element(policy)
+ end
+ out = ""
+ doc.write(out, 2)
+ return out
+ end
+
+ end
+
+ #single policy in a policies instance
+ class Policy
+
+ attr_accessor :name, :rules, :subject_group, :subjects
+
+ def initialize(name)
+ @name = name
+ @rules = {}
+ @subject_group = ""
+ @subjects = {}
+ end
+
+ #create a new rule instance for the policy
+ def new_rule(name, uri)
+ @rules[name] = Rule.new(name, uri)
+ end
+
+ #create a new subject instance for the policy
+ def new_subject(name, type, value)
+ @subjects[name] = Subject.new(name, type, value)
+ end
+
+ #rule inside a policy
+ class Rule
+
+ attr_accessor :name, :uri, :get, :post, :put, :delete
+
+ def initialize(name, uri)
+ @name = name
+ @uri = uri
+ end
+
+ def rename(new, old)
+ self[new] = self.delete(old)
+ self[new].name = new
+ end
+
+ def get=(value)
+ @get = check_value(value, @get)
+ end
+
+ def post=(value)
+ @post = check_value(value, @post)
+ end
+
+ def delete=(value)
+ @delete = check_value(value, @delete)
+ end
+
+ def put=(value)
+ @put = check_value(value, @put)
+ end
+
+ private
+ #checks if value is allow or deny. returns old value if not valid.
+ def check_value(new_value, old_value)
+ return (new_value=="allow" || new_value=="deny" || new_value==nil) ? new_value : old_value
+ end
+ end
+
+ class Subject
+
+ attr_accessor :name, :type, :value
+
+ def initialize(name, type, value)
+ @name = name
+ @type = type
+ @value = value
+ end
+ end
+ end
+end
\ No newline at end of file
--
cgit v1.2.3
From c4504c72ffb2920de65399a2dc0a2c29fe04a52d Mon Sep 17 00:00:00 2001
From: mr
Date: Thu, 9 Dec 2010 10:46:13 +0100
Subject: A&A implementation
---
lib/dataset.rb | 12 +++++---
lib/helper.rb | 4 +--
lib/model.rb | 4 +--
lib/templates/default_guest_policy.xml | 53 ++++++++++++++++++++++++++++++++++
lib/templates/default_policy.xml | 53 ++++++++++++++++++++++++++++++++++
5 files changed, 118 insertions(+), 8 deletions(-)
create mode 100644 lib/templates/default_guest_policy.xml
create mode 100644 lib/templates/default_policy.xml
(limited to 'lib')
diff --git a/lib/dataset.rb b/lib/dataset.rb
index c5704ae..bbd8b8b 100644
--- a/lib/dataset.rb
+++ b/lib/dataset.rb
@@ -6,6 +6,7 @@ module OpenTox
include OpenTox
attr_reader :features, :compounds, :data_entries, :metadata
+ attr_accessor :token_id
# Create dataset with optional URI. Does not load data into the dataset - you will need to execute one of the load_* methods to pull data from a service or to insert it from other representations.
# @example Create an empty dataset
@@ -14,8 +15,9 @@ module OpenTox
# dataset = OpenTox::Dataset.new("http:://webservices.in-silico/ch/dataset/1")
# @param [optional, String] uri Dataset URI
# @return [OpenTox::Dataset] Dataset object
- def initialize(uri=nil)
+ def initialize(uri=nil,token_id=nil)
super uri
+ @token_id = token_id
@features = {}
@compounds = []
@data_entries = {}
@@ -26,8 +28,9 @@ module OpenTox
# dataset = OpenTox::Dataset.create
# @param [optional, String] uri Dataset URI
# @return [OpenTox::Dataset] Dataset object
- def self.create(uri=CONFIG[:services]["opentox-dataset"])
+ def self.create(uri=CONFIG[:services]["opentox-dataset"], token_id=nil)
dataset = Dataset.new
+ dataset.token_id = token_id if token_id
dataset.save
dataset
end
@@ -252,7 +255,7 @@ module OpenTox
@compounds.uniq!
if @uri
if (CONFIG[:yaml_hosts].include?(URI.parse(@uri).host))
- RestClientWrapper.post(@uri,{:content_type => "application/x-yaml"},self.to_yaml)
+ RestClientWrapper.post(@uri,{:content_type => "application/x-yaml", :token_id => @token_id},self.to_yaml)
else
File.open("ot-post-file.rdf","w+") { |f| f.write(self.to_rdfxml); @path = f.path }
task_uri = RestClient.post(@uri, {:file => File.new(@path)},{:accept => "text/uri-list"}).to_s.chomp
@@ -262,7 +265,7 @@ module OpenTox
end
else
# create dataset if uri is empty
- self.uri = RestClientWrapper.post(CONFIG[:services]["opentox-dataset"],{}).to_s.chomp
+ self.uri = RestClientWrapper.post(CONFIG[:services]["opentox-dataset"],{:token_id => @token_id}).to_s.chomp
end
@uri
end
@@ -279,6 +282,7 @@ module OpenTox
@data_entries = dataset.data_entries
@compounds = dataset.compounds
@features = dataset.features
+ @token_id = dataset.token_id
if @uri
self.uri = @uri
else
diff --git a/lib/helper.rb b/lib/helper.rb
index b69f9b4..11f790b 100644
--- a/lib/helper.rb
+++ b/lib/helper.rb
@@ -17,7 +17,7 @@ helpers do
ret = OpenTox::Authorization.authorize(request.env['SCRIPT_URI'], request.env['REQUEST_METHOD'], token_id)
LOGGER.debug "OpenTox helpers OpenTox::Authorization authorized? method: #{request.env['REQUEST_METHOD']} , URI: #{request.env['SCRIPT_URI']}, token_id: #{token_id} with return #{ret}."
return ret
- when "POST"
+ when "POST", "HEAD"
if OpenTox::Authorization.is_token_valid(token_id)
LOGGER.debug "OpenTox helpers OpenTox::Authorization.is_token_valid: true"
return true
@@ -25,7 +25,6 @@ helpers do
LOGGER.warn "OpenTox helpers POST on #{request.env['SCRIPT_URI']} with token_id: #{token_id} false."
end
LOGGER.debug "Not authorized for: 1. #{request['SCRIPT_URI']} 2. #{request.env['SCRIPT_URI']} with Method: #{request.env['REQUEST_METHOD']} with Token #{token_id}"
- LOGGER.debug "Request infos: #{request.inspect}"
return false
end
@@ -55,6 +54,7 @@ before do
token_id = params[:token_id] if params[:token_id] and !check_token_id(token_id)
token_id = request.env['HTTP_TOKEN_ID'] if request.env['HTTP_TOKEN_ID'] and !check_token_id(token_id)
# see http://rack.rubyforge.org/doc/SPEC.html
+ token_id = CGI.unescape(token_id) if token_id.include?("%23")
rescue
LOGGER.debug "OpenTox api wrapper: helper before filter: NO token_id."
token_id = ""
diff --git a/lib/model.rb b/lib/model.rb
index 5654bcc..5dc4d4a 100644
--- a/lib/model.rb
+++ b/lib/model.rb
@@ -32,7 +32,7 @@ module OpenTox
include Model
include Algorithm
- attr_accessor :compound, :prediction_dataset, :features, :effects, :activities, :p_values, :fingerprints, :feature_calculation_algorithm, :similarity_algorithm, :prediction_algorithm, :min_sim
+ attr_accessor :compound, :prediction_dataset, :features, :effects, :activities, :p_values, :fingerprints, :feature_calculation_algorithm, :similarity_algorithm, :prediction_algorithm, :min_sim, :token_id
def initialize(uri=nil)
@@ -258,7 +258,7 @@ module OpenTox
# Save model at model service
def save
- self.uri = RestClientWrapper.post(@uri,{:content_type => "application/x-yaml"},self.to_yaml)
+ self.uri = RestClientWrapper.post(@uri,{:content_type => "application/x-yaml", :token_id => @token_id},self.to_yaml)
end
# Delete model at model service
diff --git a/lib/templates/default_guest_policy.xml b/lib/templates/default_guest_policy.xml
new file mode 100644
index 0000000..a778070
--- /dev/null
+++ b/lib/templates/default_guest_policy.xml
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+
+ allow
+
+
+
+ allow
+
+
+
+ allow
+
+
+
+ allow
+
+
+
+
+
+
+ uid=guest,ou=people,dc=opentox,dc=org
+
+
+
+
+
+
+
+
+
+
+ allow
+
+
+
+
+
+
+ cn=member,ou=groups,dc=opentox,dc=org
+
+
+
+
+
diff --git a/lib/templates/default_policy.xml b/lib/templates/default_policy.xml
new file mode 100644
index 0000000..a778070
--- /dev/null
+++ b/lib/templates/default_policy.xml
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+
+ allow
+
+
+
+ allow
+
+
+
+ allow
+
+
+
+ allow
+
+
+
+
+
+
+ uid=guest,ou=people,dc=opentox,dc=org
+
+
+
+
+
+
+
+
+
+
+ allow
+
+
+
+
+
+
+ cn=member,ou=groups,dc=opentox,dc=org
+
+
+
+
+
--
cgit v1.2.3
From 3dd413a79d8ef32c8bf0426228e34d87bdcd5a6b Mon Sep 17 00:00:00 2001
From: mr
Date: Thu, 9 Dec 2010 10:47:28 +0100
Subject: Ontology Service with Endpoint-option-list from
http://apps.ideaconsult.net:8080/ontology
---
lib/ontology_service.rb | 43 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 43 insertions(+)
create mode 100644 lib/ontology_service.rb
(limited to 'lib')
diff --git a/lib/ontology_service.rb b/lib/ontology_service.rb
new file mode 100644
index 0000000..4ff688f
--- /dev/null
+++ b/lib/ontology_service.rb
@@ -0,0 +1,43 @@
+module OpenTox
+ module OntologyService
+ module Endpoints
+ require 'sparql/client'
+ @sparql = SPARQL::Client.new("http://apps.ideaconsult.net:8080/ontology")
+ def self.qs(classname="Endpoints")
+ return "PREFIX ot:
+ PREFIX ota:
+ PREFIX owl:
+ PREFIX dc:
+ PREFIX rdfs:
+ PREFIX rdf:
+ PREFIX otee:
+ PREFIX toxcast:
+ select ?Endpoints ?title ?id
+ where {?Endpoints rdfs:subClassOf otee:#{classname}.
+ OPTIONAL {?Endpoints dc:title ?title}.
+ OPTIONAL {?Endpoints dc:identifier ?id}.}
+ ORDER BY ?title"
+ end
+
+ def self.make_option_list(endpoint="Endpoints", level=1)
+ out = ""
+ results = @sparql.query(qs(endpoint)) rescue results = []
+ results.each do |result|
+ endpointname = result.Endpoints.to_s.split('#').last
+ title = result.bound?(:title) ? result.title : endpointname
+ out += "\n"
+ out += make_option_list(endpointname, level + 1)
+ end
+ return out
+ end
+
+ def self.get_endpoint_selectlist(include_blank=true)
+ out = "\n"
+ return out
+ end
+ end
+ end
+end
\ No newline at end of file
--
cgit v1.2.3
From de12a8002ebc0bf4018588deafd5057b6478f414 Mon Sep 17 00:00:00 2001
From: mr
Date: Fri, 10 Dec 2010 17:19:35 +0100
Subject: A&A configuration options / request script_uri replaced
---
lib/helper.rb | 40 ++++++++++++++++++++--------------------
lib/templates/config.yaml | 13 +++++++++++++
2 files changed, 33 insertions(+), 20 deletions(-)
(limited to 'lib')
diff --git a/lib/helper.rb b/lib/helper.rb
index 11f790b..6247460 100644
--- a/lib/helper.rb
+++ b/lib/helper.rb
@@ -1,30 +1,32 @@
helpers do
- # Authentification
+ # Authentification
def protected!(token_id)
- if env["session"]
+ if env["session"]
flash[:notice] = "You don't have access to this section: " and \
redirect back and \
return unless authorized?(token_id)
+ elsif !env["session"] && token_id
+ throw(:halt, [401, "Not authorized.\n"]) and \
+ redirect back and \
+ return unless authorized?(token_id)
end
- throw(:halt, [401, "Not authorized\n"]) and \
+ throw(:halt, [401, "Not authorized.\n"]) and \
return unless authorized?(token_id)
end
-
+
def authorized?(token_id)
- case request.env['REQUEST_METHOD']
- when "DELETE", "PUT"
- ret = OpenTox::Authorization.authorize(request.env['SCRIPT_URI'], request.env['REQUEST_METHOD'], token_id)
- LOGGER.debug "OpenTox helpers OpenTox::Authorization authorized? method: #{request.env['REQUEST_METHOD']} , URI: #{request.env['SCRIPT_URI']}, token_id: #{token_id} with return #{ret}."
+ if CONFIG[:authorization][:authorize_request].include?(request.env['REQUEST_METHOD'])
+ ret = OpenTox::Authorization.authorize("#{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}#{request.env['REQUEST_URI']}", request.env['REQUEST_METHOD'], token_id)
+ LOGGER.debug "OpenTox helpers OpenTox::Authorization authorized? method: #{request.env['REQUEST_METHOD']} , URI: #{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}#{request.env['REQUEST_URI']}, token_id: #{token_id} with return #{ret}."
return ret
- when "POST", "HEAD"
+ end
+ if CONFIG[:authorization][:authenticate_request].include?(env['REQUEST_METHOD'])
if OpenTox::Authorization.is_token_valid(token_id)
- LOGGER.debug "OpenTox helpers OpenTox::Authorization.is_token_valid: true"
return true
end
- LOGGER.warn "OpenTox helpers POST on #{request.env['SCRIPT_URI']} with token_id: #{token_id} false."
- end
- LOGGER.debug "Not authorized for: 1. #{request['SCRIPT_URI']} 2. #{request.env['SCRIPT_URI']} with Method: #{request.env['REQUEST_METHOD']} with Token #{token_id}"
+ end
+ LOGGER.debug "Not authorized for: #{request.env['rack.url_scheme']}://#{request['REQUEST_URI']} with Method: #{request.env['REQUEST_METHOD']} with Token #{token_id}"
return false
end
@@ -32,7 +34,7 @@ helpers do
case env['REQUEST_URI']
when /\/login$|\/logout$|\/predict$|\/upload$/
return true
- when /\/compound|\/feature|\/task|\/toxcreate/ #to fix: read from config | validation should be protected
+ when /\/compound|\/feature|\/task|\/toxcreate/ #to fix: read from config | validation should be protected
return true
else
return false
@@ -43,24 +45,22 @@ helpers do
return false if !token_id
return true if token_id.size > 62
false
- end
+ end
end
before do
-
- unless unprotected_requests or env['REQUEST_METHOD'] == "GET"
+ unless unprotected_requests or CONFIG[:authorization][:free_request].include?(env['REQUEST_METHOD'])
begin
token_id = session[:token_id] if session[:token_id]
token_id = params[:token_id] if params[:token_id] and !check_token_id(token_id)
token_id = request.env['HTTP_TOKEN_ID'] if request.env['HTTP_TOKEN_ID'] and !check_token_id(token_id)
# see http://rack.rubyforge.org/doc/SPEC.html
- token_id = CGI.unescape(token_id) if token_id.include?("%23")
+ token_id = CGI.unescape(token_id) if token_id.include?("%23")
rescue
- LOGGER.debug "OpenTox api wrapper: helper before filter: NO token_id."
+ LOGGER.debug "OpenTox ruby api wrapper: helper before filter: NO token_id."
token_id = ""
end
protected!(token_id) if AA_SERVER
end
-
end
diff --git a/lib/templates/config.yaml b/lib/templates/config.yaml
index 00c00cb..db11006 100644
--- a/lib/templates/config.yaml
+++ b/lib/templates/config.yaml
@@ -39,3 +39,16 @@
# Uncomment for verbose logging
# :logger: debug
+
+# OpenSSO Authorization
+# set ":server: nil" to disable A&A
+:authorization:
+ :server: "https://opensso.in-silico.ch"
+ :free_request: #not controlled by A&A
+ - "GET"
+ :authenticate_request: #only for authenticated user
+ - "POST"
+ :authorize_request: #only for authenticated and authorizeduser
+ - "DELETE"
+ - "PUT"
+
\ No newline at end of file
--
cgit v1.2.3
From 4c2470353a1e3b69b4260d0052c9c48137ef76d3 Mon Sep 17 00:00:00 2001
From: mr
Date: Tue, 14 Dec 2010 12:30:20 +0100
Subject: remove token_id from tables in database
---
lib/dataset.rb | 16 ++++++----------
lib/helper.rb | 2 +-
lib/model.rb | 10 +++++-----
lib/task.rb | 1 +
lib/templates/config.yaml | 2 +-
5 files changed, 14 insertions(+), 17 deletions(-)
(limited to 'lib')
diff --git a/lib/dataset.rb b/lib/dataset.rb
index bbd8b8b..b7feeec 100644
--- a/lib/dataset.rb
+++ b/lib/dataset.rb
@@ -6,7 +6,6 @@ module OpenTox
include OpenTox
attr_reader :features, :compounds, :data_entries, :metadata
- attr_accessor :token_id
# Create dataset with optional URI. Does not load data into the dataset - you will need to execute one of the load_* methods to pull data from a service or to insert it from other representations.
# @example Create an empty dataset
@@ -15,9 +14,8 @@ module OpenTox
# dataset = OpenTox::Dataset.new("http:://webservices.in-silico/ch/dataset/1")
# @param [optional, String] uri Dataset URI
# @return [OpenTox::Dataset] Dataset object
- def initialize(uri=nil,token_id=nil)
+ def initialize(uri=nil)
super uri
- @token_id = token_id
@features = {}
@compounds = []
@data_entries = {}
@@ -30,8 +28,7 @@ module OpenTox
# @return [OpenTox::Dataset] Dataset object
def self.create(uri=CONFIG[:services]["opentox-dataset"], token_id=nil)
dataset = Dataset.new
- dataset.token_id = token_id if token_id
- dataset.save
+ dataset.save(token_id)
dataset
end
@@ -250,22 +247,22 @@ module OpenTox
# - creates a new dataset if uri is not set
# - overwrites dataset if uri exists
# @return [String] Dataset URI
- def save
+ def save(token_id=nil)
# TODO: rewrite feature URI's ??
@compounds.uniq!
if @uri
if (CONFIG[:yaml_hosts].include?(URI.parse(@uri).host))
- RestClientWrapper.post(@uri,{:content_type => "application/x-yaml", :token_id => @token_id},self.to_yaml)
+ RestClientWrapper.post(@uri,{:content_type => "application/x-yaml", :token_id => token_id},self.to_yaml)
else
File.open("ot-post-file.rdf","w+") { |f| f.write(self.to_rdfxml); @path = f.path }
- task_uri = RestClient.post(@uri, {:file => File.new(@path)},{:accept => "text/uri-list"}).to_s.chomp
+ task_uri = RestClient.post(@uri, {:file => File.new(@path)},{:accept => "text/uri-list" , :token_id => token_id}).to_s.chomp
#task_uri = `curl -X POST -H "Accept:text/uri-list" -F "file=@#{@path};type=application/rdf+xml" http://apps.ideaconsult.net:8080/ambit2/dataset`
Task.find(task_uri).wait_for_completion
self.uri = RestClientWrapper.get(task_uri,:accept => 'text/uri-list')
end
else
# create dataset if uri is empty
- self.uri = RestClientWrapper.post(CONFIG[:services]["opentox-dataset"],{:token_id => @token_id}).to_s.chomp
+ self.uri = RestClientWrapper.post(CONFIG[:services]["opentox-dataset"],{:token_id => token_id}).to_s.chomp
end
@uri
end
@@ -282,7 +279,6 @@ module OpenTox
@data_entries = dataset.data_entries
@compounds = dataset.compounds
@features = dataset.features
- @token_id = dataset.token_id
if @uri
self.uri = @uri
else
diff --git a/lib/helper.rb b/lib/helper.rb
index 6247460..42c35e8 100644
--- a/lib/helper.rb
+++ b/lib/helper.rb
@@ -32,7 +32,7 @@ helpers do
def unprotected_requests
case env['REQUEST_URI']
- when /\/login$|\/logout$|\/predict$|\/upload$/
+ when /\/login$|\/logout$|\/predict$|\/toxcreate\/models$/
return true
when /\/compound|\/feature|\/task|\/toxcreate/ #to fix: read from config | validation should be protected
return true
diff --git a/lib/model.rb b/lib/model.rb
index 5dc4d4a..9c2fb97 100644
--- a/lib/model.rb
+++ b/lib/model.rb
@@ -111,7 +111,7 @@ module OpenTox
# @param [String] compound_uri Compound URI
# @param [optinal,Boolean] verbose Verbose prediction (output includes neighbors and features)
# @return [OpenTox::Dataset] Dataset with prediction
- def predict(compound_uri,verbose=false)
+ def predict(compound_uri,verbose=false,token_id=nil)
@compound = Compound.new compound_uri
features = {}
@@ -119,7 +119,7 @@ module OpenTox
unless @prediction_dataset
#@prediction_dataset = cached_prediction
#return @prediction_dataset if cached_prediction
- @prediction_dataset = Dataset.create
+ @prediction_dataset = Dataset.create(CONFIG[:services]["opentox-dataset"], token_id)
@prediction_dataset.add_metadata( {
OT.hasSource => @uri,
DC.creator => @uri,
@@ -217,7 +217,7 @@ module OpenTox
end
end
- @prediction_dataset.save
+ @prediction_dataset.save(token_id)
@prediction_dataset
end
@@ -257,8 +257,8 @@ module OpenTox
end
# Save model at model service
- def save
- self.uri = RestClientWrapper.post(@uri,{:content_type => "application/x-yaml", :token_id => @token_id},self.to_yaml)
+ def save(token_id)
+ self.uri = RestClientWrapper.post(@uri,{:content_type => "application/x-yaml", :token_id => token_id},self.to_yaml)
end
# Delete model at model service
diff --git a/lib/task.rb b/lib/task.rb
index 17f95e6..18fba6e 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -49,6 +49,7 @@ module OpenTox
cpu_load = `cat /proc/loadavg`.split(/\s+/)[0..2].collect{|c| c.to_f}
nr_cpu_cores = `cat /proc/cpuinfo |grep "cpu cores"|cut -d ":" -f2|tr -d " "`.split("\n").collect{|c| c.to_i}.inject{|sum,n| sum+n}
+ nr_cpu_cores = 1 if !nr_cpu_cores
if cpu_load[0] > nr_cpu_cores and cpu_load[0] > cpu_load[1] and cpu_load[1] > cpu_load[2] # average CPU load of the last minute is high and CPU load is increasing
LOGGER.warn "Cannot start task - CPU load too high (#{cpu_load.join(", ")})"
task.cancel
diff --git a/lib/templates/config.yaml b/lib/templates/config.yaml
index db11006..116f462 100644
--- a/lib/templates/config.yaml
+++ b/lib/templates/config.yaml
@@ -41,7 +41,7 @@
# :logger: debug
# OpenSSO Authorization
-# set ":server: nil" to disable A&A
+# set ":server: " to disable A&A
:authorization:
:server: "https://opensso.in-silico.ch"
:free_request: #not controlled by A&A
--
cgit v1.2.3
From 2fb2f4cd34f499f8c9def5e4091cb5998794c595 Mon Sep 17 00:00:00 2001
From: mr
Date: Tue, 14 Dec 2010 16:39:01 +0100
Subject: rename token_id to subjectid
---
lib/authorization.rb | 132 +++++++++++++++++++++++++--------------------------
lib/dataset.rb | 12 ++---
lib/helper.rb | 40 ++++++++--------
lib/model.rb | 12 ++---
4 files changed, 98 insertions(+), 98 deletions(-)
(limited to 'lib')
diff --git a/lib/authorization.rb b/lib/authorization.rb
index 0cba96a..f9499e6 100644
--- a/lib/authorization.rb
+++ b/lib/authorization.rb
@@ -16,13 +16,13 @@ module OpenTox
# OpenTox::Authorization.create_policy(xml,tok)
class AA
- attr_accessor :user, :token_id, :policy
+ attr_accessor :user, :subjectid, :policy
- #Generates AA object - requires token_id
- # @param [String] token_id
- def initialize(token_id)
- @user = Authorization.get_user(token_id)
- @token_id = token_id
+ #Generates AA object - requires subjectid
+ # @param [String] subjectid
+ def initialize(subjectid)
+ @user = Authorization.get_user(subjectid)
+ @subjectid = subjectid
@policy = Policies.new()
end
@@ -40,8 +40,8 @@ module OpenTox
def send(uri)
xml = get_xml(uri)
ret = false
- ret = Authorization.create_policy(xml, @token_id)
- LOGGER.debug "Policy send with token_id: #{@token_id}"
+ ret = Authorization.create_policy(xml, @subjectid)
+ LOGGER.debug "Policy send with subjectid: #{@subjectid}"
LOGGER.warn "Not created Policy is: #{xml}" if !ret
ret
end
@@ -56,7 +56,7 @@ module OpenTox
#Authentication against OpenSSO. Returns token. Requires Username and Password.
# @param [String, String]Username,Password
- # @return [String, nil] gives token_id or nil
+ # @return [String, nil] gives subjectid or nil
def self.authenticate(user, pw)
return true if !AA_SERVER
begin
@@ -69,12 +69,12 @@ module OpenTox
end
#Logout on opensso. Make token invalid. Requires token
- # @param [String]token_id the token_id
+ # @param [String]subjectid the subjectid
# @return [Boolean] true if logout is OK
- def self.logout(token_id)
+ def self.logout(subjectid)
begin
resource = RestClient::Resource.new("#{AA_SERVER}/auth/logout")
- resource.post(:subjectid => token_id)
+ resource.post(:subjectid => subjectid)
return true
rescue
return false
@@ -82,38 +82,38 @@ module OpenTox
end
#Authorization against OpenSSO for a URI with request-method (action) [GET/POST/PUT/DELETE]
- # @param [String,String,String]uri,action,token_id
+ # @param [String,String,String]uri,action,subjectid
# @return [Boolean, nil] returns true, false or nil (if authorization-request fails).
- def self.authorize(uri, action, token_id)
+ def self.authorize(uri, action, subjectid)
return true if !AA_SERVER
begin
resource = RestClient::Resource.new("#{AA_SERVER}/auth/authorize")
- return true if resource.post(:uri => uri, :action => action, :subjectid => token_id) == "boolean=true\n"
+ return true if resource.post(:uri => uri, :action => action, :subjectid => subjectid) == "boolean=true\n"
rescue
return nil
end
end
#Checks if a token is a valid token
- # @param [String]token_id token_id from openSSO session
- # @return [Boolean] token_id is valid or not.
- def self.is_token_valid(token_id)
+ # @param [String]subjectid subjectid from openSSO session
+ # @return [Boolean] subjectid is valid or not.
+ def self.is_token_valid(subjectid)
return true if !AA_SERVER
begin
resource = RestClient::Resource.new("#{AA_SERVER}/auth/isTokenValid")
- return true if resource.post(:tokenid => token_id) == "boolean=true\n"
+ return true if resource.post(:tokenid => subjectid) == "boolean=true\n"
rescue
return false
end
end
#Returns array with all policies of the token owner
- # @param [String]token_id requires token_id
+ # @param [String]subjectid requires subjectid
# @return [Array, nil] returns an Array of policy names or nil if request fails
- def self.list_policies(token_id)
+ def self.list_policies(subjectid)
begin
resource = RestClient::Resource.new("#{AA_SERVER}/pol")
- out = resource.get(:subjectid => token_id)
+ out = resource.get(:subjectid => subjectid)
return out.split("\n")
rescue
return nil
@@ -121,45 +121,45 @@ module OpenTox
end
#Returns a policy in xml-format
- # @param [String, String]policy,token_id
+ # @param [String, String]policy,subjectid
# @return [String] XML of the policy
- def self.list_policy(policy, token_id)
+ def self.list_policy(policy, subjectid)
begin
resource = RestClient::Resource.new("#{AA_SERVER}/pol")
- return resource.get(:subjectid => token_id,:id => policy)
+ return resource.get(:subjectid => subjectid,:id => policy)
rescue
return nil
end
end
#Returns the owner (who created the first policy) of an URI
- # @param [String, String]uri,token_id
+ # @param [String, String]uri,subjectid
# return [String, nil]owner,nil returns owner of the URI
- def self.get_uri_owner(uri, token_id)
+ def self.get_uri_owner(uri, subjectid)
begin
resource = RestClient::Resource.new("#{AA_SERVER}/pol")
- return resource.get(:uri => uri, :subjectid => token_id).sub("\n","")
+ return resource.get(:uri => uri, :subjectid => subjectid).sub("\n","")
rescue
return nil
end
end
#Checks if a policy exists to a URI. Requires URI and token.
- # @param [String, String]uri,token_id
+ # @param [String, String]uri,subjectid
# return [Boolean]
- def self.uri_has_policy(uri, token_id)
- owner = get_uri_owner(uri, token_id)
+ def self.uri_has_policy(uri, subjectid)
+ owner = get_uri_owner(uri, subjectid)
return true if owner and owner != "null"
false
end
#List all policynames for a URI. Requires URI and token.
- # @param [String, String]uri,token_id
+ # @param [String, String]uri,subjectid
# return [Array, nil] returns an Array of policy names or nil if request fails
- def self.list_uri_policies(uri, token_id)
+ def self.list_uri_policies(uri, subjectid)
begin
resource = RestClient::Resource.new("#{AA_SERVER}/pol")
- out = resource.get(:uri => uri, :polnames => true, :subjectid => token_id)
+ out = resource.get(:uri => uri, :polnames => true, :subjectid => subjectid)
policies = []; notfirstline = false
out.split("\n").each do |line|
policies << line if notfirstline
@@ -172,39 +172,39 @@ module OpenTox
end
#Sends a policy in xml-format to opensso server. Requires policy-xml and token.
- # @param [String, String]policyxml,token_id
+ # @param [String, String]policyxml,subjectid
# return [Boolean] returns true if policy is created
- def self.create_policy(policy, token_id)
+ def self.create_policy(policy, subjectid)
begin
# resource = RestClient::Resource.new("#{AA_SERVER}/Pol/opensso-pol")
- LOGGER.debug "OpenTox::Authorization.create_policy policy: #{policy[168,43]} with token:" + token_id.to_s + " length: " + token_id.length.to_s
-# return true if resource.post(policy, :subjectid => token_id, :content_type => "application/xml")
- return true if RestClientWrapper.post("#{AA_SERVER}/pol", {:subjectid => token_id, :content_type => "application/xml"}, policy)
+ LOGGER.debug "OpenTox::Authorization.create_policy policy: #{policy[168,43]} with token:" + subjectid.to_s + " length: " + subjectid.length.to_s
+# return true if resource.post(policy, :subjectid => subjectid, :content_type => "application/xml")
+ return true if RestClientWrapper.post("#{AA_SERVER}/pol", {:subjectid => subjectid, :content_type => "application/xml"}, policy)
rescue
return false
end
end
#Deletes a policy
- # @param [String, String]policyname,token_id
+ # @param [String, String]policyname,subjectid
# @return [Boolean,nil]
- def self.delete_policy(policy, token_id)
+ def self.delete_policy(policy, subjectid)
begin
resource = RestClient::Resource.new("#{AA_SERVER}/pol")
- LOGGER.debug "OpenTox::Authorization.delete_policy policy: #{policy} with token: #{token_id}"
- return true if resource.delete(:subjectid => token_id, :id => policy)
+ LOGGER.debug "OpenTox::Authorization.delete_policy policy: #{policy} with token: #{subjectid}"
+ return true if resource.delete(:subjectid => subjectid, :id => policy)
rescue
return nil
end
end
#Returns array of all possible LDAP-Groups
- # @param [String]token_id
+ # @param [String]subjectid
# @return [Array]
- def self.list_groups(token_id)
+ def self.list_groups(subjectid)
begin
resource = RestClient::Resource.new("#{AA_SERVER}/opensso/identity/search")
- grps = resource.post(:admin => token_id, :attributes_names => "objecttype", :attributes_values_objecttype => "group")
+ grps = resource.post(:admin => subjectid, :attributes_names => "objecttype", :attributes_values_objecttype => "group")
grps.split("\n").collect{|x| x.sub("string=","")}
rescue
[]
@@ -212,12 +212,12 @@ module OpenTox
end
#Returns array of the LDAP-Groups of an user
- # @param [String]token_id
+ # @param [String]subjectid
# @return [Array] gives array of LDAP groups of a user
- def self.list_user_groups(user, token_id)
+ def self.list_user_groups(user, subjectid)
begin
resource = RestClient::Resource.new("#{AA_SERVER}/opensso/identity/read")
- out = resource.post(:name => user, :admin => token_id, :attributes_names => "group")
+ out = resource.post(:name => user, :admin => subjectid, :attributes_names => "group")
grps = []
out.split("\n").each do |line|
grps << line.sub("identitydetails.group=","") if line.include?("identitydetails.group=")
@@ -229,12 +229,12 @@ module OpenTox
end
#Returns the owner (user id) of a token
- # @param [String]token_id
+ # @param [String]subjectid
# @return [String]user
- def self.get_user(token_id)
+ def self.get_user(subjectid)
begin
resource = RestClient::Resource.new("#{AA_SERVER}/opensso/identity/attributes")
- out = resource.post(:subjectid => token_id, :attributes_names => "uid")
+ out = resource.post(:subjectid => subjectid, :attributes_names => "uid")
user = ""; check = false
out.split("\n").each do |line|
if check
@@ -250,34 +250,34 @@ module OpenTox
end
#Send default policy with Authorization::AA class
- # @param [String, String]URI,token_id
- def self.send_policy(uri, token_id)
+ # @param [String, String]URI,subjectid
+ def self.send_policy(uri, subjectid)
return true if !AA_SERVER
- aa = Authorization::AA.new(token_id)
+ aa = Authorization::AA.new(subjectid)
ret = aa.send(uri)
- LOGGER.debug "OpenTox::Authorization send policy for URI: #{uri} | token_id: #{token_id} - policy created: #{ret}"
+ LOGGER.debug "OpenTox::Authorization send policy for URI: #{uri} | subjectid: #{subjectid} - policy created: #{ret}"
ret
end
#Deletes all policies of an URI
- # @param [String, String]URI,token_id
+ # @param [String, String]URI,subjectid
# @return [Boolean]
- def self.delete_policies_from_uri(uri, token_id)
- policies = list_uri_policies(uri, token_id)
+ def self.delete_policies_from_uri(uri, subjectid)
+ policies = list_uri_policies(uri, subjectid)
policies.each do |policy|
- ret = delete_policy(policy, token_id)
+ ret = delete_policy(policy, subjectid)
LOGGER.debug "OpenTox::Authorization delete policy: #{policy} - with result: #{ret}"
end
return true
end
- #Checks (if token_id is valid) if a policy exist and create default policy if not
- def self.check_policy(uri, token_id)
- token_valid = OpenTox::Authorization.is_token_valid(token_id)
- LOGGER.debug "OpenTox::Authorization.check_policy with uri: #{uri}, token_id: #{token_id} is valid: #{token_valid}"
+ #Checks (if subjectid is valid) if a policy exist and create default policy if not
+ def self.check_policy(uri, subjectid)
+ token_valid = OpenTox::Authorization.is_token_valid(subjectid)
+ LOGGER.debug "OpenTox::Authorization.check_policy with uri: #{uri}, subjectid: #{subjectid} is valid: #{token_valid}"
if uri and token_valid
- if !uri_has_policy(uri, token_id)
- return send_policy(uri, token_id)
+ if !uri_has_policy(uri, subjectid)
+ return send_policy(uri, subjectid)
else
LOGGER.debug "OpenTox::Authorization.check_policy URI: #{uri} has already a Policy."
end
diff --git a/lib/dataset.rb b/lib/dataset.rb
index b7feeec..7c70c9d 100644
--- a/lib/dataset.rb
+++ b/lib/dataset.rb
@@ -26,9 +26,9 @@ module OpenTox
# dataset = OpenTox::Dataset.create
# @param [optional, String] uri Dataset URI
# @return [OpenTox::Dataset] Dataset object
- def self.create(uri=CONFIG[:services]["opentox-dataset"], token_id=nil)
+ def self.create(uri=CONFIG[:services]["opentox-dataset"], subjectid=nil)
dataset = Dataset.new
- dataset.save(token_id)
+ dataset.save(subjectid)
dataset
end
@@ -247,22 +247,22 @@ module OpenTox
# - creates a new dataset if uri is not set
# - overwrites dataset if uri exists
# @return [String] Dataset URI
- def save(token_id=nil)
+ def save(subjectid=nil)
# TODO: rewrite feature URI's ??
@compounds.uniq!
if @uri
if (CONFIG[:yaml_hosts].include?(URI.parse(@uri).host))
- RestClientWrapper.post(@uri,{:content_type => "application/x-yaml", :token_id => token_id},self.to_yaml)
+ RestClientWrapper.post(@uri,{:content_type => "application/x-yaml", :subjectid => subjectid},self.to_yaml)
else
File.open("ot-post-file.rdf","w+") { |f| f.write(self.to_rdfxml); @path = f.path }
- task_uri = RestClient.post(@uri, {:file => File.new(@path)},{:accept => "text/uri-list" , :token_id => token_id}).to_s.chomp
+ task_uri = RestClient.post(@uri, {:file => File.new(@path)},{:accept => "text/uri-list" , :subjectid => subjectid}).to_s.chomp
#task_uri = `curl -X POST -H "Accept:text/uri-list" -F "file=@#{@path};type=application/rdf+xml" http://apps.ideaconsult.net:8080/ambit2/dataset`
Task.find(task_uri).wait_for_completion
self.uri = RestClientWrapper.get(task_uri,:accept => 'text/uri-list')
end
else
# create dataset if uri is empty
- self.uri = RestClientWrapper.post(CONFIG[:services]["opentox-dataset"],{:token_id => token_id}).to_s.chomp
+ self.uri = RestClientWrapper.post(CONFIG[:services]["opentox-dataset"],{:subjectid => subjectid}).to_s.chomp
end
@uri
end
diff --git a/lib/helper.rb b/lib/helper.rb
index 42c35e8..6b616bc 100644
--- a/lib/helper.rb
+++ b/lib/helper.rb
@@ -1,32 +1,32 @@
helpers do
# Authentification
- def protected!(token_id)
+ def protected!(subjectid)
if env["session"]
flash[:notice] = "You don't have access to this section: " and \
redirect back and \
- return unless authorized?(token_id)
- elsif !env["session"] && token_id
+ return unless authorized?(subjectid)
+ elsif !env["session"] && subjectid
throw(:halt, [401, "Not authorized.\n"]) and \
redirect back and \
- return unless authorized?(token_id)
+ return unless authorized?(subjectid)
end
throw(:halt, [401, "Not authorized.\n"]) and \
- return unless authorized?(token_id)
+ return unless authorized?(subjectid)
end
- def authorized?(token_id)
+ def authorized?(subjectid)
if CONFIG[:authorization][:authorize_request].include?(request.env['REQUEST_METHOD'])
- ret = OpenTox::Authorization.authorize("#{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}#{request.env['REQUEST_URI']}", request.env['REQUEST_METHOD'], token_id)
- LOGGER.debug "OpenTox helpers OpenTox::Authorization authorized? method: #{request.env['REQUEST_METHOD']} , URI: #{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}#{request.env['REQUEST_URI']}, token_id: #{token_id} with return #{ret}."
+ ret = OpenTox::Authorization.authorize("#{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}#{request.env['REQUEST_URI']}", request.env['REQUEST_METHOD'], subjectid)
+ LOGGER.debug "OpenTox helpers OpenTox::Authorization authorized? method: #{request.env['REQUEST_METHOD']} , URI: #{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}#{request.env['REQUEST_URI']}, subjectid: #{subjectid} with return #{ret}."
return ret
end
if CONFIG[:authorization][:authenticate_request].include?(env['REQUEST_METHOD'])
- if OpenTox::Authorization.is_token_valid(token_id)
+ if OpenTox::Authorization.is_token_valid(subjectid)
return true
end
end
- LOGGER.debug "Not authorized for: #{request.env['rack.url_scheme']}://#{request['REQUEST_URI']} with Method: #{request.env['REQUEST_METHOD']} with Token #{token_id}"
+ LOGGER.debug "Not authorized for: #{request.env['rack.url_scheme']}://#{request['REQUEST_URI']} with Method: #{request.env['REQUEST_METHOD']} with Token #{subjectid}"
return false
end
@@ -41,9 +41,9 @@ helpers do
end
end
- def check_token_id(token_id)
- return false if !token_id
- return true if token_id.size > 62
+ def check_subjectid(subjectid)
+ return false if !subjectid
+ return true if subjectid.size > 62
false
end
end
@@ -51,16 +51,16 @@ end
before do
unless unprotected_requests or CONFIG[:authorization][:free_request].include?(env['REQUEST_METHOD'])
begin
- token_id = session[:token_id] if session[:token_id]
- token_id = params[:token_id] if params[:token_id] and !check_token_id(token_id)
- token_id = request.env['HTTP_TOKEN_ID'] if request.env['HTTP_TOKEN_ID'] and !check_token_id(token_id)
+ subjectid = session[:subjectid] if session[:subjectid]
+ subjectid = params[:subjectid] if params[:subjectid] and !check_subjectid(subjectid)
+ subjectid = request.env['HTTP_SUBJECTID'] if request.env['HTTP_SUBJECTID'] and !check_subjectid(subjectid)
# see http://rack.rubyforge.org/doc/SPEC.html
- token_id = CGI.unescape(token_id) if token_id.include?("%23")
+ subjectid = CGI.unescape(subjectid) if subjectid.include?("%23")
rescue
- LOGGER.debug "OpenTox ruby api wrapper: helper before filter: NO token_id."
- token_id = ""
+ LOGGER.debug "OpenTox ruby api wrapper: helper before filter: NO subjectid."
+ subjectid = ""
end
- protected!(token_id) if AA_SERVER
+ protected!(subjectid) if AA_SERVER
end
end
diff --git a/lib/model.rb b/lib/model.rb
index 9c2fb97..953bb6c 100644
--- a/lib/model.rb
+++ b/lib/model.rb
@@ -32,7 +32,7 @@ module OpenTox
include Model
include Algorithm
- attr_accessor :compound, :prediction_dataset, :features, :effects, :activities, :p_values, :fingerprints, :feature_calculation_algorithm, :similarity_algorithm, :prediction_algorithm, :min_sim, :token_id
+ attr_accessor :compound, :prediction_dataset, :features, :effects, :activities, :p_values, :fingerprints, :feature_calculation_algorithm, :similarity_algorithm, :prediction_algorithm, :min_sim, :subjectid
def initialize(uri=nil)
@@ -111,7 +111,7 @@ module OpenTox
# @param [String] compound_uri Compound URI
# @param [optinal,Boolean] verbose Verbose prediction (output includes neighbors and features)
# @return [OpenTox::Dataset] Dataset with prediction
- def predict(compound_uri,verbose=false,token_id=nil)
+ def predict(compound_uri,verbose=false,subjectid=nil)
@compound = Compound.new compound_uri
features = {}
@@ -119,7 +119,7 @@ module OpenTox
unless @prediction_dataset
#@prediction_dataset = cached_prediction
#return @prediction_dataset if cached_prediction
- @prediction_dataset = Dataset.create(CONFIG[:services]["opentox-dataset"], token_id)
+ @prediction_dataset = Dataset.create(CONFIG[:services]["opentox-dataset"], subjectid)
@prediction_dataset.add_metadata( {
OT.hasSource => @uri,
DC.creator => @uri,
@@ -217,7 +217,7 @@ module OpenTox
end
end
- @prediction_dataset.save(token_id)
+ @prediction_dataset.save(subjectid)
@prediction_dataset
end
@@ -257,8 +257,8 @@ module OpenTox
end
# Save model at model service
- def save(token_id)
- self.uri = RestClientWrapper.post(@uri,{:content_type => "application/x-yaml", :token_id => token_id},self.to_yaml)
+ def save(subjectid)
+ self.uri = RestClientWrapper.post(@uri,{:content_type => "application/x-yaml", :subjectid => subjectid},self.to_yaml)
end
# Delete model at model service
--
cgit v1.2.3
From b22110ae0d8e902d700e0a3dc629ebfde1edfe10 Mon Sep 17 00:00:00 2001
From: mr
Date: Thu, 16 Dec 2010 10:59:46 +0100
Subject: A&A
---
lib/dataset.rb | 18 +++++++++---------
lib/helper.rb | 2 +-
lib/model.rb | 18 +++++++++---------
3 files changed, 19 insertions(+), 19 deletions(-)
(limited to 'lib')
diff --git a/lib/dataset.rb b/lib/dataset.rb
index 7c70c9d..aba7754 100644
--- a/lib/dataset.rb
+++ b/lib/dataset.rb
@@ -38,12 +38,12 @@ module OpenTox
# - you will have to set remaining metadata manually
# @param [String] file CSV file path
# @return [OpenTox::Dataset] Dataset object with CSV data
- def self.create_from_csv_file(file)
- dataset = Dataset.create
+ def self.create_from_csv_file(file, subjectid=nil)
+ dataset = Dataset.create(CONFIG[:services]["opentox-dataset"], subjectid)
parser = Parser::Spreadsheets.new
parser.dataset = dataset
parser.load_csv(File.open(file).read)
- dataset.save
+ dataset.save(subjectid)
dataset
end
@@ -89,8 +89,8 @@ module OpenTox
# - you will have to set remaining metadata manually
# @param [String] csv CSV representation of the dataset
# @return [OpenTox::Dataset] Dataset object with CSV data
- def load_csv(csv)
- save unless @uri # get a uri for creating features
+ def load_csv(csv, subjectid=nil)
+ save(subjectid) unless @uri # get a uri for creating features
parser = Parser::Spreadsheets.new
parser.dataset = self
parser.load_csv(csv)
@@ -102,8 +102,8 @@ module OpenTox
# - you will have to set remaining metadata manually
# @param [Excel] book Excel workbook object (created with roo gem)
# @return [OpenTox::Dataset] Dataset object with Excel data
- def load_spreadsheet(book)
- save unless @uri # get a uri for creating features
+ def load_spreadsheet(book, subjectid=nil)
+ save(subjectid) unless @uri # get a uri for creating features
parser = Parser::Spreadsheets.new
parser.dataset = self
parser.load_spreadsheet(book)
@@ -268,8 +268,8 @@ module OpenTox
end
# Delete dataset at the dataset service
- def delete
- RestClientWrapper.delete @uri
+ def delete(subjectid=nil)
+ RestClientWrapper.delete(@uri, :subjectid => subjectid)
end
private
diff --git a/lib/helper.rb b/lib/helper.rb
index 6b616bc..965b4ad 100644
--- a/lib/helper.rb
+++ b/lib/helper.rb
@@ -57,7 +57,7 @@ before do
# see http://rack.rubyforge.org/doc/SPEC.html
subjectid = CGI.unescape(subjectid) if subjectid.include?("%23")
rescue
- LOGGER.debug "OpenTox ruby api wrapper: helper before filter: NO subjectid."
+ LOGGER.debug "OpenTox ruby api wrapper: helper before filter: NO subjectid for URI: #{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}#{request.env['REQUEST_URI']}"
subjectid = ""
end
protected!(subjectid) if AA_SERVER
diff --git a/lib/model.rb b/lib/model.rb
index 953bb6c..c645bdc 100644
--- a/lib/model.rb
+++ b/lib/model.rb
@@ -90,8 +90,8 @@ module OpenTox
# Predict a dataset
# @param [String] dataset_uri Dataset URI
# @return [OpenTox::Dataset] Dataset with predictions
- def predict_dataset(dataset_uri)
- @prediction_dataset = Dataset.create
+ def predict_dataset(dataset_uri, subjectid=nil)
+ @prediction_dataset = Dataset.create(CONFIG[:services]["opentox-dataset"], subjectid)
@prediction_dataset.add_metadata({
OT.hasSource => @uri,
DC.creator => @uri,
@@ -101,9 +101,9 @@ module OpenTox
d = Dataset.new(dataset_uri)
d.load_compounds
d.compounds.each do |compound_uri|
- predict(compound_uri,false)
+ predict(compound_uri,false,subjectid)
end
- @prediction_dataset.save
+ @prediction_dataset.save(subjectid)
@prediction_dataset
end
@@ -129,7 +129,7 @@ module OpenTox
} )
end
- return @prediction_dataset if database_activity
+ return @prediction_dataset if database_activity(subjectid)
neighbors
prediction = eval("#{@prediction_algorithm}(@neighbors,{:similarity_algorithm => @similarity_algorithm, :p_values => @p_values})")
@@ -245,11 +245,11 @@ module OpenTox
# Find database activities and store them in @prediction_dataset
# @return [Boolean] true if compound has databasse activities, false if not
- def database_activity
+ def database_activity(subjectid)
if @activities[@compound.uri]
@activities[@compound.uri].each { |act| @prediction_dataset.add @compound.uri, @metadata[OT.dependentVariables], act }
@prediction_dataset.add_metadata(OT.hasSource => @metadata[OT.trainingDataset])
- @prediction_dataset.save
+ @prediction_dataset.save(subjectid)
true
else
false
@@ -262,8 +262,8 @@ module OpenTox
end
# Delete model at model service
- def delete
- RestClientWrapper.delete @uri unless @uri == CONFIG[:services]["opentox-model"]
+ def delete(subjectid)
+ RestClientWrapper.delete(@uri, :subjectid => subjectid) unless @uri == CONFIG[:services]["opentox-model"]
end
end
--
cgit v1.2.3
From a0bcb593e95320bff832f5cca9b9f4c105c817d3 Mon Sep 17 00:00:00 2001
From: mr
Date: Mon, 10 Jan 2011 17:04:20 +0100
Subject: A&A
---
lib/authorization.rb | 4 +++-
lib/dataset.rb | 48 ++++++++++++++++++++++++------------------------
2 files changed, 27 insertions(+), 25 deletions(-)
(limited to 'lib')
diff --git a/lib/authorization.rb b/lib/authorization.rb
index f9499e6..dab228a 100644
--- a/lib/authorization.rb
+++ b/lib/authorization.rb
@@ -114,7 +114,9 @@ module OpenTox
begin
resource = RestClient::Resource.new("#{AA_SERVER}/pol")
out = resource.get(:subjectid => subjectid)
- return out.split("\n")
+ return out.split("\n")
+ rescue RestClient::InternalServerError => e
+ raise e.response
rescue
return nil
end
diff --git a/lib/dataset.rb b/lib/dataset.rb
index 7c70c9d..52b41a7 100644
--- a/lib/dataset.rb
+++ b/lib/dataset.rb
@@ -14,7 +14,7 @@ module OpenTox
# dataset = OpenTox::Dataset.new("http:://webservices.in-silico/ch/dataset/1")
# @param [optional, String] uri Dataset URI
# @return [OpenTox::Dataset] Dataset object
- def initialize(uri=nil)
+ def initialize(uri=nil,subjectid=nil)
super uri
@features = {}
@compounds = []
@@ -27,7 +27,7 @@ module OpenTox
# @param [optional, String] uri Dataset URI
# @return [OpenTox::Dataset] Dataset object
def self.create(uri=CONFIG[:services]["opentox-dataset"], subjectid=nil)
- dataset = Dataset.new
+ dataset = Dataset.new(nil,subjectid)
dataset.save(subjectid)
dataset
end
@@ -38,29 +38,29 @@ module OpenTox
# - you will have to set remaining metadata manually
# @param [String] file CSV file path
# @return [OpenTox::Dataset] Dataset object with CSV data
- def self.create_from_csv_file(file)
- dataset = Dataset.create
+ def self.create_from_csv_file(file, subjectid=nil)
+ dataset = Dataset.create(CONFIG[:services]["opentox-dataset"], subjectid)
parser = Parser::Spreadsheets.new
parser.dataset = dataset
parser.load_csv(File.open(file).read)
- dataset.save
+ dataset.save(subjectid)
dataset
end
# Find a dataset and load all data. This can be time consuming, use Dataset.new together with one of the load_* methods for a fine grained control over data loading.
# @param [String] uri Dataset URI
# @return [OpenTox::Dataset] Dataset object with all data
- def self.find(uri)
- dataset = Dataset.new(uri)
- dataset.load_all
+ def self.find(uri, subjectid=nil)
+ dataset = Dataset.new(uri, subjectid)
+ dataset.load_all(subjectid)
dataset
end
# Get all datasets from a service
# @param [optional,String] uri URI of the dataset service, defaults to service specified in configuration
# @return [Array] Array of dataset object without data (use one of the load_* methods to pull data from the server)
- def self.all(uri=CONFIG[:services]["opentox-dataset"])
- RestClientWrapper.get(uri,:accept => "text/uri-list").to_s.each_line.collect{|u| Dataset.new(u)}
+ def self.all(uri=CONFIG[:services]["opentox-dataset"], subjectid=nil)
+ RestClientWrapper.get(uri,{:accept => "text/uri-list",:subjectid => subjectid}).to_s.each_line.collect{|u| Dataset.new(u)}
end
# Load YAML representation into the dataset
@@ -89,8 +89,8 @@ module OpenTox
# - you will have to set remaining metadata manually
# @param [String] csv CSV representation of the dataset
# @return [OpenTox::Dataset] Dataset object with CSV data
- def load_csv(csv)
- save unless @uri # get a uri for creating features
+ def load_csv(csv, subjectid=nil)
+ save(subjectid) unless @uri # get a uri for creating features
parser = Parser::Spreadsheets.new
parser.dataset = self
parser.load_csv(csv)
@@ -102,8 +102,8 @@ module OpenTox
# - you will have to set remaining metadata manually
# @param [Excel] book Excel workbook object (created with roo gem)
# @return [OpenTox::Dataset] Dataset object with Excel data
- def load_spreadsheet(book)
- save unless @uri # get a uri for creating features
+ def load_spreadsheet(book, subjectid=nil)
+ save(subjectid) unless @uri # get a uri for creating features
parser = Parser::Spreadsheets.new
parser.dataset = self
parser.load_spreadsheet(book)
@@ -118,9 +118,9 @@ module OpenTox
end
# Load all data (metadata, data_entries, compounds and features) from URI
- def load_all
+ def load_all(subjectid=nil)
if (CONFIG[:yaml_hosts].include?(URI.parse(@uri).host))
- copy YAML.load(RestClientWrapper.get(@uri, :accept => "application/x-yaml"))
+ copy YAML.load(RestClientWrapper.get(@uri, {:accept => "application/x-yaml", :subjectid => subjectid}))
else
parser = Parser::Owl::Dataset.new(@uri)
copy parser.load_uri
@@ -129,8 +129,8 @@ module OpenTox
# Load and return only compound URIs from the dataset service
# @return [Array] Compound URIs in the dataset
- def load_compounds
- RestClientWrapper.get(File.join(uri,"compounds"),:accept=> "text/uri-list").to_s.each_line do |compound_uri|
+ def load_compounds(subjectid=nil)
+ RestClientWrapper.get(File.join(uri,"compounds"),{:accept=> "text/uri-list", :subjectid => subjectid}).to_s.each_line do |compound_uri|
@compounds << compound_uri.chomp
end
@compounds.uniq!
@@ -258,7 +258,7 @@ module OpenTox
task_uri = RestClient.post(@uri, {:file => File.new(@path)},{:accept => "text/uri-list" , :subjectid => subjectid}).to_s.chomp
#task_uri = `curl -X POST -H "Accept:text/uri-list" -F "file=@#{@path};type=application/rdf+xml" http://apps.ideaconsult.net:8080/ambit2/dataset`
Task.find(task_uri).wait_for_completion
- self.uri = RestClientWrapper.get(task_uri,:accept => 'text/uri-list')
+ self.uri = RestClientWrapper.get(task_uri,{:accept => 'text/uri-list', :subjectid => subjectid})
end
else
# create dataset if uri is empty
@@ -268,8 +268,8 @@ module OpenTox
end
# Delete dataset at the dataset service
- def delete
- RestClientWrapper.delete @uri
+ def delete(subjectid=nil)
+ RestClientWrapper.delete(@uri, :subjectid => subjectid)
end
private
@@ -293,9 +293,9 @@ module OpenTox
# Find a prediction dataset and load all data.
# @param [String] uri Prediction dataset URI
# @return [OpenTox::Dataset] Prediction dataset object with all data
- def self.find(uri)
- prediction = LazarPrediction.new(uri)
- prediction.load_all
+ def self.find(uri, subjectid=nil)
+ prediction = LazarPrediction.new(uri, subjectid)
+ prediction.load_all(subjectid)
prediction
end
--
cgit v1.2.3
From 57cab7b2e22b4f07ee7f53afb15d05873abeca6d Mon Sep 17 00:00:00 2001
From: mr
Date: Mon, 10 Jan 2011 17:04:49 +0100
Subject: A&A
---
lib/helper.rb | 36 ++++++++++++++++++++++++------------
1 file changed, 24 insertions(+), 12 deletions(-)
(limited to 'lib')
diff --git a/lib/helper.rb b/lib/helper.rb
index 6b616bc..857c5b5 100644
--- a/lib/helper.rb
+++ b/lib/helper.rb
@@ -15,25 +15,42 @@ helpers do
return unless authorized?(subjectid)
end
+ #Check Authorization for URI with method and subjectid.
def authorized?(subjectid)
+ uri = clean_uri("#{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}#{request.env['REQUEST_URI']}")
if CONFIG[:authorization][:authorize_request].include?(request.env['REQUEST_METHOD'])
- ret = OpenTox::Authorization.authorize("#{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}#{request.env['REQUEST_URI']}", request.env['REQUEST_METHOD'], subjectid)
- LOGGER.debug "OpenTox helpers OpenTox::Authorization authorized? method: #{request.env['REQUEST_METHOD']} , URI: #{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}#{request.env['REQUEST_URI']}, subjectid: #{subjectid} with return #{ret}."
+ ret = OpenTox::Authorization.authorize(uri, request.env['REQUEST_METHOD'], subjectid)
+ LOGGER.debug "OpenTox helpers OpenTox::Authorization authorized? method: #{request.env['REQUEST_METHOD']} , URI: #{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}#{request.env['REQUEST_URI']}, subjectid: #{subjectid} with return >>#{ret}<<"
return ret
end
if CONFIG[:authorization][:authenticate_request].include?(env['REQUEST_METHOD'])
- if OpenTox::Authorization.is_token_valid(subjectid)
- return true
- end
+ return true if OpenTox::Authorization.is_token_valid(subjectid)
end
LOGGER.debug "Not authorized for: #{request.env['rack.url_scheme']}://#{request['REQUEST_URI']} with Method: #{request.env['REQUEST_METHOD']} with Token #{subjectid}"
return false
end
+ #cleans URI from querystring and file-extension. Sets port 80 to emptystring
+ # @param [String] uri
+ def clean_uri(uri)
+ out = URI.parse(uri)
+ out.path = out.path[0, out.path.rindex(/[0-9]/) + 1] if out.path.rindex(/[0-9]/) #cuts after id for a&a
+ "#{out.scheme}:" + (out.port != 80 ? out.port : "") + "//#{out.host}#{out.path}"
+ end
+
+ def check_subjectid(subjectid)
+ return false if !subjectid
+ return true if subjectid.size > 62
+ false
+ end
+
+ #unprotected uris for login/logout, webapplication ...
def unprotected_requests
case env['REQUEST_URI']
when /\/login$|\/logout$|\/predict$|\/toxcreate\/models$/
return true
+ when /\/features/
+ return false
when /\/compound|\/feature|\/task|\/toxcreate/ #to fix: read from config | validation should be protected
return true
else
@@ -41,23 +58,18 @@ helpers do
end
end
- def check_subjectid(subjectid)
- return false if !subjectid
- return true if subjectid.size > 62
- false
- end
end
before do
unless unprotected_requests or CONFIG[:authorization][:free_request].include?(env['REQUEST_METHOD'])
begin
subjectid = session[:subjectid] if session[:subjectid]
- subjectid = params[:subjectid] if params[:subjectid] and !check_subjectid(subjectid)
+ subjectid = params[:subjectid] if params[:subjectid] and !check_subjectid(subjectid)
subjectid = request.env['HTTP_SUBJECTID'] if request.env['HTTP_SUBJECTID'] and !check_subjectid(subjectid)
# see http://rack.rubyforge.org/doc/SPEC.html
subjectid = CGI.unescape(subjectid) if subjectid.include?("%23")
rescue
- LOGGER.debug "OpenTox ruby api wrapper: helper before filter: NO subjectid."
+ LOGGER.debug "OpenTox ruby api wrapper: helper before filter: NO subjectid for URI: #{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}#{request.env['REQUEST_URI']}"
subjectid = ""
end
protected!(subjectid) if AA_SERVER
--
cgit v1.2.3
From 7327b1632cdaafd2d49d1ba8703a962f3c0e00d6 Mon Sep 17 00:00:00 2001
From: mr
Date: Mon, 10 Jan 2011 17:05:07 +0100
Subject: A&A
---
lib/model.rb | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
(limited to 'lib')
diff --git a/lib/model.rb b/lib/model.rb
index 953bb6c..32f5604 100644
--- a/lib/model.rb
+++ b/lib/model.rb
@@ -67,8 +67,8 @@ module OpenTox
# Find a lazar model
# @param [String] uri Model URI
# @return [OpenTox::Model::Lazar] lazar model
- def self.find(uri)
- YAML.load RestClientWrapper.get(uri,:accept => 'application/x-yaml')
+ def self.find(uri, subjectid=nil)
+ YAML.load RestClientWrapper.get(uri,{:accept => 'application/x-yaml', :subjectid => subjectid})
end
# Create a new lazar model
@@ -90,8 +90,8 @@ module OpenTox
# Predict a dataset
# @param [String] dataset_uri Dataset URI
# @return [OpenTox::Dataset] Dataset with predictions
- def predict_dataset(dataset_uri)
- @prediction_dataset = Dataset.create
+ def predict_dataset(dataset_uri, subjectid=nil)
+ @prediction_dataset = Dataset.create(CONFIG[:services]["opentox-dataset"], subjectid)
@prediction_dataset.add_metadata({
OT.hasSource => @uri,
DC.creator => @uri,
@@ -101,9 +101,9 @@ module OpenTox
d = Dataset.new(dataset_uri)
d.load_compounds
d.compounds.each do |compound_uri|
- predict(compound_uri,false)
+ predict(compound_uri,false,subjectid)
end
- @prediction_dataset.save
+ @prediction_dataset.save(subjectid)
@prediction_dataset
end
@@ -129,7 +129,7 @@ module OpenTox
} )
end
- return @prediction_dataset if database_activity
+ return @prediction_dataset if database_activity(subjectid)
neighbors
prediction = eval("#{@prediction_algorithm}(@neighbors,{:similarity_algorithm => @similarity_algorithm, :p_values => @p_values})")
@@ -245,11 +245,11 @@ module OpenTox
# Find database activities and store them in @prediction_dataset
# @return [Boolean] true if compound has databasse activities, false if not
- def database_activity
+ def database_activity(subjectid)
if @activities[@compound.uri]
@activities[@compound.uri].each { |act| @prediction_dataset.add @compound.uri, @metadata[OT.dependentVariables], act }
@prediction_dataset.add_metadata(OT.hasSource => @metadata[OT.trainingDataset])
- @prediction_dataset.save
+ @prediction_dataset.save(subjectid)
true
else
false
@@ -262,8 +262,8 @@ module OpenTox
end
# Delete model at model service
- def delete
- RestClientWrapper.delete @uri unless @uri == CONFIG[:services]["opentox-model"]
+ def delete(subjectid)
+ RestClientWrapper.delete(@uri, :subjectid => subjectid) unless @uri == CONFIG[:services]["opentox-model"]
end
end
--
cgit v1.2.3
From ecdd0347a347bd2ac5fa9e6a41ec7475b007309d Mon Sep 17 00:00:00 2001
From: mr
Date: Mon, 10 Jan 2011 17:47:09 +0100
Subject: A&A extent
---
lib/feature.rb | 4 ++--
lib/model.rb | 8 ++++----
lib/policy.rb | 9 +++++++++
lib/task.rb | 12 ++++++------
4 files changed, 21 insertions(+), 12 deletions(-)
(limited to 'lib')
diff --git a/lib/feature.rb b/lib/feature.rb
index 9e28077..349f8ae 100644
--- a/lib/feature.rb
+++ b/lib/feature.rb
@@ -2,10 +2,10 @@ module OpenTox
class Feature
include OpenTox
- def self.find(uri)
+ def self.find(uri, subjectid=nil)
feature = Feature.new uri
if (CONFIG[:yaml_hosts].include?(URI.parse(uri).host))
- feature.add_metadata YAML.load(RestClientWrapper.get(uri,:accept => "application/x-yaml"))
+ feature.add_metadata YAML.load(RestClientWrapper.get(uri,{:accept => "application/x-yaml", :subjectid => subjectid}))
else
feature.add_metadata Parser::Owl::Dataset.new(uri).load_metadata
end
diff --git a/lib/model.rb b/lib/model.rb
index 32f5604..7aa3f5c 100644
--- a/lib/model.rb
+++ b/lib/model.rb
@@ -60,8 +60,8 @@ module OpenTox
# Get URIs of all lazar models
# @return [Array] List of lazar model URIs
- def self.all
- RestClientWrapper.get(CONFIG[:services]["opentox-model"]).to_s.split("\n")
+ def self.all(subjectid=nil)
+ RestClientWrapper.get(CONFIG[:services]["opentox-model"], :subjectid => subjectid).to_s.split("\n")
end
# Find a lazar model
@@ -77,7 +77,7 @@ module OpenTox
def self.create(params)
lazar_algorithm = OpenTox::Algorithm::Generic.new File.join( CONFIG[:services]["opentox-algorithm"],"lazar")
model_uri = lazar_algorithm.run(params)
- OpenTox::Model::Lazar.find(model_uri)
+ OpenTox::Model::Lazar.find(model_uri, params[:subjectid])
end
# Get a parameter value
@@ -98,7 +98,7 @@ module OpenTox
DC.title => URI.decode(File.basename( @metadata[OT.dependentVariables] )),
OT.parameters => [{DC.title => "dataset_uri", OT.paramValue => dataset_uri}]
})
- d = Dataset.new(dataset_uri)
+ d = Dataset.new(dataset_uri,subjectid)
d.load_compounds
d.compounds.each do |compound_uri|
predict(compound_uri,false,subjectid)
diff --git a/lib/policy.rb b/lib/policy.rb
index 0ef8298..9c81fbd 100644
--- a/lib/policy.rb
+++ b/lib/policy.rb
@@ -33,6 +33,15 @@ module OpenTox
return true
end
+ #drop all policies in a policies instance
+ def names
+ out = []
+ @policies.each do |name, policy|
+ out << name
+ end
+ return out
+ end
+
#loads a default policy template in policies instance
def load_default_policy(user, uri, group="member")
template = case user
diff --git a/lib/task.rb b/lib/task.rb
index 18fba6e..9cf909f 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -50,12 +50,12 @@ module OpenTox
cpu_load = `cat /proc/loadavg`.split(/\s+/)[0..2].collect{|c| c.to_f}
nr_cpu_cores = `cat /proc/cpuinfo |grep "cpu cores"|cut -d ":" -f2|tr -d " "`.split("\n").collect{|c| c.to_i}.inject{|sum,n| sum+n}
nr_cpu_cores = 1 if !nr_cpu_cores
- if cpu_load[0] > nr_cpu_cores and cpu_load[0] > cpu_load[1] and cpu_load[1] > cpu_load[2] # average CPU load of the last minute is high and CPU load is increasing
- LOGGER.warn "Cannot start task - CPU load too high (#{cpu_load.join(", ")})"
- task.cancel
- return task
- #raise "Server too busy to start a new task"
- end
+ #if cpu_load[0] > nr_cpu_cores and cpu_load[0] > cpu_load[1] and cpu_load[1] > cpu_load[2] # average CPU load of the last minute is high and CPU load is increasing
+ # LOGGER.warn "Cannot start task - CPU load too high (#{cpu_load.join(", ")})"
+ # task.cancel
+ # return task
+ # #raise "Server too busy to start a new task"
+ #end
task_pid = Spork.spork(:logger => LOGGER) do
--
cgit v1.2.3
From 2aafed7543287c420a5aa2e751b8c74ad771d14c Mon Sep 17 00:00:00 2001
From: mr
Date: Thu, 13 Jan 2011 12:01:19 +0100
Subject: A&A for GET requests
---
lib/dataset.rb | 22 +++++++++++-----------
lib/model.rb | 2 +-
lib/opentox.rb | 8 ++++----
lib/parser.rb | 17 ++++++++++-------
4 files changed, 26 insertions(+), 23 deletions(-)
(limited to 'lib')
diff --git a/lib/dataset.rb b/lib/dataset.rb
index 52b41a7..a85c2b5 100644
--- a/lib/dataset.rb
+++ b/lib/dataset.rb
@@ -60,7 +60,7 @@ module OpenTox
# @param [optional,String] uri URI of the dataset service, defaults to service specified in configuration
# @return [Array] Array of dataset object without data (use one of the load_* methods to pull data from the server)
def self.all(uri=CONFIG[:services]["opentox-dataset"], subjectid=nil)
- RestClientWrapper.get(uri,{:accept => "text/uri-list",:subjectid => subjectid}).to_s.each_line.collect{|u| Dataset.new(u)}
+ RestClientWrapper.get(uri,{:accept => "text/uri-list",:subjectid => subjectid}).to_s.each_line.collect{|u| Dataset.new(u, subjectid)}
end
# Load YAML representation into the dataset
@@ -77,10 +77,10 @@ module OpenTox
# Load RDF/XML representation from a file
# @param [String] file File with RDF/XML representation of the dataset
# @return [OpenTox::Dataset] Dataset object with RDF/XML data
- def load_rdfxml_file(file)
- parser = Parser::Owl::Dataset.new @uri
+ def load_rdfxml_file(file, subjectid=nil)
+ parser = Parser::Owl::Dataset.new @uri, subjectid
parser.uri = file.path
- copy parser.load_uri
+ copy parser.load_uri(subjectid)
end
# Load CSV string (format specification: http://toxcreate.org/help)
@@ -111,8 +111,8 @@ module OpenTox
# Load and return only metadata of a Dataset object
# @return [Hash] Metadata of the dataset
- def load_metadata
- add_metadata Parser::Owl::Dataset.new(@uri).load_metadata
+ def load_metadata(subjectid=nil)
+ add_metadata Parser::Owl::Dataset.new(@uri, subjectid).load_metadata(subjectid)
self.uri = @uri if @uri # keep uri
@metadata
end
@@ -122,8 +122,8 @@ module OpenTox
if (CONFIG[:yaml_hosts].include?(URI.parse(@uri).host))
copy YAML.load(RestClientWrapper.get(@uri, {:accept => "application/x-yaml", :subjectid => subjectid}))
else
- parser = Parser::Owl::Dataset.new(@uri)
- copy parser.load_uri
+ parser = Parser::Owl::Dataset.new(@uri, subjectid)
+ copy parser.load_uri(subjectid)
end
end
@@ -138,9 +138,9 @@ module OpenTox
# Load and return only features from the dataset service
# @return [Hash] Features of the dataset
- def load_features
- parser = Parser::Owl::Dataset.new(@uri)
- @features = parser.load_features
+ def load_features(subjectid=nil)
+ parser = Parser::Owl::Dataset.new(@uri, subjectid)
+ @features = parser.load_features(subjectid)
@features
end
diff --git a/lib/model.rb b/lib/model.rb
index 7aa3f5c..6ef4af2 100644
--- a/lib/model.rb
+++ b/lib/model.rb
@@ -99,7 +99,7 @@ module OpenTox
OT.parameters => [{DC.title => "dataset_uri", OT.paramValue => dataset_uri}]
})
d = Dataset.new(dataset_uri,subjectid)
- d.load_compounds
+ d.load_compounds(subjectid)
d.compounds.each do |compound_uri|
predict(compound_uri,false,subjectid)
end
diff --git a/lib/opentox.rb b/lib/opentox.rb
index 90683e5..f1af5c3 100644
--- a/lib/opentox.rb
+++ b/lib/opentox.rb
@@ -19,14 +19,14 @@ module OpenTox
# Get all objects from a service
# @return [Array] List of available URIs
- def self.all(uri)
- RestClientWrapper.get(uri,:accept => "text/uri-list").to_s.split(/\n/)
+ def self.all(uri, subjectid=nil)
+ RestClientWrapper.get(uri,:accept => "text/uri-list", :subjectid => subjectid).to_s.split(/\n/)
end
# Load (and return) metadata from object URI
# @return [Hash] Metadata
- def load_metadata
- @metadata = Parser::Owl::Generic.new(@uri).load_metadata
+ def load_metadata(subjectid=nil)
+ @metadata = Parser::Owl::Generic.new(@uri).load_metadata(subjectid)
@metadata
end
diff --git a/lib/parser.rb b/lib/parser.rb
index b727412..a913cf2 100644
--- a/lib/parser.rb
+++ b/lib/parser.rb
@@ -29,14 +29,14 @@ module OpenTox
# Read metadata from opentox service
# @return [Hash] Object metadata
- def load_metadata
+ def load_metadata(subjectid=nil)
if @dataset
uri = File.join(@uri,"metadata")
else
uri = @uri
end
-
+ uri += "?subjectid=#{CGI.escape(subjectid)}" if subjectid
statements = []
parameter_ids = []
`rapper -i rdfxml -o ntriples #{uri} 2>/dev/null`.each_line do |line|
@@ -71,9 +71,9 @@ module OpenTox
# Create a new OWL-DL dataset parser
# @param uri Dataset URI
# @return [OpenTox::Parser::Owl::Dataset] OWL-DL parser
- def initialize(uri)
+ def initialize(uri, subjectid=nil)
super uri
- @dataset = ::OpenTox::Dataset.new(@uri)
+ @dataset = ::OpenTox::Dataset.new(@uri, subjectid)
end
# Read data from dataset service. Files can be parsed by setting #uri to a filename (after initialization with a real URI)
@@ -87,12 +87,14 @@ module OpenTox
# dataset = parser.load_uri
# dataset.save
# @return [Hash] Internal dataset representation
- def load_uri
+ def load_uri(subjectid=nil)
+ uri = @uri
+ uri += "?subjectid=#{CGI.escape(subjectid)}" if subjectid
data = {}
feature_values = {}
feature = {}
other_statements = {}
- `rapper -i rdfxml -o ntriples #{@uri} 2>/dev/null`.each_line do |line|
+ `rapper -i rdfxml -o ntriples #{uri} 2>/dev/null`.each_line do |line|
triple = line.chomp.split(' ',3)
triple = triple[0..2].collect{|i| i.sub(/\s+.$/,'').gsub(/[<>"]/,'')}
case triple[1]
@@ -122,8 +124,9 @@ module OpenTox
# Read only features from a dataset service.
# @return [Hash] Internal features representation
- def load_features
+ def load_features(subjectid=nil)
uri = File.join(@uri,"features")
+ uri += "?subjectid=#{CGI.escape(subjectid)}" if subjectid
statements = []
features = Set.new
`rapper -i rdfxml -o ntriples #{uri} 2>/dev/null`.each_line do |line|
--
cgit v1.2.3
From f2ca545448ab8a6f654309f23cfce9416b2e9856 Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Thu, 13 Jan 2011 14:02:58 +0100
Subject: find methods for algorithm and model, split method for dataset,
feature_type method for model and feature, perform single predicitons in
resuce block, add to-html.rb, fix handling of rest-client-wrapper
---
lib/algorithm.rb | 14 ++++++
lib/dataset.rb | 33 +++++++++++++-
lib/feature.rb | 23 +++++++++-
lib/model.rb | 76 +++++++++++++++++++++++++++++++-
lib/opentox-ruby.rb | 2 +-
lib/overwrite.rb | 18 +++++++-
lib/rest_client_wrapper.rb | 18 +++-----
lib/task.rb | 106 ++++++++++++++++++++++++++++++++++++++++++++-
lib/to-html.rb | 80 ++++++++++++++++++++++++++++++++++
9 files changed, 351 insertions(+), 19 deletions(-)
create mode 100755 lib/to-html.rb
(limited to 'lib')
diff --git a/lib/algorithm.rb b/lib/algorithm.rb
index a2f7786..0aa86e6 100644
--- a/lib/algorithm.rb
+++ b/lib/algorithm.rb
@@ -29,6 +29,20 @@ module OpenTox
# Generic Algorithm class, should work with all OpenTox webservices
class Generic
include Algorithm
+
+ # Find Generic Opentox Algorithm via URI, and loads metadata
+ # @param [String] uri Algorithm URI
+ # @return [OpenTox::Algorithm::Generic] Algorithm instance, nil if alogrithm was not found
+ def self.find(uri)
+ alg = Generic.new(uri)
+ alg.load_metadata
+ if alg.metadata==nil or alg.metadata.size==0
+ nil
+ else
+ alg
+ end
+ end
+
end
# Fminer algorithms (https://github.com/amaunz/fminer2)
diff --git a/lib/dataset.rb b/lib/dataset.rb
index aba7754..d45c821 100644
--- a/lib/dataset.rb
+++ b/lib/dataset.rb
@@ -46,7 +46,7 @@ module OpenTox
dataset.save(subjectid)
dataset
end
-
+
# Find a dataset and load all data. This can be time consuming, use Dataset.new together with one of the load_* methods for a fine grained control over data loading.
# @param [String] uri Dataset URI
# @return [OpenTox::Dataset] Dataset object with all data
@@ -242,6 +242,37 @@ module OpenTox
def add_feature_metadata(feature,metadata)
metadata.each { |k,v| @features[feature][k] = v }
end
+
+ # Add a new compound
+ # @param [String] compound Compound URI
+ def add_compound (compound)
+ @compounds << compound unless @compounds.include? compound
+ end
+
+ # Creates a new dataset, by splitting the current dataset, i.e. using only a subset of compounds and features
+ # @param [Array] compounds List of compound URIs
+ # @param [Array] features List of feature URIs
+ # @param [Hash] metadata Hash containing the metadata for the new dataset
+ # @return [OpenTox::Dataset] newly created dataset, already saved
+ def split( compounds, features, metadata)
+ LOGGER.debug "split dataset using "+compounds.size.to_s+"/"+@compounds.size.to_s+" compounds"
+ raise "no new compounds selected" unless compounds and compounds.size>0
+ dataset = OpenTox::Dataset.create
+ if features.size==0
+ compounds.each{ |c| dataset.add_compound(c) }
+ else
+ compounds.each do |c|
+ features.each do |f|
+ @data_entries[c][f].each do |v|
+ dataset.add(c,f,v)
+ end
+ end
+ end
+ end
+ dataset.add_metadata(metadata)
+ dataset.save
+ dataset
+ end
# Save dataset at the dataset service
# - creates a new dataset if uri is not set
diff --git a/lib/feature.rb b/lib/feature.rb
index 9e28077..de7c757 100644
--- a/lib/feature.rb
+++ b/lib/feature.rb
@@ -1,7 +1,7 @@
module OpenTox
class Feature
include OpenTox
-
+
def self.find(uri)
feature = Feature.new uri
if (CONFIG[:yaml_hosts].include?(URI.parse(uri).host))
@@ -11,5 +11,26 @@ module OpenTox
end
feature
end
+
+ # provides domain (possible target values) of classification feature
+ # @return [Array] list with possible target values
+ def domain
+ #TODO derieve from metadata / ontology
+ return [true, false]
+ end
+
+ # provides feature type, possible types are "regression" or "classification"
+ # @return [String] feature type, unknown if OT.isA property is unknown/ not set
+ def feature_type
+ case metadata[OT.isA]
+ when /NominalFeature/
+ "classification"
+ when /NumericFeature/
+ "regression"
+ else
+ "unknown"
+ end
+ end
+
end
end
diff --git a/lib/model.rb b/lib/model.rb
index c645bdc..fb266e0 100644
--- a/lib/model.rb
+++ b/lib/model.rb
@@ -24,8 +24,76 @@ module OpenTox
# Generic OpenTox model class for all API compliant services
class Generic
include Model
+
+ # Find Generic Opentox Model via URI, and loads metadata
+ # @param [String] uri Model URI
+ # @return [OpenTox::Model::Generic] Model instance, nil if model was not found
+ def self.find(uri)
+ model = Generic.new(uri)
+ model.load_metadata
+ if model.metadata==nil or model.metadata.size==0
+ nil
+ else
+ model
+ end
+ end
+
+ # provides feature type, possible types are "regression" or "classification"
+ # @return [String] feature type, "unknown" if type could not be estimated
+ def feature_type
+ # dynamically perform restcalls if necessary
+ load_metadata if @metadata==nil or @metadata.size==0 or (@metadata.size==1 && @metadata.values[0]==@uri)
+ @dependentVariable = OpenTox::Feature.find( @metadata[OT.dependentVariables] ) unless @dependentVariable
+
+ [@dependentVariable.feature_type, @metadata[OT.isA], @metadata[DC.title], @uri].each do |type|
+ case type
+ when /(?i)classification/
+ return "classification"
+ when /(?i)regression/
+ return "regression"
+ end
+ end
+ raise "unknown model "+[@dependentVariable.feature_type, @metadata[OT.isA], @metadata[DC.title], @uri].inspect
+ end
+
+# def classification?
+# # TODO test on various services / request to ontology service needed?
+# # TODO replace bool (for classification/regression) with string value (more types are coming)
+# #raise "classification?: type: "+@type.to_s+", title: "+@title.to_s+", uri: "+@uri.to_s+" "+((@uri =~ /class/) != nil).to_s
+#
+# load_metadata if @metadata==nil or @metadata.size==0 or (@metadata.size==1 && @metadata.values[0]==@uri)
+# @dependentVariable = OpenTox::Feature.find( @metadata[OT.dependentVariables] ) unless @dependentVariable
+# case @dependentVariable.feature_type
+# when "classification"
+# return true
+# when "regression"
+# return false
+# end
+#
+# if @metadata[OT.isA] =~ /(?i)classification/
+# return true
+# end
+#
+# if @metadata[DC.title] =~ /(?i)classification/
+# return true
+# elsif @metadata[DC.title] =~ /(?i)regression/
+# return false
+# elsif @uri =~/ntua/ and @metadata[DC.title] =~ /mlr/
+# return false
+# elsif @uri =~/tu-muenchen/ and @metadata[DC.title] =~ /regression|M5P|GaussP/
+# return false
+# elsif @uri =~/ambit2/ and @metadata[DC.title] =~ /pKa/ || @metadata[DC.title] =~ /Regression|Caco/
+# return false
+# elsif @uri =~/majority/
+# return (@uri =~ /class/) != nil
+# else
+# raise "unknown model, uri:'"+@uri.to_s+"' title:'"+@metadata[DC.title].to_s+"'"
+# end
+# end
+# end
+
end
-
+
# Lazy Structure Activity Relationship class
class Lazar
@@ -101,7 +169,11 @@ module OpenTox
d = Dataset.new(dataset_uri)
d.load_compounds
d.compounds.each do |compound_uri|
- predict(compound_uri,false,subjectid)
+ begin
+ predict(compound_uri,false,subjectid)
+ rescue => ex
+ LOGGER.warn "prediction for compound "+compound_uri.to_s+" failed: "+ex.message
+ end
end
@prediction_dataset.save(subjectid)
@prediction_dataset
diff --git a/lib/opentox-ruby.rb b/lib/opentox-ruby.rb
index c0bff95..fb3803b 100644
--- a/lib/opentox-ruby.rb
+++ b/lib/opentox-ruby.rb
@@ -8,6 +8,6 @@ rescue LoadError
puts "Please install Openbabel with 'rake openbabel:install' in the compound component"
end
-['opentox', 'compound','dataset', 'parser','serializer', 'algorithm','model','task','validation','feature', 'rest_client_wrapper', 'authorization', 'policy', 'helper'].each do |lib|
+['opentox', 'compound','dataset', 'parser','serializer', 'algorithm','model','task','validation','feature', 'rest_client_wrapper', 'authorization', 'policy', 'helper', 'to-html'].each do |lib|
require lib
end
diff --git a/lib/overwrite.rb b/lib/overwrite.rb
index 8d787a6..e5ed5c3 100644
--- a/lib/overwrite.rb
+++ b/lib/overwrite.rb
@@ -2,6 +2,22 @@
# hack: store sinatra in global var to make url_for and halt methods accessible
before{ $sinatra = self unless $sinatra }
+# handle errors manually
+# this is to return 502, when an error occurs during a rest-call (see rest_client_wrapper.rb)
+set :raise_errors, Proc.new { false }
+set :show_exceptions, false
+error do
+ # try if the error is an OpenTox::Error
+ if OpenTox::Error.parse(request.env['sinatra.error'].to_s)
+ # if true, this error comes from rest_client_wrapper, halt with 502
+ # (502 is defined in OT API as Error coming from other service)
+ halt 502,request.env['sinatra.error']
+ else
+ # else, raise exception, this will return 500 = internal error
+ raise request.env['sinatra.error']
+ end
+end
+
class Sinatra::Base
# overwriting halt to log halts (!= 202)
def halt(*response)
@@ -60,7 +76,7 @@ class OTLogger < Logger
n = 2
line = lines[n]
- while (line =~ /spork.rb/ or line =~ /create/ or line =~ /ot-logger.rb/)
+ while (line =~ /spork.rb/ or line =~ /create/ or line =~ /overwrite.rb/)
n += 1
line = lines[n]
end
diff --git a/lib/rest_client_wrapper.rb b/lib/rest_client_wrapper.rb
index 5f5273b..2f0e215 100644
--- a/lib/rest_client_wrapper.rb
+++ b/lib/rest_client_wrapper.rb
@@ -115,7 +115,7 @@ module OpenTox
task = OpenTox::Task.from_yaml(res)
when /text\//
raise "uri list has more than one entry, should be a task" if res.content_type=~/text\/uri-list/ and res.split("\n").size > 1 #if uri list contains more then one uri, its not a task
- task = OpenTox::Task.find(res.to_s) if res.to_s.uri?
+ task = OpenTox::Task.find(res.to_s.chomp) if res.to_s.uri?
else
raise "unknown content-type for task: '"+res.content_type.to_s+"'" #+"' content: "+res[0..200].to_s
end
@@ -151,18 +151,14 @@ module OpenTox
File.new(File.join(error_dir,file_name+"_"+time+"_"+count.to_s),"w").puts(body)
# handle error
- # we are either in a task, or in sinatra
# PENDING: always return yaml for now
- if $self_task #this global var in Task.create to mark that the current process is running in a task
- raise error.to_yaml # the error is caught, logged, and task state is set to error in Task.create
- #elsif $sinatra #else halt sinatra
- #$sinatra.halt(502,error.to_yaml)
- elsif defined?(halt)
- halt(502,error.to_yaml)
- else #for testing purposes (if classes used directly)
- raise error.to_yaml
- end
+ # raising OpenTox::Error
+ # to handle the error yourself, put rest-call in begin, rescue block
+ # if the error is not caught:
+ # if we are in a task, the error is caught, logged, and task state is set to error in Task.as_task
+ # if we are in a default call, the error is handled in overwrite.rb to return 502 (according to OT API)
+ raise error.to_yaml
end
end
end
diff --git a/lib/task.rb b/lib/task.rb
index 18fba6e..dcbff3f 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -1,4 +1,3 @@
-$self_task=nil
module OpenTox
@@ -60,7 +59,6 @@ module OpenTox
task_pid = Spork.spork(:logger => LOGGER) do
LOGGER.debug "Task #{task.uri} started #{Time.now}"
- $self_task = task
begin
result = catch(:halt) do
@@ -254,7 +252,111 @@ module OpenTox
RestClientWrapper.raise_uri_error(ex.message, @uri)
end
end
+
+ public
+ #hint: do not overwrite percentageCompleted=, this is used in toYaml
+ def progress(pct)
+# #puts "task := "+pct.to_s
+# raise "no numeric >= 0 and <= 100 : '"+pct.to_s+"'" unless pct.is_a?(Numeric) and pct>=0 and pct<=100
+# RestClientWrapper.put(File.join(@uri,'Running'),{:percentageCompleted => pct})
+# reload
+ end
+
+ end
+
+ # Convenience class to split a (sub)task into subtasks
+ #
+ # example:
+ # a crossvalidation is split into creating datasets and performing the validations
+ # creating the dataset is 1/3 of the work, perform the validations is 2/3:
+ # Task.as_task do |task|
+ # create_datasets( SubTask.new(task, 0, 33) )
+ # perfom_validations( SubTask.new(task, 33, 100) )
+ # end
+ # inside the create_datasets / perform_validations you can use subtask.progress()
+ # with vals from 0-100
+ #
+ # note that you can split a subtask into further subtasks
+ class SubTask
+
+ def initialize(task, min, max)
+ raise "not a task or subtask" unless task.is_a?(Task) or task.is_a?(SubTask)
+ raise "invalid max ("+max.to_s+"), min ("+min.to_s+") params" unless
+ min.is_a?(Numeric) and max.is_a?(Numeric) and min >= 0 and max <= 100 and max > min
+ @task = task
+ @min = min
+ @max = max
+ @delta = max - min
+ end
+ # convenience method to handle null tasks
+ def self.create(task, min, max)
+ if task
+ SubTask.new(task, min, max)
+ else
+ nil
+ end
+ end
+
+ def progress(pct)
+ raise "no numeric >= 0 and <= 100 : '"+pct.to_s+"'" unless pct.is_a?(Numeric) and pct>=0 and pct<=100
+ #puts "subtask := "+pct.to_s+" -> task := "+(@min + @delta * pct.to_f * 0.01).to_s
+ @task.progress( @min + @delta * pct.to_f * 0.01 )
+ end
+
+ def running?()
+ @task.running?
+ end
+ end
+
+
+ # The David Gallagher feature:
+ # a fake sub task to keep the progress bar movin for external jobs
+ # note: param could be a subtask
+ #
+ # usage (for a call that is normally finished in under 60 seconds):
+ # fsk = FakeSubTask.new(task, 60)
+ # external_lib_call.start
+ # external_lib_call.wait_until_finished
+ # fsk.finished
+ #
+ # what happens:
+ # the FakeSubTask updates the task.progress each second until
+ # runtime is up or the finished mehtod is called
+ #
+ # example if the param runtime is too low:
+ # 25% .. 50% .. 75% .. 100% .. 100% .. 100% .. 100% .. 100%
+ # example if the param runtime is too high:
+ # 5% .. 10% .. 15% .. 20% .. 25% .. 30% .. 35% .. 100%
+ # the latter example is better (keep the bar movin!)
+ # -> better make a conservative runtime estimate
+ class FakeSubTask
+
+ def initialize(task, runtime)
+ @task = task
+ @thread = Thread.new do
+ timeleft = runtime
+ while (timeleft > 0 and @task.running?)
+ sleep 1
+ timeleft -= 1
+ @task.progress( (runtime - timeleft) / runtime.to_f * 100 )
+ end
+ end
+ end
+
+ # convenience method to handle null tasks
+ def self.create(task, runtime)
+ if task
+ FakeSubTask.new(task, runtime)
+ else
+ nil
+ end
+ end
+
+ def finished
+ @thread.exit
+ @task.progress(100) if @task.running?
+ end
end
end
diff --git a/lib/to-html.rb b/lib/to-html.rb
new file mode 100755
index 0000000..1bc1496
--- /dev/null
+++ b/lib/to-html.rb
@@ -0,0 +1,80 @@
+
+OT_LOGO = "http://opentox.informatik.uni-freiburg.de/ot-logo.png"
+
+
+class String
+
+ # encloses URI in text with with link tag
+ # @return [String] new text with marked links
+ def link_urls
+ self.gsub(/(?i)http:\/\/[^\r\n\s']*/, '\0')
+ end
+end
+
+module OpenTox
+
+ # produces a html page for making web services browser friendly
+ # format of text (=string params) is preserved (e.g. line breaks)
+ # urls are marked as links
+ # @example post params:
+ # [ [ [:mandatory_param_1], [:mandatory_param_2], [:optional_param,"default_value"] ],
+ # [ [:alteranative_mandatory_param_1], [:alteranative_mandatory_param_2] ]
+ # ]
+ # @param [String] text this is the actual content,
+ # @param [optional,String] related_links info on related resources
+ # @param [optional,String] description general info
+ # @param [optional,Array] post_params, array of arrays containing info on POST operation, see example
+ # @return [String] html page
+ def self.text_to_html( text, related_links=nil, description=nil, post_params=nil )
+
+ title = $sinatra.url_for($sinatra.request.env['PATH_INFO'], :full) if $sinatra
+
+ html = <
+EOF
+ html.chomp!
+ html += ""+title+"" if title
+ html += <
+
+EOF
+ html.chomp!
+ html += "
Description
"+description.link_urls+"
" if description
+ html += "
Related links
"+related_links.link_urls+"
" if related_links
+ if post_params
+ html += "
POST parameters
"
+ count = 0
+ post_params.each do |p|
+ html += "
alternatively:
" if count > 0
+ html += "
param
default_value
"
+ p.each do |k,v|
+ html += "
"+k.to_s+"
"+(v!=nil ? v.to_s : "mandatory")+"
"
+ end
+ html += "
"
+ count += 1
+ end
+ end
+ html += "
Content
" if description || related_links
+ html += <
+
+EOF
+ html.chomp!
+ html += text.link_urls
+ html += <
+
+
+
+EOF
+ html
+ end
+
+end
+
+#puts OpenTox.text_to_html("bla")
\ No newline at end of file
--
cgit v1.2.3
From 1db377c898a49417c669a52aaf75014f6a31158f Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Thu, 13 Jan 2011 14:10:59 +0100
Subject: remove old classification? in model.rb, add ie hack to overwrite
---
lib/model.rb | 36 ------------------------------------
lib/overwrite.rb | 6 +++++-
2 files changed, 5 insertions(+), 37 deletions(-)
(limited to 'lib')
diff --git a/lib/model.rb b/lib/model.rb
index fb266e0..1671ba7 100644
--- a/lib/model.rb
+++ b/lib/model.rb
@@ -56,42 +56,6 @@ module OpenTox
raise "unknown model "+[@dependentVariable.feature_type, @metadata[OT.isA], @metadata[DC.title], @uri].inspect
end
-# def classification?
-# # TODO test on various services / request to ontology service needed?
-# # TODO replace bool (for classification/regression) with string value (more types are coming)
-# #raise "classification?: type: "+@type.to_s+", title: "+@title.to_s+", uri: "+@uri.to_s+" "+((@uri =~ /class/) != nil).to_s
-#
-# load_metadata if @metadata==nil or @metadata.size==0 or (@metadata.size==1 && @metadata.values[0]==@uri)
-# @dependentVariable = OpenTox::Feature.find( @metadata[OT.dependentVariables] ) unless @dependentVariable
-# case @dependentVariable.feature_type
-# when "classification"
-# return true
-# when "regression"
-# return false
-# end
-#
-# if @metadata[OT.isA] =~ /(?i)classification/
-# return true
-# end
-#
-# if @metadata[DC.title] =~ /(?i)classification/
-# return true
-# elsif @metadata[DC.title] =~ /(?i)regression/
-# return false
-# elsif @uri =~/ntua/ and @metadata[DC.title] =~ /mlr/
-# return false
-# elsif @uri =~/tu-muenchen/ and @metadata[DC.title] =~ /regression|M5P|GaussP/
-# return false
-# elsif @uri =~/ambit2/ and @metadata[DC.title] =~ /pKa/ || @metadata[DC.title] =~ /Regression|Caco/
-# return false
-# elsif @uri =~/majority/
-# return (@uri =~ /class/) != nil
-# else
-# raise "unknown model, uri:'"+@uri.to_s+"' title:'"+@metadata[DC.title].to_s+"'"
-# end
-# end
-# end
-
end
# Lazy Structure Activity Relationship class
diff --git a/lib/overwrite.rb b/lib/overwrite.rb
index e5ed5c3..ffeba21 100644
--- a/lib/overwrite.rb
+++ b/lib/overwrite.rb
@@ -1,6 +1,10 @@
# class overwrites aka monkey patches
# hack: store sinatra in global var to make url_for and halt methods accessible
-before{ $sinatra = self unless $sinatra }
+before {
+ $sinatra = self unless $sinatra
+ # stupid internet explorer does not ask for text/html, add this manually
+ request.env['HTTP_ACCEPT'] += ";text/html" if request.env["HTTP_USER_AGENT"]=~/MSIE/
+}
# handle errors manually
# this is to return 502, when an error occurs during a rest-call (see rest_client_wrapper.rb)
--
cgit v1.2.3
From 97e3942191e1ab8f084ba8da475749a9609c37aa Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Fri, 14 Jan 2011 14:54:14 +0100
Subject: add percentage completed support
---
lib/algorithm.rb | 5 ++--
lib/model.rb | 12 ++++++--
lib/rest_client_wrapper.rb | 68 ++++++++++++++++++++++++++++++++++------------
lib/task.rb | 33 +++++++++++++---------
4 files changed, 83 insertions(+), 35 deletions(-)
(limited to 'lib')
diff --git a/lib/algorithm.rb b/lib/algorithm.rb
index 0aa86e6..58a2640 100644
--- a/lib/algorithm.rb
+++ b/lib/algorithm.rb
@@ -13,9 +13,10 @@ module OpenTox
# Execute algorithm with parameters, please consult the OpenTox API and the webservice documentation for acceptable parameters
# @param [optional,Hash] params Algorithm parameters
+ # @param [optional,OpenTox::Task] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
# @return [String] URI of new resource (dataset, model, ...)
- def run(params=nil)
- RestClientWrapper.post(@uri, {:accept => 'text/uri-list'}, params).to_s
+ def run(params=nil, waiting_task=nil)
+ RestClientWrapper.post(@uri, {:accept => 'text/uri-list'}, params, waiting_task).to_s
end
# Get OWL-DL representation in RDF/XML format
diff --git a/lib/model.rb b/lib/model.rb
index 1671ba7..e95c78c 100644
--- a/lib/model.rb
+++ b/lib/model.rb
@@ -6,15 +6,16 @@ module OpenTox
# Run a model with parameters
# @param [Hash] params Parameters for OpenTox model
+ # @param [optional,OpenTox::Task] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
# @return [text/uri-list] Task or resource URI
- def run(params)
+ def run( params, waiting_task=nil )
if CONFIG[:yaml_hosts].include?(URI.parse(@uri).host)
accept = 'application/x-yaml'
else
accept = 'application/rdf+xml'
end
begin
- RestClientWrapper.post(@uri,{:accept => accept},params).to_s
+ RestClientWrapper.post(@uri,{:accept => accept},params,waiting_task).to_s
rescue => e
LOGGER.error "Failed to run #{@uri} with #{params.inspect} (#{e.inspect})"
raise "Failed to run #{@uri} with #{params.inspect}"
@@ -121,8 +122,10 @@ module OpenTox
# Predict a dataset
# @param [String] dataset_uri Dataset URI
+ # @param [optional,subjectid]
+ # @param [optional,OpenTox::Task] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
# @return [OpenTox::Dataset] Dataset with predictions
- def predict_dataset(dataset_uri, subjectid=nil)
+ def predict_dataset(dataset_uri, subjectid=nil, waiting_task=nil)
@prediction_dataset = Dataset.create(CONFIG[:services]["opentox-dataset"], subjectid)
@prediction_dataset.add_metadata({
OT.hasSource => @uri,
@@ -132,9 +135,12 @@ module OpenTox
})
d = Dataset.new(dataset_uri)
d.load_compounds
+ count = 0
d.compounds.each do |compound_uri|
begin
predict(compound_uri,false,subjectid)
+ count += 1
+ waiting_task.progress( count/d.compounds.size.to_f*100.0 ) if waiting_task
rescue => ex
LOGGER.warn "prediction for compound "+compound_uri.to_s+" failed: "+ex.message
end
diff --git a/lib/rest_client_wrapper.rb b/lib/rest_client_wrapper.rb
index 2f0e215..920a828 100644
--- a/lib/rest_client_wrapper.rb
+++ b/lib/rest_client_wrapper.rb
@@ -34,33 +34,67 @@ module OpenTox
class RestClientWrapper
- def self.get(uri, headers=nil, wait=true)
- execute( "get", uri, headers, nil, wait)
+ # performs a GET REST call
+ # raises OpenTox::Error if call fails (rescued in overwrite.rb -> halt 502)
+ # per default: waits for Task to finish and returns result URI of Task
+ # @param [String] uri destination URI
+ # @param [optional,Hash] headers contains params like accept-header
+ # @param [optional,OpenTox::Task] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
+ # @param [wait,Boolean] wait set to false to NOT wait for task if result is task
+ # @return [OpenTox::WrapperResult] a String containing the result-body of the REST call
+ def self.get(uri, headers=nil, waiting_task=nil, wait=true )
+ execute( "get", uri, headers, nil, waiting_task, wait)
end
- def self.post(uri, headers, payload=nil, wait=true)
- execute( "post", uri, headers, payload, wait )
+ # performs a POST REST call
+ # raises OpenTox::Error if call fails (rescued in overwrite.rb -> halt 502)
+ # per default: waits for Task to finish and returns result URI of Task
+ # @param [String] uri destination URI
+ # @param [optional,Hash] headers contains params like accept-header
+ # @param [optional,String] payload data posted to the service
+ # @param [optional,OpenTox::Task] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
+ # @param [wait,Boolean] wait set to false to NOT wait for task if result is task
+ # @return [OpenTox::WrapperResult] a String containing the result-body of the REST call
+ def self.post(uri, headers, payload=nil, waiting_task=nil, wait=true )
+ execute( "post", uri, headers, payload, waiting_task, wait )
end
+ # performs a PUT REST call
+ # raises OpenTox::Error if call fails (rescued in overwrite.rb -> halt 502)
+ # @param [String] uri destination URI
+ # @param [optional,Hash] headers contains params like accept-header
+ # @param [optional,String] payload data put to the service
+ # @return [OpenTox::WrapperResult] a String containing the result-body of the REST call
def self.put(uri, headers, payload=nil )
execute( "put", uri, headers, payload )
end
- def self.delete(uri, headers=nil)
+ # performs a DELETE REST call
+ # raises OpenTox::Error if call fails (rescued in overwrite.rb -> halt 502)
+ # @param [String] uri destination URI
+ # @param [optional,Hash] headers contains params like accept-header
+ # @return [OpenTox::WrapperResult] a String containing the result-body of the REST call
+ def self.delete(uri, headers=nil )
execute( "delete", uri, headers, nil)
end
+ # raises an Error message (rescued in overwrite.rb -> halt 502)
+ # usage: if the return value of a call is invalid
+ # @param [String] error_msg the error message
+ # @param [String] uri destination URI that is responsible for the error
+ # @param [optional,Hash] headers sent to the URI
+ # @param [optional,String] payload data sent to the URI
def self.raise_uri_error(error_msg, uri, headers=nil, payload=nil)
- do_halt( "-", error_msg, uri, headers, payload )
+ raise_ot_error( "-", error_msg, uri, headers, payload )
end
private
- def self.execute( rest_call, uri, headers, payload=nil, wait=true )
+ def self.execute( rest_call, uri, headers, payload=nil, waiting_task=nil, wait=true )
- do_halt 400,"uri is null",uri,headers,payload unless uri
- do_halt 400,"not a uri",uri,headers,payload unless uri.to_s.uri?
- do_halt 400,"headers are no hash",uri,headers,payload unless headers==nil or headers.is_a?(Hash)
- do_halt 400,"nil headers for post not allowed, use {}",uri,headers,payload if rest_call=="post" and headers==nil
+ raise_ot_error 400,"uri is null",uri,headers,payload unless uri
+ raise_ot_error 400,"not a uri",uri,headers,payload unless uri.to_s.uri?
+ raise_ot_error 400,"headers are no hash",uri,headers,payload unless headers==nil or headers.is_a?(Hash)
+ raise_ot_error 400,"nil headers for post not allowed, use {}",uri,headers,payload if rest_call=="post" and headers==nil
headers.each{ |k,v| headers.delete(k) if v==nil } if headers #remove keys with empty values, as this can cause problems
begin
@@ -84,13 +118,13 @@ module OpenTox
return res if res.code==200 || !wait
while (res.code==201 || res.code==202)
- res = wait_for_task(res, uri)
+ res = wait_for_task(res, uri, waiting_task)
end
raise "illegal status code: '"+res.code.to_s+"'" unless res.code==200
return res
rescue RestClient::RequestTimeout => ex
- do_halt 408,ex.message,uri,headers,payload
+ raise_ot_error 408,ex.message,uri,headers,payload
rescue => ex
#raise ex
#raise "'"+ex.message+"' uri: "+uri.to_s
@@ -101,11 +135,11 @@ module OpenTox
code = 500
msg = ex.to_s
end
- do_halt code,msg,uri,headers,payload
+ raise_ot_error code,msg,uri,headers,payload
end
end
- def self.wait_for_task( res, base_uri )
+ def self.wait_for_task( res, base_uri, waiting_task=nil )
task = nil
case res.content_type
@@ -121,7 +155,7 @@ module OpenTox
end
LOGGER.debug "result is a task '"+task.uri.to_s+"', wait for completion"
- task.wait_for_completion
+ task.wait_for_completion waiting_task
raise task.description unless task.completed? # maybe task was cancelled / error
res = WrapperResult.new task.result_uri
@@ -130,7 +164,7 @@ module OpenTox
return res
end
- def self.do_halt( code, body, uri, headers, payload=nil )
+ def self.raise_ot_error( code, body, uri, headers, payload=nil )
#build error
causing_errors = Error.parse(body)
diff --git a/lib/task.rb b/lib/task.rb
index dcbff3f..d701c82 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -12,7 +12,7 @@ module OpenTox
DC.title => "",
DC.date => "",
OT.hasStatus => "Running",
- OT.percentageCompleted => "0",
+ OT.percentageCompleted => 0.0,
OT.resultURI => "",
DC.creator => "", # not mandatory according to API
DC.description => "", # not mandatory according to API
@@ -160,12 +160,12 @@ module OpenTox
def load_metadata
if (CONFIG[:yaml_hosts].include?(URI.parse(uri).host))
- result = RestClientWrapper.get(@uri, {:accept => 'application/x-yaml'}, false)
+ result = RestClientWrapper.get(@uri, {:accept => 'application/x-yaml'}, nil, false)
@metadata = YAML.load result.to_s
@http_code = result.code
else
@metadata = Parser::Owl::Generic.new(@uri).load_metadata
- @http_code = RestClientWrapper.get(uri, {:accept => 'application/rdf+xml'}, false).code
+ @http_code = RestClientWrapper.get(uri, {:accept => 'application/rdf+xml'}, nil, false).code
end
end
@@ -216,7 +216,9 @@ module OpenTox
=end
# waits for a task, unless time exceeds or state is no longer running
- def wait_for_completion(dur=0.3)
+ # @param [optional,OpenTox::Task] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
+ # @param [optional,Numeric] dur seconds pausing before cheking again for completion
+ def wait_for_completion( waiting_task=nil, dur=0.3)
due_to_time = Time.new + DEFAULT_TASK_MAX_DURATION
LOGGER.debug "start waiting for task "+@uri.to_s+" at: "+Time.new.to_s+", waiting at least until "+due_to_time.to_s
@@ -226,6 +228,8 @@ module OpenTox
while self.running?
sleep dur
load_metadata
+ # if another (sub)task is waiting for self, set progress accordingly
+ waiting_task.progress(@metadata[OT.percentageCompleted]) if waiting_task
check_state
if (Time.new > due_to_time)
raise "max wait time exceeded ("+DEFAULT_TASK_MAX_DURATION.to_s+"sec), task: '"+@uri.to_s+"'"
@@ -234,6 +238,18 @@ module OpenTox
LOGGER.debug "Task '"+@metadata[OT.hasStatus]+"': "+@uri.to_s+", Result: "+@metadata[OT.resultURI].to_s
end
+
+ # updates percentageCompleted value (can only be increased)
+ # task has to be running
+ # @param [Numeric] pct value between 0 and 100
+ def progress(pct)
+ #puts "task := "+pct.to_s
+ raise "no numeric >= 0 and <= 100 : '"+pct.to_s+"'" unless pct.is_a?(Numeric) and pct>=0 and pct<=100
+ if (pct > @metadata[OT.percentageCompleted] + 0.0001)
+ RestClientWrapper.put(File.join(@uri,'Running'),{:percentageCompleted => pct})
+ load_metadata
+ end
+ end
private
def check_state
@@ -252,15 +268,6 @@ module OpenTox
RestClientWrapper.raise_uri_error(ex.message, @uri)
end
end
-
- public
- #hint: do not overwrite percentageCompleted=, this is used in toYaml
- def progress(pct)
-# #puts "task := "+pct.to_s
-# raise "no numeric >= 0 and <= 100 : '"+pct.to_s+"'" unless pct.is_a?(Numeric) and pct>=0 and pct<=100
-# RestClientWrapper.put(File.join(@uri,'Running'),{:percentageCompleted => pct})
-# reload
- end
end
--
cgit v1.2.3
From 9197d6a6503b3995e6f9499840e91a9ed6d3a1db Mon Sep 17 00:00:00 2001
From: mr
Date: Tue, 18 Jan 2011 13:07:52 +0100
Subject: get subjectid from api-wrapper helper
---
lib/environment.rb | 3 +++
lib/helper.rb | 13 ++++++++-----
2 files changed, 11 insertions(+), 5 deletions(-)
(limited to 'lib')
diff --git a/lib/environment.rb b/lib/environment.rb
index 1761d92..203ebc6 100644
--- a/lib/environment.rb
+++ b/lib/environment.rb
@@ -84,6 +84,9 @@ class OwlNamespace
end
AA_SERVER = CONFIG[:authorization] ? (CONFIG[:authorization][:server] ? CONFIG[:authorization][:server] : nil) : nil
+CONFIG[:authorization][:authenticate_request] = [""] unless CONFIG[:authorization][:authenticate_request]
+CONFIG[:authorization][:authorize_request] = [""] unless CONFIG[:authorization][:authorize_request]
+CONFIG[:authorization][:free_request] = [""] unless CONFIG[:authorization][:free_request]
RDF = OwlNamespace.new 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'
OWL = OwlNamespace.new 'http://www.w3.org/2002/07/owl#'
diff --git a/lib/helper.rb b/lib/helper.rb
index 857c5b5..cc643f3 100644
--- a/lib/helper.rb
+++ b/lib/helper.rb
@@ -17,16 +17,18 @@ helpers do
#Check Authorization for URI with method and subjectid.
def authorized?(subjectid)
+ request_method = request.env['REQUEST_METHOD']
uri = clean_uri("#{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}#{request.env['REQUEST_URI']}")
- if CONFIG[:authorization][:authorize_request].include?(request.env['REQUEST_METHOD'])
- ret = OpenTox::Authorization.authorize(uri, request.env['REQUEST_METHOD'], subjectid)
- LOGGER.debug "OpenTox helpers OpenTox::Authorization authorized? method: #{request.env['REQUEST_METHOD']} , URI: #{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}#{request.env['REQUEST_URI']}, subjectid: #{subjectid} with return >>#{ret}<<"
+ request_method = "GET" if request_method == "POST" && uri =~ /\/model\/\d+\/?$/
+ if CONFIG[:authorization][:authorize_request].include?(request_method)
+ ret = OpenTox::Authorization.authorize(uri, request_method, subjectid)
+ LOGGER.debug "OpenTox helpers OpenTox::Authorization authorized? method: #{request_method} , URI: #{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}#{request.env['REQUEST_URI']}, subjectid: #{subjectid} with return >>#{ret}<<"
return ret
end
- if CONFIG[:authorization][:authenticate_request].include?(env['REQUEST_METHOD'])
+ if CONFIG[:authorization][:authenticate_request].include?(request_method)
return true if OpenTox::Authorization.is_token_valid(subjectid)
end
- LOGGER.debug "Not authorized for: #{request.env['rack.url_scheme']}://#{request['REQUEST_URI']} with Method: #{request.env['REQUEST_METHOD']} with Token #{subjectid}"
+ LOGGER.debug "Not authorized for: #{uri} with Method: #{request.env['REQUEST_METHOD']}/#{request_method} with Token #{subjectid}"
return false
end
@@ -68,6 +70,7 @@ before do
subjectid = request.env['HTTP_SUBJECTID'] if request.env['HTTP_SUBJECTID'] and !check_subjectid(subjectid)
# see http://rack.rubyforge.org/doc/SPEC.html
subjectid = CGI.unescape(subjectid) if subjectid.include?("%23")
+ @subjectid = subjectid
rescue
LOGGER.debug "OpenTox ruby api wrapper: helper before filter: NO subjectid for URI: #{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}#{request.env['REQUEST_URI']}"
subjectid = ""
--
cgit v1.2.3
From dbd302164b74de2b241627bcc205de7245ea0da1 Mon Sep 17 00:00:00 2001
From: mr
Date: Tue, 18 Jan 2011 17:15:14 +0100
Subject: refactoring A&A
---
lib/authorization.rb | 6 +++++-
lib/helper.rb | 30 ++++++++++++++----------------
2 files changed, 19 insertions(+), 17 deletions(-)
(limited to 'lib')
diff --git a/lib/authorization.rb b/lib/authorization.rb
index dab228a..7e898cc 100644
--- a/lib/authorization.rb
+++ b/lib/authorization.rb
@@ -286,7 +286,11 @@ module OpenTox
end
true
end
-
+
+ class << self
+ alias :token_valid? :is_token_valid
+ end
+
end
end
diff --git a/lib/helper.rb b/lib/helper.rb
index cc643f3..5fe1857 100644
--- a/lib/helper.rb
+++ b/lib/helper.rb
@@ -3,18 +3,21 @@ helpers do
# Authentification
def protected!(subjectid)
if env["session"]
- flash[:notice] = "You don't have access to this section: " and \
- redirect back and \
- return unless authorized?(subjectid)
+ unless authorized?(subjectid)
+ flash[:notice] = "You don't have access to this section: "
+ redirect back
+ end
elsif !env["session"] && subjectid
- throw(:halt, [401, "Not authorized.\n"]) and \
- redirect back and \
- return unless authorized?(subjectid)
+ unless authorized?(subjectid)
+ throw(:halt, [401, "Not authorized.\n"])
+ redirect back
+ end
+ else
+ throw(:halt, [401, "Not authorized.\n"]) unless authorized?(subjectid)
end
- throw(:halt, [401, "Not authorized.\n"]) and \
- return unless authorized?(subjectid)
end
+
#Check Authorization for URI with method and subjectid.
def authorized?(subjectid)
request_method = request.env['REQUEST_METHOD']
@@ -40,12 +43,6 @@ helpers do
"#{out.scheme}:" + (out.port != 80 ? out.port : "") + "//#{out.host}#{out.path}"
end
- def check_subjectid(subjectid)
- return false if !subjectid
- return true if subjectid.size > 62
- false
- end
-
#unprotected uris for login/logout, webapplication ...
def unprotected_requests
case env['REQUEST_URI']
@@ -65,9 +62,10 @@ end
before do
unless unprotected_requests or CONFIG[:authorization][:free_request].include?(env['REQUEST_METHOD'])
begin
+ subjectid = nil
subjectid = session[:subjectid] if session[:subjectid]
- subjectid = params[:subjectid] if params[:subjectid] and !check_subjectid(subjectid)
- subjectid = request.env['HTTP_SUBJECTID'] if request.env['HTTP_SUBJECTID'] and !check_subjectid(subjectid)
+ subjectid = params[:subjectid] if params[:subjectid] and !subjectid
+ subjectid = request.env['HTTP_SUBJECTID'] if request.env['HTTP_SUBJECTID'] and !subjectid
# see http://rack.rubyforge.org/doc/SPEC.html
subjectid = CGI.unescape(subjectid) if subjectid.include?("%23")
@subjectid = subjectid
--
cgit v1.2.3
From 23d96df630689d122c023d76ec1d40d7688d2c96 Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Wed, 19 Jan 2011 15:59:12 +0100
Subject: extend authorization and rdf serialization for validation
---
lib/authorization.rb | 48 ++++++++++++++++----
lib/dataset.rb | 7 +--
lib/error.rb | 11 +++++
lib/helper.rb | 25 ++++++-----
lib/opentox-ruby.rb | 3 +-
lib/overwrite.rb | 10 +++--
lib/policy.rb | 10 +++++
lib/serializer.rb | 124 +++++++++++++++++++++++++++++++++++++++++++++++++++
lib/to-html.rb | 3 +-
9 files changed, 213 insertions(+), 28 deletions(-)
create mode 100644 lib/error.rb
(limited to 'lib')
diff --git a/lib/authorization.rb b/lib/authorization.rb
index f9499e6..c33f712 100644
--- a/lib/authorization.rb
+++ b/lib/authorization.rb
@@ -132,6 +132,20 @@ module OpenTox
end
end
+ # Lists policies alongside with affected uris
+ # @param [String] subjectid
+ # @return [Hash] keys: all policies of the subjectid owner, values: uris affected by those policies
+ def self.list_policy_uris( subjectid )
+ names = list_policies(subjectid)
+ policies = {}
+ names.each do |n|
+ p = OpenTox::Policies.new
+ p.load_xml( list_policy(n, subjectid) )
+ policies[n] = p.uris
+ end
+ policies
+ end
+
#Returns the owner (who created the first policy) of an URI
# @param [String, String]uri,subjectid
# return [String, nil]owner,nil returns owner of the URI
@@ -271,21 +285,37 @@ module OpenTox
return true
end
- #Checks (if subjectid is valid) if a policy exist and create default policy if not
+ # Checks (if subjectid is valid) if a policy exist and create default policy if not
+ # @param [String] uri
+ # @param [String] subjectid
+ # @return [Boolean] true if policy checked/created successfully (or no uri/subjectid given), false else
def self.check_policy(uri, subjectid)
+ return true unless uri and subjectid
token_valid = OpenTox::Authorization.is_token_valid(subjectid)
LOGGER.debug "OpenTox::Authorization.check_policy with uri: #{uri}, subjectid: #{subjectid} is valid: #{token_valid}"
- if uri and token_valid
- if !uri_has_policy(uri, subjectid)
- return send_policy(uri, subjectid)
- else
- LOGGER.debug "OpenTox::Authorization.check_policy URI: #{uri} has already a Policy."
+ # check if subjectid is valid
+ unless token_valid
+ # abort if invalid
+ LOGGER.error "OpenTox::Authorization.check_policy, subjectid NOT valid: #{subjectid}"
+ return false
+ end
+
+ if !uri_has_policy(uri, subjectid)
+ # if no policy exists, create a policy, return result of send policy
+ send_policy(uri, subjectid)
+ else
+ LOGGER.debug "OpenTox::Authorization.check_policy URI: #{uri} has already a Policy."
+ # if policy exists check for POST rights
+ if authorize(uri, "POST", subjectid)
+ true
+ else
+ LOGGER.error "OpenTox::Authorization.check_policy, already exists, but no POST-authorization with subjectid: #{subjectid}"
+ false
end
end
- true
- end
+ end
- end
+ end
end
diff --git a/lib/dataset.rb b/lib/dataset.rb
index d45c821..ae86f5f 100644
--- a/lib/dataset.rb
+++ b/lib/dataset.rb
@@ -253,11 +253,12 @@ module OpenTox
# @param [Array] compounds List of compound URIs
# @param [Array] features List of feature URIs
# @param [Hash] metadata Hash containing the metadata for the new dataset
+ # @param [String] subjectid
# @return [OpenTox::Dataset] newly created dataset, already saved
- def split( compounds, features, metadata)
+ def split( compounds, features, metadata, subjectid=nil)
LOGGER.debug "split dataset using "+compounds.size.to_s+"/"+@compounds.size.to_s+" compounds"
raise "no new compounds selected" unless compounds and compounds.size>0
- dataset = OpenTox::Dataset.create
+ dataset = OpenTox::Dataset.create(CONFIG[:services]["opentox-dataset"],subjectid)
if features.size==0
compounds.each{ |c| dataset.add_compound(c) }
else
@@ -270,7 +271,7 @@ module OpenTox
end
end
dataset.add_metadata(metadata)
- dataset.save
+ dataset.save(subjectid)
dataset
end
diff --git a/lib/error.rb b/lib/error.rb
new file mode 100644
index 0000000..87e1a5d
--- /dev/null
+++ b/lib/error.rb
@@ -0,0 +1,11 @@
+module OpenTox
+
+ class NotFoundError < RuntimeError
+
+ end
+
+ class BadRequestError < RuntimeError
+
+ end
+
+end
\ No newline at end of file
diff --git a/lib/helper.rb b/lib/helper.rb
index 965b4ad..bb0279e 100644
--- a/lib/helper.rb
+++ b/lib/helper.rb
@@ -3,22 +3,24 @@ helpers do
# Authentification
def protected!(subjectid)
if env["session"]
- flash[:notice] = "You don't have access to this section: " and \
- redirect back and \
- return unless authorized?(subjectid)
+ unless authorized?(subjectid)
+ flash[:notice] = "You don't have access to this section: "
+ redirect back
+ end
elsif !env["session"] && subjectid
- throw(:halt, [401, "Not authorized.\n"]) and \
- redirect back and \
- return unless authorized?(subjectid)
+ unless authorized?(subjectid)
+ throw(:halt, [401, "Not authorized.\n"])
+ redirect back
+ end
+ else
+ throw(:halt, [401, "Not authorized.\n"]) unless authorized?(subjectid)
end
- throw(:halt, [401, "Not authorized.\n"]) and \
- return unless authorized?(subjectid)
end
def authorized?(subjectid)
if CONFIG[:authorization][:authorize_request].include?(request.env['REQUEST_METHOD'])
ret = OpenTox::Authorization.authorize("#{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}#{request.env['REQUEST_URI']}", request.env['REQUEST_METHOD'], subjectid)
- LOGGER.debug "OpenTox helpers OpenTox::Authorization authorized? method: #{request.env['REQUEST_METHOD']} , URI: #{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}#{request.env['REQUEST_URI']}, subjectid: #{subjectid} with return #{ret}."
+ LOGGER.debug "OpenTox helpers OpenTox::Authorization authorized? method: #{request.env['REQUEST_METHOD']}, URI: #{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}#{request.env['REQUEST_URI']}, subjectid: #{subjectid} with return #{ret}."
return ret
end
if CONFIG[:authorization][:authenticate_request].include?(env['REQUEST_METHOD'])
@@ -49,7 +51,7 @@ helpers do
end
before do
- unless unprotected_requests or CONFIG[:authorization][:free_request].include?(env['REQUEST_METHOD'])
+ unless !AA_SERVER or unprotected_requests or CONFIG[:authorization][:free_request].include?(env['REQUEST_METHOD'])
begin
subjectid = session[:subjectid] if session[:subjectid]
subjectid = params[:subjectid] if params[:subjectid] and !check_subjectid(subjectid)
@@ -60,7 +62,8 @@ before do
LOGGER.debug "OpenTox ruby api wrapper: helper before filter: NO subjectid for URI: #{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}#{request.env['REQUEST_URI']}"
subjectid = ""
end
- protected!(subjectid) if AA_SERVER
+ @subjectid = subjectid
+ protected!(subjectid)
end
end
diff --git a/lib/opentox-ruby.rb b/lib/opentox-ruby.rb
index fb3803b..fc1732d 100644
--- a/lib/opentox-ruby.rb
+++ b/lib/opentox-ruby.rb
@@ -8,6 +8,7 @@ rescue LoadError
puts "Please install Openbabel with 'rake openbabel:install' in the compound component"
end
-['opentox', 'compound','dataset', 'parser','serializer', 'algorithm','model','task','validation','feature', 'rest_client_wrapper', 'authorization', 'policy', 'helper', 'to-html'].each do |lib|
+['opentox', 'compound','dataset', 'parser','serializer', 'algorithm','model','task','validation','feature',
+ 'rest_client_wrapper', 'authorization', 'policy', 'helper', 'to-html', 'error' ].each do |lib|
require lib
end
diff --git a/lib/overwrite.rb b/lib/overwrite.rb
index ffeba21..720ed77 100644
--- a/lib/overwrite.rb
+++ b/lib/overwrite.rb
@@ -1,7 +1,11 @@
# class overwrites aka monkey patches
-# hack: store sinatra in global var to make url_for and halt methods accessible
+# hack: store sinatra instance in global var $url_provider to make url_for and halt methods accessible
before {
- $sinatra = self unless $sinatra
+ raise "should not happen, url provider already differently initialized "+
+ $url_provider.request.host.to_s+" != "+self.request.host.to_s if
+ $url_provider and $url_provider.request.host!=self.request.host and
+ $url_provider.request.script_name!=self.request.script_name
+ $url_provider = self
# stupid internet explorer does not ask for text/html, add this manually
request.env['HTTP_ACCEPT'] += ";text/html" if request.env["HTTP_USER_AGENT"]=~/MSIE/
}
@@ -91,7 +95,7 @@ class OTLogger < Logger
end
def format(msg)
- pwd.ljust(18)+" :: "+msg.to_s+" :: "+trace+" :: "+($sinatra ? $sinatra.request.env['REMOTE_ADDR'] : nil).to_s
+ pwd.ljust(18)+" :: "+msg.to_s+" :: "+trace
end
def debug(msg)
diff --git a/lib/policy.rb b/lib/policy.rb
index 0ef8298..08bf6ed 100644
--- a/lib/policy.rb
+++ b/lib/policy.rb
@@ -32,6 +32,11 @@ module OpenTox
end
return true
end
+
+ # @return [Array] set of arrays affected by policies
+ def uris
+ @policies.collect{ |k,v| v.uris }.flatten.uniq
+ end
#loads a default policy template in policies instance
def load_default_policy(user, uri, group="member")
@@ -190,6 +195,11 @@ module OpenTox
@subjects[name] = Subject.new(name, type, value)
end
+ # @return [Array] set of uris affected by policy
+ def uris
+ @rules.collect{ |k,v| v.uri }.uniq
+ end
+
#rule inside a policy
class Rule
diff --git a/lib/serializer.rb b/lib/serializer.rb
index 495702a..03c2639 100644
--- a/lib/serializer.rb
+++ b/lib/serializer.rb
@@ -26,6 +26,15 @@ module OpenTox
OT.Algorithm => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
OT.Parameter => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
OT.Task => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
+ #classes for validation
+ OT.Validation => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
+ OT.ClassificationStatistics => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
+ OT.ConfusionMatrix => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
+ OT.ConfusionMatrixCell => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
+ OT.ClassValueStatistics => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
+ OT.RegressionStatistics => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
+ OT.Crossvalidation => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
+ OT.CrossvalidationInfo => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
OT.compound => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
OT.feature => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
@@ -34,6 +43,22 @@ module OpenTox
OT.values => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
OT.algorithm => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
OT.parameters => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
+ #object props for validation#
+ OT.model => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
+ OT.trainingDataset => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
+ OT.predictionFeature => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
+ OT.predictionDataset => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
+ OT.crossvalidation => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
+ OT.testTargetDataset => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
+ OT.testDataset => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
+ OT.classificationStatistics => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
+ OT.confusionMatrix => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
+ OT.confusionMatrixCell => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
+ OT.classValueStatistics => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
+ OT.regressionStatistics => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
+ OT.validation => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
+ OT.crossvalidationInfo => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
+ OT.dataset => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
DC.title => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
DC.identifier => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
@@ -47,6 +72,47 @@ module OpenTox
OT.hasStatus => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
OT.resultURI => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
OT.percentageCompleted => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ # annotation props for validation
+ OT.numUnpredicted => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.crossvalidationFold => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.numInstances => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.numWithoutClass => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.percentWithoutClass => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.percentUnpredicted => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.confusionMatrixActual => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.confusionMatrixPredicted => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.confusionMatrixValue => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.numIncorrect => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.percentCorrect => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.numCorrect => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.accuracy => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.trueNegativeRate => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.truePositiveRate => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.falseNegativeRate => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.falsePositiveRate => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.numTrueNegatives => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.numTruePositives => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.numFalseNegatives => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.numFalsePositives => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.classValue => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.precision => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.areaUnderRoc => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.weightedAreaUnderRoc => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.fMeasure => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.percentIncorrect => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.validationType => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.realRuntime => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.sampleCorrelationCoefficient => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.targetVarianceActual => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.targetVariancePredicted => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.meanAbsoluteError => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.sumSquaredError => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.rootMeanSquaredError => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.rSquare => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.stratified => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.numFolds => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.randomSeed => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.reportType => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
OT.hasSource => { RDF["type"] => [{ "type" => "uri", "value" => OWL.DatatypeProperty }] } ,
OT.value => { RDF["type"] => [{ "type" => "uri", "value" => OWL.DatatypeProperty }] } ,
@@ -121,6 +187,64 @@ module OpenTox
@object[uri] = { RDF["type"] => [{ "type" => "uri", "value" => OT.Task }] }
add_metadata uri, metadata
end
+
+ # Add a resource defined by resource_class and content
+ # (see documentation of add_content for example)
+ # @param [String] uri of resource
+ # @param [String] resource class, e.g. OT.Validation
+ # @param [Hash] content as hash
+ def add_resource(uri, resource_class, content)
+ @object[uri] = { RDF["type"] => [{ "type" => "uri", "value" => resource_class }] }
+ @@content_id = 1
+ add_content uri, content
+ end
+
+ private
+ @@content_id = 1
+
+ # Recursiv function to add content
+ # @example
+ # { DC.description => "bla",
+ # OT.similar_resources => [ "http://uri1", "http://uri2" ],
+ # OT.matrixCells =>
+ # [ { RDF.type => OT.MatrixCell, OT.cellIndex=1 OT.cellValue => "xy" },
+ # { RDF.type => OT.MatrixCell, OT.cellIndex=2 OT.cellValue => "z" } ],
+ # OT.info => { RDF.type => OT.ImportantInfo,
+ # DC.description => "blub" }
+ # }
+ # @param [String] uri
+ # @param [Hash] content as hash, uri must already have been added to @object
+ def add_content(uri, hash)
+ raise "content is no hash: "+hash.class.to_s unless hash.is_a?(Hash)
+ hash.each do |u,v|
+ if v.is_a? Hash
+ # value is again a hash, i.e. a new owl class is added
+ # first make sure type (==class) is set
+ type = v[RDF.type]
+ raise "type missing for "+u.to_s+" content:\n"+v.inspect unless type
+ raise "class unknown "+type.to_s+" (for "+u.to_s+")" unless @object.has_key?(type)
+ # create new node and add to current uri
+ genid = "_:#{type.split('#')[-1]}#{@@content_id}"
+ @@content_id += 1
+ @object[uri] = {} unless @object[uri]
+ @object[uri][u] = [{ "type" => "bnode", "value" => genid }]
+ # add content to new class
+ add_hash(genid,v)
+ elsif v.is_a? Array
+ # value is an array, i.e. a list of values with property is added
+ v.each{ |vv| add_hash( uri, { u => vv } ) }
+ else # v.is_a? String
+ # simple string value
+ @object[uri] = {} unless @object[uri]
+ @object[uri][u] = [] unless @object[uri][u]
+ raise "property unknown "+u.to_s if !@object.has_key?(u) and u!=RDF.type
+ # use << to allow different values for one property
+ @object[uri][u] << {"type" => type(v), "value" => v }
+ end
+ end
+ end
+
+ public
# Add metadata
# @param [Hash] metadata
diff --git a/lib/to-html.rb b/lib/to-html.rb
index 1bc1496..e9764ef 100755
--- a/lib/to-html.rb
+++ b/lib/to-html.rb
@@ -27,7 +27,8 @@ module OpenTox
# @return [String] html page
def self.text_to_html( text, related_links=nil, description=nil, post_params=nil )
- title = $sinatra.url_for($sinatra.request.env['PATH_INFO'], :full) if $sinatra
+ # TODO add title as parameter
+ title = nil #$sinatra.url_for($sinatra.request.env['PATH_INFO'], :full) if $sinatra
html = <
--
cgit v1.2.3
From 9d06bd3024139f2bfee4722c7536ee4ffa99fe32 Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Thu, 20 Jan 2011 11:29:53 +0100
Subject: implemented new error handling, still TODO rdf-support, replace halts
---
lib/error.rb | 60 +++++++++++++++++++++++++++---
lib/opentox-ruby.rb | 4 +-
lib/overwrite.rb | 44 +++++++++++-----------
lib/rest_client_wrapper.rb | 91 ++++++++++------------------------------------
4 files changed, 99 insertions(+), 100 deletions(-)
(limited to 'lib')
diff --git a/lib/error.rb b/lib/error.rb
index 87e1a5d..b72ce7e 100644
--- a/lib/error.rb
+++ b/lib/error.rb
@@ -1,11 +1,61 @@
-module OpenTox
- class NotFoundError < RuntimeError
-
+# adding additional fields to Exception class to format errors according to OT-API
+class Exception
+ attr_accessor :creator, :errorCause, :id
+end
+
+module OpenTox
+
+ class NotAuthorizedError < Exception
end
- class BadRequestError < RuntimeError
-
+ class NotFoundError < Exception
end
+ class BadRequestError < Exception
+ end
+
+ class RestCallError < Exception
+ attr_accessor :code, :body, :uri, :payload, :headers
+ end
+
+ class ErrorReport
+
+ # formats error according to accept-header, yaml is default
+ # ( sets content-type in response accordingly )
+ # @param [Exception] error
+ # @param |Sinatra::Request, optional] request
+ # @param [Sinatra::Response, optiona,] response, optional to set content-type
+ # @return [String] formated error
+ def self.format(error, request=nil, response=nil)
+ # sets current uri
+ error.creator = "#{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}#{request.env['REQUEST_URI']}" if request
+ accept = request.env['HTTP_ACCEPT'].to_s if request
+ case accept
+ # when /rdf/
+ # TODO add error to rdf
+ when /html/
+ response['Content-Type'] = 'text/html' if response
+ OpenTox.text_to_html error.to_yaml
+ else
+ response['Content-Type'] = 'application/x-yaml' if response
+ error.to_yaml
+ end
+ end
+
+ # trys to parse error from text
+ # @return [Exception] Exception if parsing sucessfull, nil otherwise
+ def self.parse( body )
+ begin
+ err = YAML.load(body)
+ if err and err.is_a?(Exception)
+ return err
+ else
+ return nil
+ end
+ rescue
+ return nil
+ end
+ end
+ end
end
\ No newline at end of file
diff --git a/lib/opentox-ruby.rb b/lib/opentox-ruby.rb
index fc1732d..735b845 100644
--- a/lib/opentox-ruby.rb
+++ b/lib/opentox-ruby.rb
@@ -1,4 +1,4 @@
-['rubygems', 'sinatra', 'sinatra/url_for', 'rest_client', 'yaml', 'cgi', 'spork', 'overwrite', 'environment'].each do |lib|
+['rubygems', 'sinatra', 'sinatra/url_for', 'rest_client', 'yaml', 'cgi', 'spork', 'error', 'overwrite', 'environment'].each do |lib|
require lib
end
@@ -9,6 +9,6 @@ rescue LoadError
end
['opentox', 'compound','dataset', 'parser','serializer', 'algorithm','model','task','validation','feature',
- 'rest_client_wrapper', 'authorization', 'policy', 'helper', 'to-html', 'error' ].each do |lib|
+ 'rest_client_wrapper', 'authorization', 'policy', 'helper', 'to-html' ].each do |lib|
require lib
end
diff --git a/lib/overwrite.rb b/lib/overwrite.rb
index 720ed77..2f9fabd 100644
--- a/lib/overwrite.rb
+++ b/lib/overwrite.rb
@@ -10,30 +10,30 @@ before {
request.env['HTTP_ACCEPT'] += ";text/html" if request.env["HTTP_USER_AGENT"]=~/MSIE/
}
-# handle errors manually
-# this is to return 502, when an error occurs during a rest-call (see rest_client_wrapper.rb)
-set :raise_errors, Proc.new { false }
-set :show_exceptions, false
-error do
- # try if the error is an OpenTox::Error
- if OpenTox::Error.parse(request.env['sinatra.error'].to_s)
- # if true, this error comes from rest_client_wrapper, halt with 502
- # (502 is defined in OT API as Error coming from other service)
- halt 502,request.env['sinatra.error']
+# Error handling
+# Errors are logged as error and formated according to acccept-header
+# Non OpenTox::Errors (defined in error.rb) are handled as internal error (500), stacktrace is logged
+# IMPT: set sinatra settings :show_exceptions + :raise_errors to false in config.ru, otherwise Rack::Showexceptions takes over
+error Exception do
+ error = request.env['sinatra.error']
+ # log error to logfile
+ LOGGER.error error.class.to_s+": "+error.message
+ case error.class
+ when OpenTox::BadRequestError
+ code = 400
+ when OpenTox::NotAuthorizedError
+ code = 401
+ when OpenTox::NotFoundError
+ code = 404
+ when OpenTox::RestCallError
+ code = 502
else
- # else, raise exception, this will return 500 = internal error
- raise request.env['sinatra.error']
- end
-end
-
-class Sinatra::Base
- # overwriting halt to log halts (!= 202)
- def halt(*response)
- LOGGER.error "halt "+response.first.to_s+" "+(response.size>1 ? response[1].to_s : "") if response and response.first and response.first >= 300
- # orig sinatra code:
- response = response.first if response.length == 1
- throw :halt, response
+ # (unwanted RuntimeExceptions as well as sth. like 'raise "invalid state"' is handled here)
+ code = 500
+ # log backtrace for debugging
+ LOGGER.error error.backtrace.join("\n")
end
+ halt code,OpenTox::ErrorReport.format(error,request,response)
end
class String
diff --git a/lib/rest_client_wrapper.rb b/lib/rest_client_wrapper.rb
index 920a828..5bc8072 100644
--- a/lib/rest_client_wrapper.rb
+++ b/lib/rest_client_wrapper.rb
@@ -1,32 +1,4 @@
module OpenTox
-
- #PENDING: implement ot error api, move to own file
- class Error
-
- attr_accessor :code, :body, :uri, :payload, :headers
-
- def initialize(code, body, uri, payload, headers)
- self.code = code
- self.body = body.to_s[0..1000]
- self.uri = uri
- self.payload = payload
- self.headers = headers
- end
-
- def self.parse(error_array_string)
- begin
- err = YAML.load(error_array_string)
- if err and err.is_a?(Array) and err.size>0 and err[0].is_a?(Error)
- return err
- else
- return nil
- end
- rescue
- return nil
- end
- end
-
- end
class WrapperResult < String
attr_accessor :content_type, :code
@@ -85,16 +57,16 @@ module OpenTox
# @param [optional,Hash] headers sent to the URI
# @param [optional,String] payload data sent to the URI
def self.raise_uri_error(error_msg, uri, headers=nil, payload=nil)
- raise_ot_error( "-", error_msg, uri, headers, payload )
+ raise_ot_error( nil, error_msg, nil, uri, headers, payload )
end
private
def self.execute( rest_call, uri, headers, payload=nil, waiting_task=nil, wait=true )
- raise_ot_error 400,"uri is null",uri,headers,payload unless uri
- raise_ot_error 400,"not a uri",uri,headers,payload unless uri.to_s.uri?
- raise_ot_error 400,"headers are no hash",uri,headers,payload unless headers==nil or headers.is_a?(Hash)
- raise_ot_error 400,"nil headers for post not allowed, use {}",uri,headers,payload if rest_call=="post" and headers==nil
+ raise OpenTox::BadRequestError.new "uri is null" unless uri
+ raise OpenTox::BadRequestError.new "not a uri: "+uri.to_s unless uri.to_s.uri?
+ raise OpenTox::BadRequestError.new "headers are no hash: "+headers.inspect unless headers==nil or headers.is_a?(Hash)
+ raise OpenTox::BadRequestError.new "nil headers for post not allowed, use {}" if rest_call=="post" and headers==nil
headers.each{ |k,v| headers.delete(k) if v==nil } if headers #remove keys with empty values, as this can cause problems
begin
@@ -124,18 +96,11 @@ module OpenTox
return res
rescue RestClient::RequestTimeout => ex
- raise_ot_error 408,ex.message,uri,headers,payload
+ raise_ot_error 408,ex.message,nil,ex.uri,headers,payload
+ rescue RestClient::ExceptionWithResponse => ex
+ raise_ot_error ex.http_code,ex.message,ex.http_body,uri,headers,payload
rescue => ex
- #raise ex
- #raise "'"+ex.message+"' uri: "+uri.to_s
- begin
- code = ex.http_code
- msg = ex.http_body
- rescue
- code = 500
- msg = ex.to_s
- end
- raise_ot_error code,msg,uri,headers,payload
+ raise_ot_error 500,ex.message,nil,uri,headers,payload
end
end
@@ -164,35 +129,19 @@ module OpenTox
return res
end
- def self.raise_ot_error( code, body, uri, headers, payload=nil )
-
- #build error
- causing_errors = Error.parse(body)
- if causing_errors
- error = causing_errors + [Error.new(code, "subsequent error", uri, payload, headers)]
+ def self.raise_ot_error( code, message, body, uri, headers, payload=nil )
+ error = OpenTox::RestCallError.new("REST call returned error: '"+message.to_s+"'")
+ error.code = code
+ error.uri = uri
+ error.headers = headers
+ error.payload = payload
+ parsed = OpenTox::ErrorReport.parse(body) if body
+ if parsed
+ error.errorCause = parsed
else
- error = [Error.new(code, body, uri, payload, headers)]
+ error.body = body
end
-
- #debug utility: write error to file
- error_dir = "/tmp/ot_errors"
- FileUtils.mkdir(error_dir) unless File.exist?(error_dir)
- raise "could not create error dir" unless File.exist?(error_dir) and File.directory?(error_dir)
- file_name = "error"
- time=Time.now.strftime("%m.%d.%Y-%H:%M:%S")
- count = 1
- count+=1 while File.exist?(File.join(error_dir,file_name+"_"+time+"_"+count.to_s))
- File.new(File.join(error_dir,file_name+"_"+time+"_"+count.to_s),"w").puts(body)
-
- # handle error
- # PENDING: always return yaml for now
-
- # raising OpenTox::Error
- # to handle the error yourself, put rest-call in begin, rescue block
- # if the error is not caught:
- # if we are in a task, the error is caught, logged, and task state is set to error in Task.as_task
- # if we are in a default call, the error is handled in overwrite.rb to return 502 (according to OT API)
- raise error.to_yaml
+ raise error
end
end
end
--
cgit v1.2.3
From 0e759bee80e2668e1fec7b741a4ea18015f98b84 Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Fri, 21 Jan 2011 11:52:53 +0100
Subject: simplify error handling once again, and adding http code
---
lib/error.rb | 18 +++++++++++++-----
lib/overwrite.rb | 19 +++----------------
lib/rest_client_wrapper.rb | 10 +++++-----
3 files changed, 21 insertions(+), 26 deletions(-)
(limited to 'lib')
diff --git a/lib/error.rb b/lib/error.rb
index b72ce7e..e47ad62 100644
--- a/lib/error.rb
+++ b/lib/error.rb
@@ -1,22 +1,27 @@
# adding additional fields to Exception class to format errors according to OT-API
class Exception
- attr_accessor :creator, :errorCause, :id
+ attr_accessor :creator, :errorCause, :id, :http_code
+ def http_code; 500; end
end
module OpenTox
- class NotAuthorizedError < Exception
+ class BadRequestError < Exception
+ def http_code; 400; end
end
- class NotFoundError < Exception
+ class NotAuthorizedError < Exception
+ def http_code; 401; end
end
- class BadRequestError < Exception
+ class NotFoundError < Exception
+ def http_code; 404; end
end
class RestCallError < Exception
- attr_accessor :code, :body, :uri, :payload, :headers
+ attr_accessor :rest_code, :rest_body, :rest_uri, :rest_payload, :rest_headers
+ def http_code; 502; end
end
class ErrorReport
@@ -30,6 +35,9 @@ module OpenTox
def self.format(error, request=nil, response=nil)
# sets current uri
error.creator = "#{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}#{request.env['REQUEST_URI']}" if request
+ # bit of a hack: set instance attribute in order to add it for the to_yaml conversion
+ error.http_code = error.http_code
+
accept = request.env['HTTP_ACCEPT'].to_s if request
case accept
# when /rdf/
diff --git a/lib/overwrite.rb b/lib/overwrite.rb
index 2f9fabd..83d8099 100644
--- a/lib/overwrite.rb
+++ b/lib/overwrite.rb
@@ -18,22 +18,9 @@ error Exception do
error = request.env['sinatra.error']
# log error to logfile
LOGGER.error error.class.to_s+": "+error.message
- case error.class
- when OpenTox::BadRequestError
- code = 400
- when OpenTox::NotAuthorizedError
- code = 401
- when OpenTox::NotFoundError
- code = 404
- when OpenTox::RestCallError
- code = 502
- else
- # (unwanted RuntimeExceptions as well as sth. like 'raise "invalid state"' is handled here)
- code = 500
- # log backtrace for debugging
- LOGGER.error error.backtrace.join("\n")
- end
- halt code,OpenTox::ErrorReport.format(error,request,response)
+ # log backtrace only if code is 500 -> unwanted (Runtime)Exceptions and internal errors (see error.rb)
+ LOGGER.error error.backtrace.join("\n") if error.http_code==500
+ halt error.http_code,OpenTox::ErrorReport.format(error,request,response)
end
class String
diff --git a/lib/rest_client_wrapper.rb b/lib/rest_client_wrapper.rb
index 5bc8072..3d7b72e 100644
--- a/lib/rest_client_wrapper.rb
+++ b/lib/rest_client_wrapper.rb
@@ -131,15 +131,15 @@ module OpenTox
def self.raise_ot_error( code, message, body, uri, headers, payload=nil )
error = OpenTox::RestCallError.new("REST call returned error: '"+message.to_s+"'")
- error.code = code
- error.uri = uri
- error.headers = headers
- error.payload = payload
+ error.rest_code = code
+ error.rest_uri = uri
+ error.rest_headers = headers
+ error.rest_payload = payload
parsed = OpenTox::ErrorReport.parse(body) if body
if parsed
error.errorCause = parsed
else
- error.body = body
+ error.rest_body = body
end
raise error
end
--
cgit v1.2.3
From 59dba52a30de35da0122cd6c25777573faa5ffc3 Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Mon, 24 Jan 2011 17:19:56 +0100
Subject: fix error handling
---
lib/error.rb | 67 ++++++++++++++++--------------------------
lib/overwrite.rb | 18 ++++++++++--
lib/rest_client_wrapper.rb | 72 +++++++++++++++++++++++++++++-----------------
lib/task.rb | 36 +++++++++++------------
4 files changed, 102 insertions(+), 91 deletions(-)
(limited to 'lib')
diff --git a/lib/error.rb b/lib/error.rb
index e47ad62..8a57bd0 100644
--- a/lib/error.rb
+++ b/lib/error.rb
@@ -1,69 +1,52 @@
# adding additional fields to Exception class to format errors according to OT-API
class Exception
- attr_accessor :creator, :errorCause, :id, :http_code
+ attr_accessor :errorCause
def http_code; 500; end
end
module OpenTox
- class BadRequestError < Exception
+ class BadRequestError < RuntimeError
def http_code; 400; end
end
- class NotAuthorizedError < Exception
+ class NotAuthorizedError < RuntimeError
def http_code; 401; end
end
- class NotFoundError < Exception
+ class NotFoundError < RuntimeError
def http_code; 404; end
end
- class RestCallError < Exception
- attr_accessor :rest_code, :rest_body, :rest_uri, :rest_payload, :rest_headers
+ class RestCallError < RuntimeError
+ attr_accessor :rest_params
def http_code; 502; end
end
class ErrorReport
- # formats error according to accept-header, yaml is default
- # ( sets content-type in response accordingly )
- # @param [Exception] error
- # @param |Sinatra::Request, optional] request
- # @param [Sinatra::Response, optiona,] response, optional to set content-type
- # @return [String] formated error
- def self.format(error, request=nil, response=nil)
- # sets current uri
- error.creator = "#{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}#{request.env['REQUEST_URI']}" if request
- # bit of a hack: set instance attribute in order to add it for the to_yaml conversion
- error.http_code = error.http_code
-
- accept = request.env['HTTP_ACCEPT'].to_s if request
- case accept
- # when /rdf/
- # TODO add error to rdf
- when /html/
- response['Content-Type'] = 'text/html' if response
- OpenTox.text_to_html error.to_yaml
- else
- response['Content-Type'] = 'application/x-yaml' if response
- error.to_yaml
- end
+ # TODO replace params with URIs (errorCause -> OT.errorCause)
+ attr_reader :message, :actor, :errorCause, :http_code, :errorDetails, :errorType
+
+ # creates a error report object, from an ruby-exception object
+ # @param [Exception] error
+ # @param [String] actor, URI of the call that cause the error
+ def initialize( error, actor )
+ @http_code = error.http_code
+ @errorType = error.class.to_s
+ @message = error.message
+ @actor = actor
+ @errorCause = error.errorCause if error.errorCause
+ @rest_params = error.rest_params if error.is_a?(OpenTox::RestCallError) and error.rest_params
+ end
+
+ def self.from_rdf(rdf)
+ raise "not yet implemented"
end
- # trys to parse error from text
- # @return [Exception] Exception if parsing sucessfull, nil otherwise
- def self.parse( body )
- begin
- err = YAML.load(body)
- if err and err.is_a?(Exception)
- return err
- else
- return nil
- end
- rescue
- return nil
- end
+ def self.to_rdf
+ raise "not yet implemented"
end
end
end
\ No newline at end of file
diff --git a/lib/overwrite.rb b/lib/overwrite.rb
index 83d8099..4fa0829 100644
--- a/lib/overwrite.rb
+++ b/lib/overwrite.rb
@@ -19,8 +19,22 @@ error Exception do
# log error to logfile
LOGGER.error error.class.to_s+": "+error.message
# log backtrace only if code is 500 -> unwanted (Runtime)Exceptions and internal errors (see error.rb)
- LOGGER.error error.backtrace.join("\n") if error.http_code==500
- halt error.http_code,OpenTox::ErrorReport.format(error,request,response)
+ LOGGER.error ":\n"+error.backtrace.join("\n") if error.http_code==500
+
+ actor = "#{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}#{request.env['REQUEST_URI']}"
+ rep = OpenTox::ErrorReport.new(error, actor)
+
+ case request.env['HTTP_ACCEPT']
+ when /rdf/
+ content_type 'application/rdf+xml'
+ halt error.http_code,rep.to_xml
+ when /html/
+ content_type 'text/html'
+ halt error.http_code,(OpenTox.text_to_html rep.to_yaml)
+ else
+ content_type 'application/x-yaml'
+ halt error.http_code,rep.to_yaml
+ end
end
class String
diff --git a/lib/rest_client_wrapper.rb b/lib/rest_client_wrapper.rb
index 3d7b72e..7c2d719 100644
--- a/lib/rest_client_wrapper.rb
+++ b/lib/rest_client_wrapper.rb
@@ -50,16 +50,6 @@ module OpenTox
execute( "delete", uri, headers, nil)
end
- # raises an Error message (rescued in overwrite.rb -> halt 502)
- # usage: if the return value of a call is invalid
- # @param [String] error_msg the error message
- # @param [String] uri destination URI that is responsible for the error
- # @param [optional,Hash] headers sent to the URI
- # @param [optional,String] payload data sent to the URI
- def self.raise_uri_error(error_msg, uri, headers=nil, payload=nil)
- raise_ot_error( nil, error_msg, nil, uri, headers, payload )
- end
-
private
def self.execute( rest_call, uri, headers, payload=nil, waiting_task=nil, wait=true )
@@ -70,7 +60,7 @@ module OpenTox
headers.each{ |k,v| headers.delete(k) if v==nil } if headers #remove keys with empty values, as this can cause problems
begin
- #LOGGER.debug "RestCall: "+rest_call.to_s+" "+uri.to_s+" "+headers.inspect
+ #LOGGER.debug "RestCall: "+rest_call.to_s+" "+uri.to_s+" "+headers.inspect+" "+payload.inspect
resource = RestClient::Resource.new(uri,{:timeout => 60})
if payload
result = resource.send(rest_call, payload, headers)
@@ -86,6 +76,7 @@ module OpenTox
raise "content-type not set" unless res.content_type
res.code = result.code
+ #LOGGER.debug "RestCall result: "+res.to_s+" "+res.code.to_s+" "+res.content_type.to_s
# TODO: Ambit returns task representation with 200 instead of result URI
return res if res.code==200 || !wait
@@ -96,11 +87,16 @@ module OpenTox
return res
rescue RestClient::RequestTimeout => ex
- raise_ot_error 408,ex.message,nil,ex.uri,headers,payload
+ received_error ex.message, 408, nil, {:rest_uri => uri, :headers => headers}
rescue RestClient::ExceptionWithResponse => ex
- raise_ot_error ex.http_code,ex.message,ex.http_body,uri,headers,payload
+ # error comming from a different webservice,
+ received_error ex.http_body, ex.http_code, ex.response.net_http_res.content_type, {:rest_uri => uri, :headers => headers}
+ rescue OpenTox::RestCallError => ex
+ # already a rest-error, probably comes from wait_for_task, just pass through
+ raise ex
rescue => ex
- raise_ot_error 500,ex.message,nil,uri,headers,payload
+ # some internal error occuring in rest_client_wrapper, just pass through
+ raise ex
end
end
@@ -121,27 +117,49 @@ module OpenTox
LOGGER.debug "result is a task '"+task.uri.to_s+"', wait for completion"
task.wait_for_completion waiting_task
- raise task.description unless task.completed? # maybe task was cancelled / error
-
+ unless task.completed? # maybe task was cancelled / error
+ if task.errorReport
+ received_error task.errorReport, task.http_code, nil, {:rest_uri => task.uri, :rest_code => task.http_code}
+ else
+ raise "task status: '"+task.status.to_s+"' but errorReport nil"
+ end
+ end
+
res = WrapperResult.new task.result_uri
res.code = task.http_code
res.content_type = "text/uri-list"
return res
end
- def self.raise_ot_error( code, message, body, uri, headers, payload=nil )
- error = OpenTox::RestCallError.new("REST call returned error: '"+message.to_s+"'")
- error.rest_code = code
- error.rest_uri = uri
- error.rest_headers = headers
- error.rest_payload = payload
- parsed = OpenTox::ErrorReport.parse(body) if body
- if parsed
- error.errorCause = parsed
+ def self.received_error( body, code, content_type=nil, params=nil )
+
+ # try to parse body
+ report = nil
+ if body.is_a?(OpenTox::ErrorReport)
+ report = body
+ else
+ case content_type
+ when /yaml/
+ report = YAML.load(body)
+ when /rdf/
+ report = OpenTox::ErrorReport.from_rdf(body)
+ end
+ end
+
+ unless report
+ # parsing was not successfull
+ # raise 'plain' RestCallError
+ err = OpenTox::RestCallError.new("REST call returned error: '"+body.to_s+"'")
+ err.rest_params = params
+ raise err
else
- error.rest_body = body
+ # parsing sucessfull
+ # raise RestCallError with parsed report as error cause
+ err = OpenTox::RestCallError.new("REST call subsequent error")
+ err.errorCause = report
+ err.rest_params = params
+ raise err
end
- raise error
end
end
end
diff --git a/lib/task.rb b/lib/task.rb
index d701c82..06d290f 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -56,26 +56,17 @@ module OpenTox
#raise "Server too busy to start a new task"
end
-
task_pid = Spork.spork(:logger => LOGGER) do
LOGGER.debug "Task #{task.uri} started #{Time.now}"
-
begin
- result = catch(:halt) do
- yield task
- end
- # catching halt, set task state to error
- if result && result.is_a?(Array) && result.size==2 && result[0]>202
- LOGGER.error "task was halted: "+result.inspect
- task.error(result[1])
- return
- end
+ result = yield task
LOGGER.debug "Task #{task.uri} done #{Time.now} -> "+result.to_s
task.completed(result)
- rescue => ex
- LOGGER.error "task failed: "+ex.message
- LOGGER.error ": "+ex.backtrace.join("\n")
- task.error(ex.message)
+ rescue => error
+ LOGGER.error "task failed: "+error.class.to_s+": "+error.message
+ # log backtrace only if code is 500 -> unwanted (Runtime)Exceptions and internal errors (see error.rb)
+ LOGGER.error ":\n"+error.backtrace.join("\n") if error.http_code==500
+ task.error(OpenTox::ErrorReport.new(error, creator))
end
end
task.pid = task_pid
@@ -127,6 +118,10 @@ module OpenTox
@metadata[DC.description]
end
+ def errorReport
+ @metadata[OT.errorReport]
+ end
+
def cancel
RestClientWrapper.put(File.join(@uri,'Cancelled'))
load_metadata
@@ -137,8 +132,9 @@ module OpenTox
load_metadata
end
- def error(description)
- RestClientWrapper.put(File.join(@uri,'Error'),{:description => description.to_s[0..2000]})
+ def error(error_report)
+ raise "no error report" unless error_report.is_a?(OpenTox::ErrorReport)
+ RestClientWrapper.put(File.join(@uri,'Error'),{:errorReport => error_report.to_yaml})
load_metadata
end
@@ -236,7 +232,7 @@ module OpenTox
end
end
- LOGGER.debug "Task '"+@metadata[OT.hasStatus]+"': "+@uri.to_s+", Result: "+@metadata[OT.resultURI].to_s
+ LOGGER.debug "Task '"+@metadata[OT.hasStatus].to_s+"': "+@uri.to_s+", Result: "+@metadata[OT.resultURI].to_s
end
# updates percentageCompleted value (can only be increased)
@@ -250,7 +246,7 @@ module OpenTox
load_metadata
end
end
-
+
private
def check_state
begin
@@ -265,7 +261,7 @@ module OpenTox
"'" unless @metadata[OT.resultURI] and @metadata[OT.resultURI].to_s.uri?
end
rescue => ex
- RestClientWrapper.raise_uri_error(ex.message, @uri)
+ raise OpenTox::BadRequestError.new ex.message+" (task-uri:"+@uri+")"
end
end
--
cgit v1.2.3
From 8cfe8ad608e59d3536cd5403a70743a51cb901ee Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Mon, 24 Jan 2011 19:35:36 +0100
Subject: fix task to rdf
---
lib/error.rb | 18 ++++++++++++++++--
lib/overwrite.rb | 2 +-
lib/serializer.rb | 11 ++++++++---
lib/task.rb | 7 +++++++
4 files changed, 32 insertions(+), 6 deletions(-)
(limited to 'lib')
diff --git a/lib/error.rb b/lib/error.rb
index 8a57bd0..d3fd19b 100644
--- a/lib/error.rb
+++ b/lib/error.rb
@@ -40,13 +40,27 @@ module OpenTox
@errorCause = error.errorCause if error.errorCause
@rest_params = error.rest_params if error.is_a?(OpenTox::RestCallError) and error.rest_params
end
+
+ def rdf_content()
+ c = {
+ RDF.type => OT.ErrorReport,
+ OT.statusCode => @http_code,
+ OT.message => @message,
+ OT.actor => @actor,
+ OT.errorCode => @errorType,
+ }
+ c[OT.errorCause] = @errorCause.rdf_content if @errorCause
+ c
+ end
def self.from_rdf(rdf)
raise "not yet implemented"
end
- def self.to_rdf
- raise "not yet implemented"
+ def to_rdfxml
+ s = Serializer::Owl.new
+ s.add_resource(CONFIG[:services]["opentox-task"]+"/tmpId/ErrorReport/tmpId", OT.errorReport, rdf_content)
+ s.to_rdfxml
end
end
end
\ No newline at end of file
diff --git a/lib/overwrite.rb b/lib/overwrite.rb
index 4fa0829..e52618c 100644
--- a/lib/overwrite.rb
+++ b/lib/overwrite.rb
@@ -27,7 +27,7 @@ error Exception do
case request.env['HTTP_ACCEPT']
when /rdf/
content_type 'application/rdf+xml'
- halt error.http_code,rep.to_xml
+ halt error.http_code,rep.to_rdfxml
when /html/
content_type 'text/html'
halt error.http_code,(OpenTox.text_to_html rep.to_yaml)
diff --git a/lib/serializer.rb b/lib/serializer.rb
index 03c2639..44b4414 100644
--- a/lib/serializer.rb
+++ b/lib/serializer.rb
@@ -14,7 +14,7 @@ module OpenTox
def initialize
@object = {
- # this should come from opntox.owl
+ # this should come from opentox.owl
OT.Compound => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
OT.Feature => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
OT.NominalFeature => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
@@ -35,6 +35,7 @@ module OpenTox
OT.RegressionStatistics => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
OT.Crossvalidation => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
OT.CrossvalidationInfo => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
+ OT.ErrorReport => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
OT.compound => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
OT.feature => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
@@ -113,6 +114,10 @@ module OpenTox
OT.numFolds => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
OT.randomSeed => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
OT.reportType => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.message => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.statusCode => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.actor => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.errorCode => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
OT.hasSource => { RDF["type"] => [{ "type" => "uri", "value" => OWL.DatatypeProperty }] } ,
OT.value => { RDF["type"] => [{ "type" => "uri", "value" => OWL.DatatypeProperty }] } ,
@@ -229,10 +234,10 @@ module OpenTox
@object[uri] = {} unless @object[uri]
@object[uri][u] = [{ "type" => "bnode", "value" => genid }]
# add content to new class
- add_hash(genid,v)
+ add_content(genid,v)
elsif v.is_a? Array
# value is an array, i.e. a list of values with property is added
- v.each{ |vv| add_hash( uri, { u => vv } ) }
+ v.each{ |vv| add_content( uri, { u => vv } ) }
else # v.is_a? String
# simple string value
@object[uri] = {} unless @object[uri]
diff --git a/lib/task.rb b/lib/task.rb
index 06d290f..4d1ee90 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -102,7 +102,9 @@ module OpenTox
def to_rdfxml
s = Serializer::Owl.new
+ @metadata[OT.errorReport] = @uri+"/ErrorReport/tmpId" if @error_report
s.add_task(@uri,@metadata)
+ s.add_resource(@uri+"/ErrorReport/tmpId", OT.errorReport, @error_report.rdf_content) if @error_report
s.to_rdfxml
end
@@ -138,6 +140,11 @@ module OpenTox
load_metadata
end
+ # not stored just for to_rdf
+ def add_error_report( error_report )
+ @error_report = error_report
+ end
+
def pid=(pid)
RestClientWrapper.put(File.join(@uri,'pid'), {:pid => pid})
end
--
cgit v1.2.3
From b8e919f933b4137043c6facf56b5ad20249fdd2b Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Tue, 25 Jan 2011 12:50:41 +0100
Subject: add backtrace to error if configured in .yaml config
---
lib/error.rb | 9 +++++++++
1 file changed, 9 insertions(+)
(limited to 'lib')
diff --git a/lib/error.rb b/lib/error.rb
index d3fd19b..e5c460d 100644
--- a/lib/error.rb
+++ b/lib/error.rb
@@ -39,6 +39,15 @@ module OpenTox
@actor = actor
@errorCause = error.errorCause if error.errorCause
@rest_params = error.rest_params if error.is_a?(OpenTox::RestCallError) and error.rest_params
+ @backtrace = error.backtrace.join("\n") if CONFIG[:backtrace]
+ end
+
+ # overwrite sorting to make easier readable
+ def to_yaml_properties
+ p = super
+ p = ( p - ["@backtrace"]) + ["@backtrace"] if @backtrace
+ p = ( p - ["@errorCause"]) + ["@errorCause"] if @errorCause
+ p
end
def rdf_content()
--
cgit v1.2.3
From bbb753ffe7a428dc4bdfef59fdd703d077aefbfb Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Tue, 25 Jan 2011 14:18:24 +0100
Subject: do not catch error in model.run
---
lib/model.rb | 7 +------
1 file changed, 1 insertion(+), 6 deletions(-)
(limited to 'lib')
diff --git a/lib/model.rb b/lib/model.rb
index e95c78c..efa273b 100644
--- a/lib/model.rb
+++ b/lib/model.rb
@@ -14,12 +14,7 @@ module OpenTox
else
accept = 'application/rdf+xml'
end
- begin
- RestClientWrapper.post(@uri,{:accept => accept},params,waiting_task).to_s
- rescue => e
- LOGGER.error "Failed to run #{@uri} with #{params.inspect} (#{e.inspect})"
- raise "Failed to run #{@uri} with #{params.inspect}"
- end
+ RestClientWrapper.post(@uri,{:accept => accept},params,waiting_task).to_s
end
# Generic OpenTox model class for all API compliant services
--
cgit v1.2.3
From ddcf8597a13ea6f03c697c78d224376ff36c7ea3 Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Tue, 25 Jan 2011 16:20:28 +0100
Subject: replace halt with raise NotAuthorized
---
lib/helper.rb | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
(limited to 'lib')
diff --git a/lib/helper.rb b/lib/helper.rb
index bb0279e..ff5e908 100644
--- a/lib/helper.rb
+++ b/lib/helper.rb
@@ -9,11 +9,10 @@ helpers do
end
elsif !env["session"] && subjectid
unless authorized?(subjectid)
- throw(:halt, [401, "Not authorized.\n"])
- redirect back
+ raise OpenTox::NotAuthorizedError.new "Not authorized"
end
else
- throw(:halt, [401, "Not authorized.\n"]) unless authorized?(subjectid)
+ raise OpenTox::NotAuthorizedError.new "Not authorized" unless authorized?(subjectid)
end
end
--
cgit v1.2.3
From ce93b07bb253df3c548c59bacc869839aa78bb4c Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Wed, 26 Jan 2011 15:54:05 +0100
Subject: add whitlisting concept for A&A, some minor modifications
---
lib/authorization.rb | 42 +++++++++++++++++++++++++++++++++++++++++-
lib/error.rb | 13 ++++++++++++-
lib/helper.rb | 12 +-----------
lib/model.rb | 10 +++++-----
4 files changed, 59 insertions(+), 18 deletions(-)
(limited to 'lib')
diff --git a/lib/authorization.rb b/lib/authorization.rb
index 5bc690a..c6f39c1 100644
--- a/lib/authorization.rb
+++ b/lib/authorization.rb
@@ -322,7 +322,47 @@ module OpenTox
alias :token_valid? :is_token_valid
end
- end
+ #Check Authorization for URI with method and subjectid.
+ def self.authorized?(uri, request_method, subjectid)
+ return true if OpenTox::Authorization.whitelisted?(uri, request_method)
+ if CONFIG[:authorization][:authorize_request].include?(request_method)
+ ret = OpenTox::Authorization.authorize(uri, request_method, subjectid)
+ LOGGER.debug "OpenTox helpers OpenTox::Authorization authorized? method: #{request_method} , URI: #{uri}, subjectid: #{subjectid} with return >>#{ret}<<"
+ return ret
+ end
+ if CONFIG[:authorization][:authenticate_request].include?(request_method)
+ return true if OpenTox::Authorization.is_token_valid(subjectid)
+ end
+ LOGGER.debug "Not authorized for: #{uri} with Method: #{request_method} with Token #{subjectid}"
+ return false
+ end
+
+ @@whitelist = {}
+
+ private
+ def self.whitelisted?(uri, request_method)
+ return false unless @@whitelist[request_method]
+ @@whitelist[request_method].each do |r|
+ return true if r.match(uri)
+ end
+ return false
+ end
+
+ public
+ def self.whitelist(uri_match, request_method)
+ if uri_match.is_a?(Regexp)
+ uri_regex = uri_match
+ elsif uri_match.is_a?(String)
+ uri_regex = Regexp.new("^"+uri_match+"$")
+ else
+ raise "uri-match param is neither string(->exact uri match) nor regexp: "+uri_match.class
+ end
+ LOGGER.info("whitelisted "+request_method+" "+uri_regex.to_s)
+ @@whitelist[request_method] = [] unless @@whitelist[request_method]
+ @@whitelist[request_method] << uri_regex
+ end
+
+ end
end
diff --git a/lib/error.rb b/lib/error.rb
index e5c460d..8c666f3 100644
--- a/lib/error.rb
+++ b/lib/error.rb
@@ -39,7 +39,7 @@ module OpenTox
@actor = actor
@errorCause = error.errorCause if error.errorCause
@rest_params = error.rest_params if error.is_a?(OpenTox::RestCallError) and error.rest_params
- @backtrace = error.backtrace.join("\n") if CONFIG[:backtrace]
+ @backtrace = error.backtrace.short_backtrace if CONFIG[:backtrace]
end
# overwrite sorting to make easier readable
@@ -72,4 +72,15 @@ module OpenTox
s.to_rdfxml
end
end
+end
+
+class Array
+ def short_backtrace
+ short = []
+ each do |c|
+ break if c =~ /sinatra\/base/
+ short << c
+ end
+ short.join("\n")
+ end
end
\ No newline at end of file
diff --git a/lib/helper.rb b/lib/helper.rb
index e82c8fb..afeeb43 100644
--- a/lib/helper.rb
+++ b/lib/helper.rb
@@ -16,22 +16,12 @@ helpers do
end
end
-
#Check Authorization for URI with method and subjectid.
def authorized?(subjectid)
request_method = request.env['REQUEST_METHOD']
uri = clean_uri("#{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}#{request.env['REQUEST_URI']}")
request_method = "GET" if request_method == "POST" && uri =~ /\/model\/\d+\/?$/
- if CONFIG[:authorization][:authorize_request].include?(request_method)
- ret = OpenTox::Authorization.authorize(uri, request_method, subjectid)
- LOGGER.debug "OpenTox helpers OpenTox::Authorization authorized? method: #{request_method} , URI: #{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}#{request.env['REQUEST_URI']}, subjectid: #{subjectid} with return >>#{ret}<<"
- return ret
- end
- if CONFIG[:authorization][:authenticate_request].include?(request_method)
- return true if OpenTox::Authorization.is_token_valid(subjectid)
- end
- LOGGER.debug "Not authorized for: #{uri} with Method: #{request.env['REQUEST_METHOD']}/#{request_method} with Token #{subjectid}"
- return false
+ return OpenTox::Authorization.authorized?(uri, request_method, subjectid)
end
#cleans URI from querystring and file-extension. Sets port 80 to emptystring
diff --git a/lib/model.rb b/lib/model.rb
index 85be1b5..741eea6 100644
--- a/lib/model.rb
+++ b/lib/model.rb
@@ -24,9 +24,9 @@ module OpenTox
# Find Generic Opentox Model via URI, and loads metadata
# @param [String] uri Model URI
# @return [OpenTox::Model::Generic] Model instance, nil if model was not found
- def self.find(uri)
+ def self.find(uri,subjectid=nil)
model = Generic.new(uri)
- model.load_metadata
+ model.load_metadata(subjectid)
if model.metadata==nil or model.metadata.size==0
nil
else
@@ -36,10 +36,10 @@ module OpenTox
# provides feature type, possible types are "regression" or "classification"
# @return [String] feature type, "unknown" if type could not be estimated
- def feature_type
+ def feature_type(subjectid=nil)
# dynamically perform restcalls if necessary
- load_metadata if @metadata==nil or @metadata.size==0 or (@metadata.size==1 && @metadata.values[0]==@uri)
- @dependentVariable = OpenTox::Feature.find( @metadata[OT.dependentVariables] ) unless @dependentVariable
+ load_metadata(subjectid) if @metadata==nil or @metadata.size==0 or (@metadata.size==1 && @metadata.values[0]==@uri)
+ @dependentVariable = OpenTox::Feature.find( @metadata[OT.dependentVariables],subjectid ) unless @dependentVariable
[@dependentVariable.feature_type, @metadata[OT.isA], @metadata[DC.title], @uri].each do |type|
case type
--
cgit v1.2.3
From 53a6d76d44543ba8109bc6fa1a609e30dd7e91ff Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Wed, 26 Jan 2011 16:08:57 +0100
Subject: documented new autorization function
---
lib/authorization.rb | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
(limited to 'lib')
diff --git a/lib/authorization.rb b/lib/authorization.rb
index c6f39c1..6a8a174 100644
--- a/lib/authorization.rb
+++ b/lib/authorization.rb
@@ -322,7 +322,11 @@ module OpenTox
alias :token_valid? :is_token_valid
end
- #Check Authorization for URI with method and subjectid.
+ # Check Authorization for a resource (identified via URI) with method and subjectid.
+ # @param [String] uri
+ # @param [String] request_method, should be GET, POST, PUT, DELETE
+ # @param [String] subjectid
+ # @return [Boolean] true if access granted, else otherwise
def self.authorized?(uri, request_method, subjectid)
return true if OpenTox::Authorization.whitelisted?(uri, request_method)
if CONFIG[:authorization][:authorize_request].include?(request_method)
@@ -349,6 +353,9 @@ module OpenTox
end
public
+ # adds uri/regexp-for-matching-uri to the whitelist for a request-method (i.e. access will be granted without cheking the A&A service)
+ # @param [String or Regexp] uri_match if string match must be ecaxt
+ # @param [String] request_method, must be GET, POST, PUT, DELETE
def self.whitelist(uri_match, request_method)
if uri_match.is_a?(Regexp)
uri_regex = uri_match
@@ -357,7 +364,7 @@ module OpenTox
else
raise "uri-match param is neither string(->exact uri match) nor regexp: "+uri_match.class
end
- LOGGER.info("whitelisted "+request_method+" "+uri_regex.to_s)
+ LOGGER.info("whitelisted "+request_method.to_s+" "+uri_regex.to_s)
@@whitelist[request_method] = [] unless @@whitelist[request_method]
@@whitelist[request_method] << uri_regex
end
--
cgit v1.2.3
From 171ab814d15b9504ef9892ba5f194de8bc019f46 Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Wed, 26 Jan 2011 16:16:09 +0100
Subject: minor fix
---
lib/authorization.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/authorization.rb b/lib/authorization.rb
index 6a8a174..a6253b7 100644
--- a/lib/authorization.rb
+++ b/lib/authorization.rb
@@ -362,7 +362,7 @@ module OpenTox
elsif uri_match.is_a?(String)
uri_regex = Regexp.new("^"+uri_match+"$")
else
- raise "uri-match param is neither string(->exact uri match) nor regexp: "+uri_match.class
+ raise "uri-match param is neither string(->exact uri match) nor regexp: "+uri_match.class.to_s
end
LOGGER.info("whitelisted "+request_method.to_s+" "+uri_regex.to_s)
@@whitelist[request_method] = [] unless @@whitelist[request_method]
--
cgit v1.2.3
From e1a067953dd9139b01aaebe42ff158a944240540 Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Fri, 28 Jan 2011 12:20:08 +0100
Subject: extend whitelisting, get feature_type from algorithm
---
lib/algorithm.rb | 5 +++--
lib/authorization.rb | 18 +++++++++++++-----
lib/dataset.rb | 1 +
lib/feature.rb | 3 ++-
lib/model.rb | 24 ++++++++++++++++--------
lib/task.rb | 20 +++++++++++++++++---
6 files changed, 52 insertions(+), 19 deletions(-)
(limited to 'lib')
diff --git a/lib/algorithm.rb b/lib/algorithm.rb
index 58a2640..ee3109c 100644
--- a/lib/algorithm.rb
+++ b/lib/algorithm.rb
@@ -34,9 +34,10 @@ module OpenTox
# Find Generic Opentox Algorithm via URI, and loads metadata
# @param [String] uri Algorithm URI
# @return [OpenTox::Algorithm::Generic] Algorithm instance, nil if alogrithm was not found
- def self.find(uri)
+ def self.find(uri, subjectid)
+ return nil unless uri
alg = Generic.new(uri)
- alg.load_metadata
+ alg.load_metadata( subjectid )
if alg.metadata==nil or alg.metadata.size==0
nil
else
diff --git a/lib/authorization.rb b/lib/authorization.rb
index a6253b7..1573da3 100644
--- a/lib/authorization.rb
+++ b/lib/authorization.rb
@@ -328,7 +328,10 @@ module OpenTox
# @param [String] subjectid
# @return [Boolean] true if access granted, else otherwise
def self.authorized?(uri, request_method, subjectid)
- return true if OpenTox::Authorization.whitelisted?(uri, request_method)
+ if OpenTox::Authorization.whitelisted?(uri, request_method)
+ LOGGER.debug "whitelisted! "+uri.to_s
+ return true
+ end
if CONFIG[:authorization][:authorize_request].include?(request_method)
ret = OpenTox::Authorization.authorize(uri, request_method, subjectid)
LOGGER.debug "OpenTox helpers OpenTox::Authorization authorized? method: #{request_method} , URI: #{uri}, subjectid: #{subjectid} with return >>#{ret}<<"
@@ -346,8 +349,12 @@ module OpenTox
private
def self.whitelisted?(uri, request_method)
return false unless @@whitelist[request_method]
- @@whitelist[request_method].each do |r|
- return true if r.match(uri)
+ @@whitelist[request_method].each do |regexp,invert|
+ if invert
+ return true if !regexp.match(uri)
+ else
+ return true if regexp.match(uri)
+ end
end
return false
end
@@ -356,7 +363,8 @@ module OpenTox
# adds uri/regexp-for-matching-uri to the whitelist for a request-method (i.e. access will be granted without cheking the A&A service)
# @param [String or Regexp] uri_match if string match must be ecaxt
# @param [String] request_method, must be GET, POST, PUT, DELETE
- def self.whitelist(uri_match, request_method)
+ # @param [Boolean,optional] invert, set to true if you want to whitelist everything that does not match (careful!)
+ def self.whitelist(uri_match, request_method, invert=false)
if uri_match.is_a?(Regexp)
uri_regex = uri_match
elsif uri_match.is_a?(String)
@@ -366,7 +374,7 @@ module OpenTox
end
LOGGER.info("whitelisted "+request_method.to_s+" "+uri_regex.to_s)
@@whitelist[request_method] = [] unless @@whitelist[request_method]
- @@whitelist[request_method] << uri_regex
+ @@whitelist[request_method] << [ uri_regex, invert ]
end
end
diff --git a/lib/dataset.rb b/lib/dataset.rb
index 640e3da..9c20968 100644
--- a/lib/dataset.rb
+++ b/lib/dataset.rb
@@ -51,6 +51,7 @@ module OpenTox
# @param [String] uri Dataset URI
# @return [OpenTox::Dataset] Dataset object with all data
def self.find(uri, subjectid=nil)
+ return nil unless uri
dataset = Dataset.new(uri, subjectid)
dataset.load_all(subjectid)
dataset
diff --git a/lib/feature.rb b/lib/feature.rb
index 28ac0c5..be063dd 100644
--- a/lib/feature.rb
+++ b/lib/feature.rb
@@ -3,7 +3,8 @@ module OpenTox
include OpenTox
def self.find(uri, subjectid=nil)
- feature = Feature.new uri
+ return nil unless uri
+ feature = Feature.new uri
if (CONFIG[:yaml_hosts].include?(URI.parse(uri).host))
feature.add_metadata YAML.load(RestClientWrapper.get(uri,{:accept => "application/x-yaml", :subjectid => subjectid}))
else
diff --git a/lib/model.rb b/lib/model.rb
index 741eea6..80d7ec4 100644
--- a/lib/model.rb
+++ b/lib/model.rb
@@ -8,13 +8,16 @@ module OpenTox
# @param [Hash] params Parameters for OpenTox model
# @param [optional,OpenTox::Task] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
# @return [text/uri-list] Task or resource URI
- def run( params, waiting_task=nil )
- if CONFIG[:yaml_hosts].include?(URI.parse(@uri).host)
- accept = 'application/x-yaml'
- else
- accept = 'application/rdf+xml'
+ def run( params, accept_header=nil, waiting_task=nil )
+ unless accept_header
+ if CONFIG[:yaml_hosts].include?(URI.parse(@uri).host)
+ accept_header = 'application/x-yaml'
+ else
+ accept_header = 'application/rdf+xml'
+ end
end
- RestClientWrapper.post(@uri,{:accept => accept},params,waiting_task).to_s
+ LOGGER.info "running model "+@uri.to_s+", params: "+params.inspect+", accept: "+accept_header.to_s
+ RestClientWrapper.post(@uri,{:accept => accept_header},params,waiting_task).to_s
end
# Generic OpenTox model class for all API compliant services
@@ -25,6 +28,7 @@ module OpenTox
# @param [String] uri Model URI
# @return [OpenTox::Model::Generic] Model instance, nil if model was not found
def self.find(uri,subjectid=nil)
+ return nil unless uri
model = Generic.new(uri)
model.load_metadata(subjectid)
if model.metadata==nil or model.metadata.size==0
@@ -39,9 +43,12 @@ module OpenTox
def feature_type(subjectid=nil)
# dynamically perform restcalls if necessary
load_metadata(subjectid) if @metadata==nil or @metadata.size==0 or (@metadata.size==1 && @metadata.values[0]==@uri)
+
+ @algorithm = OpenTox::Algorithm::Generic.find(@metadata[OT.algorithm], subjectid) unless @algorithm
+ algorithm_title = @algorithm ? @algorithm.metadata[DC.title] : nil
@dependentVariable = OpenTox::Feature.find( @metadata[OT.dependentVariables],subjectid ) unless @dependentVariable
- [@dependentVariable.feature_type, @metadata[OT.isA], @metadata[DC.title], @uri].each do |type|
+ [@dependentVariable.feature_type, @metadata[OT.isA], @metadata[DC.title], @uri, algorithm_title].each do |type|
case type
when /(?i)classification/
return "classification"
@@ -49,7 +56,8 @@ module OpenTox
return "regression"
end
end
- raise "unknown model "+[@dependentVariable.feature_type, @metadata[OT.isA], @metadata[DC.title], @uri].inspect
+ raise "unknown model "+[@dependentVariable.feature_type, @metadata[OT.isA],
+ @metadata[DC.title], @uri, algorithm_title].inspect
end
end
diff --git a/lib/task.rb b/lib/task.rb
index 3c6aba5..74940de 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -78,6 +78,7 @@ module OpenTox
# @param [String] uri Task URI
# @return [OpenTox::Task] Task object
def self.find(uri)
+ return nil unless uri
task = Task.new(uri)
task.load_metadata
task
@@ -94,10 +95,23 @@ module OpenTox
@metadata = YAML.load(yaml)
end
+
def self.from_rdfxml(rdfxml)
- file = Tempfile.open("ot-rdfxml"){|f| f.write(rdfxml)}.path
+ file = Tempfile.new("ot-rdfxml")
+ file.puts rdfxml
+ file.close
+ file = "file://"+file.path
+
+ # PENDING
+ raise "Parse from file not working: what is the base-object-uri??? (omitted in triples)"
+
parser = Parser::Owl::Generic.new file
- @metadata = parser.load_metadata
+ metadata = parser.load_metadata
+ puts metadata.inspect
+
+ task = Task.new(uri)
+ task.add_metadata(metadata)
+ task
end
def to_rdfxml
@@ -232,7 +246,7 @@ module OpenTox
sleep dur
load_metadata
# if another (sub)task is waiting for self, set progress accordingly
- waiting_task.progress(@metadata[OT.percentageCompleted]) if waiting_task
+ waiting_task.progress(@metadata[OT.percentageCompleted].to_f) if waiting_task
check_state
if (Time.new > due_to_time)
raise "max wait time exceeded ("+DEFAULT_TASK_MAX_DURATION.to_s+"sec), task: '"+@uri.to_s+"'"
--
cgit v1.2.3
From 3aaae5a3fe341073fc0537606aababe387d830e0 Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Fri, 28 Jan 2011 13:56:33 +0100
Subject: reorderd Autohorizaion.authorize?
---
lib/authorization.rb | 23 ++++++++++++-----------
1 file changed, 12 insertions(+), 11 deletions(-)
(limited to 'lib')
diff --git a/lib/authorization.rb b/lib/authorization.rb
index 1573da3..b4c1ee5 100644
--- a/lib/authorization.rb
+++ b/lib/authorization.rb
@@ -329,19 +329,20 @@ module OpenTox
# @return [Boolean] true if access granted, else otherwise
def self.authorized?(uri, request_method, subjectid)
if OpenTox::Authorization.whitelisted?(uri, request_method)
- LOGGER.debug "whitelisted! "+uri.to_s
- return true
- end
- if CONFIG[:authorization][:authorize_request].include?(request_method)
+ LOGGER.debug "authorized? >>true<< (uris is whitelisted), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}"
+ true
+ elsif CONFIG[:authorization][:authorize_request].include?(request_method)
ret = OpenTox::Authorization.authorize(uri, request_method, subjectid)
- LOGGER.debug "OpenTox helpers OpenTox::Authorization authorized? method: #{request_method} , URI: #{uri}, subjectid: #{subjectid} with return >>#{ret}<<"
- return ret
+ LOGGER.debug "authorized? >>#{ret}<< (uri authorized), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}"
+ ret
+ elsif CONFIG[:authorization][:authenticate_request].include?(request_method)
+ ret = OpenTox::Authorization.is_token_valid(subjectid)
+ LOGGER.debug "authorized? >>#{ret}<< (token is valid), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}"
+ ret
+ else
+ LOGGER.debug "authorized? >>true<< (request is free), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}"
+ true
end
- if CONFIG[:authorization][:authenticate_request].include?(request_method)
- return true if OpenTox::Authorization.is_token_valid(subjectid)
- end
- LOGGER.debug "Not authorized for: #{uri} with Method: #{request_method} with Token #{subjectid}"
- return false
end
@@whitelist = {}
--
cgit v1.2.3
From 26c0b93a02fddb60175747f7733d13e973257cd8 Mon Sep 17 00:00:00 2001
From: mr
Date: Tue, 1 Feb 2011 16:34:20 +0100
Subject: A&A for validations
---
lib/authorization.rb | 79 ++++++++++++++++++++++++++++------------------------
lib/helper.rb | 20 ++++---------
lib/model.rb | 4 +--
lib/validation.rb | 12 ++++----
4 files changed, 56 insertions(+), 59 deletions(-)
(limited to 'lib')
diff --git a/lib/authorization.rb b/lib/authorization.rb
index b4c1ee5..12be037 100644
--- a/lib/authorization.rb
+++ b/lib/authorization.rb
@@ -328,55 +328,60 @@ module OpenTox
# @param [String] subjectid
# @return [Boolean] true if access granted, else otherwise
def self.authorized?(uri, request_method, subjectid)
- if OpenTox::Authorization.whitelisted?(uri, request_method)
- LOGGER.debug "authorized? >>true<< (uris is whitelisted), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}"
- true
- elsif CONFIG[:authorization][:authorize_request].include?(request_method)
- ret = OpenTox::Authorization.authorize(uri, request_method, subjectid)
- LOGGER.debug "authorized? >>#{ret}<< (uri authorized), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}"
- ret
+ if CONFIG[:authorization][:free_request].include?(request_method)
+ #LOGGER.debug "authorized? >>true<< (request is free), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}"
+ true
+ elsif OpenTox::Authorization.free_uri?(uri, request_method)
+ #LOGGER.debug "authorized? >>true<< (uris is free_uri), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}"
+ true
elsif CONFIG[:authorization][:authenticate_request].include?(request_method)
ret = OpenTox::Authorization.is_token_valid(subjectid)
- LOGGER.debug "authorized? >>#{ret}<< (token is valid), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}"
+ #LOGGER.debug "authorized? >>#{ret}<< (token is in/valid), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}"
+ ret
+ elsif OpenTox::Authorization.authorize_exception?(uri, request_method)
+ ret = OpenTox::Authorization.is_token_valid(subjectid)
+ #LOGGER.debug "authorized? >>#{ret}<< (uris is authorize exception, token is in/valid), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}"
+ ret
+ elsif CONFIG[:authorization][:authorize_request].include?(request_method)
+ ret = OpenTox::Authorization.authorize(uri, request_method, subjectid)
+ LOGGER.debug "authorized? >>#{ret}<< (uri (not) authorized), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}"
ret
else
- LOGGER.debug "authorized? >>true<< (request is free), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}"
- true
+ LOGGER.error "invalid request/uri method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}"
+ false
end
end
- @@whitelist = {}
-
private
- def self.whitelisted?(uri, request_method)
- return false unless @@whitelist[request_method]
- @@whitelist[request_method].each do |regexp,invert|
- if invert
- return true if !regexp.match(uri)
- else
- return true if regexp.match(uri)
+ def self.free_uri?(uri, request_method)
+ if CONFIG[:authorization][:free_uris]
+ CONFIG[:authorization][:free_uris].each do |request_methods,uris|
+ LOGGER.info "free uris "+request_methods.inspect+" -> "+uris.inspect
+ if request_methods and uris and request_methods.include?(request_method.to_sym)
+ uris.each do |u|
+ return true if u.match uri
+ end
+ end
end
- end
+ end
return false
end
- public
- # adds uri/regexp-for-matching-uri to the whitelist for a request-method (i.e. access will be granted without cheking the A&A service)
- # @param [String or Regexp] uri_match if string match must be ecaxt
- # @param [String] request_method, must be GET, POST, PUT, DELETE
- # @param [Boolean,optional] invert, set to true if you want to whitelist everything that does not match (careful!)
- def self.whitelist(uri_match, request_method, invert=false)
- if uri_match.is_a?(Regexp)
- uri_regex = uri_match
- elsif uri_match.is_a?(String)
- uri_regex = Regexp.new("^"+uri_match+"$")
- else
- raise "uri-match param is neither string(->exact uri match) nor regexp: "+uri_match.class.to_s
- end
- LOGGER.info("whitelisted "+request_method.to_s+" "+uri_regex.to_s)
- @@whitelist[request_method] = [] unless @@whitelist[request_method]
- @@whitelist[request_method] << [ uri_regex, invert ]
- end
+ def self.authorize_exception?(uri, request_method)
+ if CONFIG[:authorization][:authorize_exceptions]
+ CONFIG[:authorization][:authorize_exceptions].each do |request_methods,uris|
+ if request_methods and uris and request_methods.include?(request_method.to_sym)
+ uris.each do |u|
+ return true if u.match uri
+ end
+ end
+ end
+ end
+ return false
+ end
+
+
+
end
end
diff --git a/lib/helper.rb b/lib/helper.rb
index afeeb43..0bb489c 100644
--- a/lib/helper.rb
+++ b/lib/helper.rb
@@ -9,6 +9,7 @@ helpers do
end
elsif !env["session"] && subjectid
unless authorized?(subjectid)
+ LOGGER.debug "URI not authorized: #{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}#{request.env['REQUEST_URI']} with request: #{request.env['REQUEST_METHOD']}"
raise OpenTox::NotAuthorizedError.new "Not authorized"
end
else
@@ -29,27 +30,18 @@ helpers do
def clean_uri(uri)
out = URI.parse(uri)
out.path = out.path[0, out.path.rindex(/[0-9]/) + 1] if out.path.rindex(/[0-9]/) #cuts after id for a&a
- "#{out.scheme}:" + (out.port != 80 ? out.port : "") + "//#{out.host}#{out.path}"
+ "#{out.scheme}:" + (out.port != 80 ? out.port : "") + "//#{out.host}#{out.path.chomp('/')}"
end
- #unprotected uris for login/logout, webapplication ...
- def unprotected_requests
- case env['REQUEST_URI']
- when /\/login$|\/logout$|\/predict$|\/toxcreate\/models$/
- return true
- when /\/features/
- return false
- when /\/compound|\/feature|\/task|\/toxcreate/ #to fix: read from config | validation should be protected
- return true
- else
- return false
- end
+ #unprotected uri for login
+ def login_requests
+ return env['REQUEST_URI'] =~ /\/login$/
end
end
before do
- unless !AA_SERVER or unprotected_requests or CONFIG[:authorization][:free_request].include?(env['REQUEST_METHOD'])
+ unless !AA_SERVER or login_requests or CONFIG[:authorization][:free_request].include?(env['REQUEST_METHOD'])
begin
subjectid = nil
subjectid = session[:subjectid] if session[:subjectid]
diff --git a/lib/model.rb b/lib/model.rb
index 80d7ec4..0073ea4 100644
--- a/lib/model.rb
+++ b/lib/model.rb
@@ -46,7 +46,7 @@ module OpenTox
@algorithm = OpenTox::Algorithm::Generic.find(@metadata[OT.algorithm], subjectid) unless @algorithm
algorithm_title = @algorithm ? @algorithm.metadata[DC.title] : nil
- @dependentVariable = OpenTox::Feature.find( @metadata[OT.dependentVariables],subjectid ) unless @dependentVariable
+ @dependentVariable = OpenTox::Feature.find( @metadata[OT.dependentVariables], subjectid) unless @dependentVariable
[@dependentVariable.feature_type, @metadata[OT.isA], @metadata[DC.title], @uri, algorithm_title].each do |type|
case type
@@ -137,7 +137,7 @@ module OpenTox
OT.parameters => [{DC.title => "dataset_uri", OT.paramValue => dataset_uri}]
})
d = Dataset.new(dataset_uri,subjectid)
- d.load_compounds
+ d.load_compounds(subjectid)
count = 0
d.compounds.each do |compound_uri|
begin
diff --git a/lib/validation.rb b/lib/validation.rb
index 76c4529..23b246b 100644
--- a/lib/validation.rb
+++ b/lib/validation.rb
@@ -13,18 +13,18 @@ module OpenTox
OpenTox::Validation.new(uri)
end
- def create_report
- @report_uri = RestClientWrapper.post(File.join(CONFIG[:services]["opentox-validation"],"/report/crossvalidation"), :validation_uris => @uri).to_s
+ def create_report(subjectid=nil)
+ @report_uri = OpenTox::RestClientWrapper.post(File.join(CONFIG[:services]["opentox-validation"],"/report/crossvalidation"), {:validation_uris => @uri, :subjectid => subjectid}).to_s
@report_uri
end
- def create_qmrf_report
- @qmrf_report_uri = RestClientWrapper.post(File.join(CONFIG[:services]["opentox-validation"],"/reach_report/qmrf"), :model_uri => @uri).to_s
+ def create_qmrf_report(subjectid=nil)
+ @qmrf_report_uri = OpenTox::RestClientWrapper.post(File.join(CONFIG[:services]["opentox-validation"],"/reach_report/qmrf"), {:model_uri => @uri, :subjectid => subjectid}).to_s
@qmrf_report_uri
end
- def summary(type)
- v = YAML.load RestClientWrappper.get(File.join(@uri, 'statistics'),:accept => "application/x-yaml").to_s
+ def summary(type, subjectid=nil)
+ v = YAML.load OpenTox::RestClientWrapper.get(File.join(@uri, 'statistics'),{:accept => "application/x-yaml", :subjectid => subjectid}).to_s
case type
when "classification"
--
cgit v1.2.3
From 70aee6e9dfece2760fc6d616e7151f41cc7625bf Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Wed, 2 Feb 2011 17:11:24 +0100
Subject: resclient wrapper: headers <-> payload, error report from rdf
---
lib/algorithm.rb | 2 +-
lib/authorization.rb | 7 ++++++-
lib/dataset.rb | 2 +-
lib/environment.rb | 4 ++--
lib/error.rb | 41 +++++++++++++++++++++++++++--------------
lib/model.rb | 4 ++--
lib/overwrite.rb | 7 +++----
lib/parser.rb | 33 ++++++++++++++++++++++++++++++++-
lib/rest_client_wrapper.rb | 39 ++++++++++++++++++++++-----------------
lib/task.rb | 9 ++++-----
lib/validation.rb | 2 +-
11 files changed, 101 insertions(+), 49 deletions(-)
(limited to 'lib')
diff --git a/lib/algorithm.rb b/lib/algorithm.rb
index ee3109c..ae05e16 100644
--- a/lib/algorithm.rb
+++ b/lib/algorithm.rb
@@ -16,7 +16,7 @@ module OpenTox
# @param [optional,OpenTox::Task] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
# @return [String] URI of new resource (dataset, model, ...)
def run(params=nil, waiting_task=nil)
- RestClientWrapper.post(@uri, {:accept => 'text/uri-list'}, params, waiting_task).to_s
+ RestClientWrapper.post(@uri, params, {:accept => 'text/uri-list'}, waiting_task).to_s
end
# Get OWL-DL representation in RDF/XML format
diff --git a/lib/authorization.rb b/lib/authorization.rb
index b4c1ee5..dd7dc12 100644
--- a/lib/authorization.rb
+++ b/lib/authorization.rb
@@ -195,7 +195,7 @@ module OpenTox
# resource = RestClient::Resource.new("#{AA_SERVER}/Pol/opensso-pol")
LOGGER.debug "OpenTox::Authorization.create_policy policy: #{policy[168,43]} with token:" + subjectid.to_s + " length: " + subjectid.length.to_s
# return true if resource.post(policy, :subjectid => subjectid, :content_type => "application/xml")
- return true if RestClientWrapper.post("#{AA_SERVER}/pol", {:subjectid => subjectid, :content_type => "application/xml"}, policy)
+ return true if RestClientWrapper.post("#{AA_SERVER}/pol", policy, {:subjectid => subjectid, :content_type => "application/xml"})
rescue
return false
end
@@ -381,4 +381,9 @@ module OpenTox
end
end
+# PENDING delete as soon as new free uri handling is merged
+# this allows GET access to all URIS that do NOT end with / or //
+OpenTox::Authorization.whitelist( /\/[0-9]+(\/?)$/, "GET", true )
+OpenTox::Authorization.whitelist( /\/[0-9]+(\/?)$/, "POST", true )
+
diff --git a/lib/dataset.rb b/lib/dataset.rb
index 9c20968..a4716dc 100644
--- a/lib/dataset.rb
+++ b/lib/dataset.rb
@@ -285,7 +285,7 @@ module OpenTox
@compounds.uniq!
if @uri
if (CONFIG[:yaml_hosts].include?(URI.parse(@uri).host))
- RestClientWrapper.post(@uri,{:content_type => "application/x-yaml", :subjectid => subjectid},self.to_yaml)
+ RestClientWrapper.post(@uri,self.to_yaml,{:content_type => "application/x-yaml", :subjectid => subjectid})
else
File.open("ot-post-file.rdf","w+") { |f| f.write(self.to_rdfxml); @path = f.path }
task_uri = RestClient.post(@uri, {:file => File.new(@path)},{:accept => "text/uri-list" , :subjectid => subjectid}).to_s.chomp
diff --git a/lib/environment.rb b/lib/environment.rb
index 203ebc6..b30b3f3 100644
--- a/lib/environment.rb
+++ b/lib/environment.rb
@@ -54,8 +54,8 @@ else
end
# Regular expressions for parsing classification data
-TRUE_REGEXP = /^(true|active|1|1.0)$/i
-FALSE_REGEXP = /^(false|inactive|0|0.0)$/i
+TRUE_REGEXP = /^(true|active|1|1.0|tox)$/i
+FALSE_REGEXP = /^(false|inactive|0|0.0|low tox)$/i
# Task durations
DEFAULT_TASK_MAX_DURATION = 36000
diff --git a/lib/error.rb b/lib/error.rb
index 8c666f3..49756d5 100644
--- a/lib/error.rb
+++ b/lib/error.rb
@@ -18,6 +18,10 @@ module OpenTox
class NotFoundError < RuntimeError
def http_code; 404; end
end
+
+ class ServiceUnavailableError < RuntimeError
+ def http_code; 503; end
+ end
class RestCallError < RuntimeError
attr_accessor :rest_params
@@ -28,18 +32,31 @@ module OpenTox
# TODO replace params with URIs (errorCause -> OT.errorCause)
attr_reader :message, :actor, :errorCause, :http_code, :errorDetails, :errorType
+
+ private
+ def initialize( http_code, erroType, message, actor, errorCause, rest_params=nil, backtrace=nil )
+ @http_code = http_code
+ @errorType = erroType
+ @message = message
+ @actor = actor
+ @errorCause = errorCause
+ @rest_params = rest_params
+ @backtrace = backtrace
+ end
+ public
# creates a error report object, from an ruby-exception object
- # @param [Exception] error
- # @param [String] actor, URI of the call that cause the error
- def initialize( error, actor )
- @http_code = error.http_code
- @errorType = error.class.to_s
- @message = error.message
- @actor = actor
- @errorCause = error.errorCause if error.errorCause
- @rest_params = error.rest_params if error.is_a?(OpenTox::RestCallError) and error.rest_params
- @backtrace = error.backtrace.short_backtrace if CONFIG[:backtrace]
+ # @param [Exception] error
+ # @param [String] actor, URI of the call that cause the error
+ def self.create( error, actor )
+ rest_params = error.rest_params if error.is_a?(OpenTox::RestCallError) and error.rest_params
+ backtrace = error.backtrace.short_backtrace if CONFIG[:backtrace]
+ ErrorReport.new( error.http_code, error.class.to_s, error.message, actor, error.errorCause, rest_params, backtrace )
+ end
+
+ def self.from_rdf(rdf)
+ metadata = OpenTox::Parser::Owl.metadata_from_rdf( rdf, OT.ErrorReport )
+ ErrorReport.new(metadata[OT.statusCode], metadata[OT.errorCode], metadata[OT.message], metadata[OT.actor], metadata[OT.errorCause])
end
# overwrite sorting to make easier readable
@@ -61,10 +78,6 @@ module OpenTox
c[OT.errorCause] = @errorCause.rdf_content if @errorCause
c
end
-
- def self.from_rdf(rdf)
- raise "not yet implemented"
- end
def to_rdfxml
s = Serializer::Owl.new
diff --git a/lib/model.rb b/lib/model.rb
index 80d7ec4..7cf52ad 100644
--- a/lib/model.rb
+++ b/lib/model.rb
@@ -17,7 +17,7 @@ module OpenTox
end
end
LOGGER.info "running model "+@uri.to_s+", params: "+params.inspect+", accept: "+accept_header.to_s
- RestClientWrapper.post(@uri,{:accept => accept_header},params,waiting_task).to_s
+ RestClientWrapper.post(@uri,params,{:accept => accept_header},waiting_task).to_s
end
# Generic OpenTox model class for all API compliant services
@@ -303,7 +303,7 @@ module OpenTox
# Save model at model service
def save(subjectid)
- self.uri = RestClientWrapper.post(@uri,{:content_type => "application/x-yaml", :subjectid => subjectid},self.to_yaml)
+ self.uri = RestClientWrapper.post(@uri,self.to_yaml,{:content_type => "application/x-yaml", :subjectid => subjectid})
end
# Delete model at model service
diff --git a/lib/overwrite.rb b/lib/overwrite.rb
index e52618c..1e1cc43 100644
--- a/lib/overwrite.rb
+++ b/lib/overwrite.rb
@@ -16,13 +16,12 @@ before {
# IMPT: set sinatra settings :show_exceptions + :raise_errors to false in config.ru, otherwise Rack::Showexceptions takes over
error Exception do
error = request.env['sinatra.error']
- # log error to logfile
+ # log error message and backtrace to logfile
LOGGER.error error.class.to_s+": "+error.message
- # log backtrace only if code is 500 -> unwanted (Runtime)Exceptions and internal errors (see error.rb)
- LOGGER.error ":\n"+error.backtrace.join("\n") if error.http_code==500
+ LOGGER.error ":\n"+error.backtrace.join("\n")
actor = "#{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}#{request.env['REQUEST_URI']}"
- rep = OpenTox::ErrorReport.new(error, actor)
+ rep = OpenTox::ErrorReport.create(error, actor)
case request.env['HTTP_ACCEPT']
when /rdf/
diff --git a/lib/parser.rb b/lib/parser.rb
index a913cf2..e055eec 100644
--- a/lib/parser.rb
+++ b/lib/parser.rb
@@ -30,7 +30,6 @@ module OpenTox
# Read metadata from opentox service
# @return [Hash] Object metadata
def load_metadata(subjectid=nil)
-
if @dataset
uri = File.join(@uri,"metadata")
else
@@ -55,6 +54,38 @@ module OpenTox
end
@metadata
end
+
+ # loads metadata from rdf-data
+ # @param [String] rdf
+ # @param [String] type of the info (e.g. OT.Task, OT.ErrorReport) needed to get the subject-uri
+ # @return [Hash] metadata
+ def self.metadata_from_rdf( rdf, type )
+ # write to file and read convert with rapper into tripples
+ file = Tempfile.new("ot-rdfxml")
+ file.puts rdf
+ file.close
+ file = "file://"+file.path
+ #puts "cmd: rapper -i rdfxml -o ntriples #{file} 2>/dev/null"
+ triples = `rapper -i rdfxml -o ntriples #{file} 2>/dev/null`
+
+ # load uri via type
+ uri = nil
+ triples.each_line do |line|
+ triple = line.to_triple
+ if triple[1] == RDF['type'] and triple[2]==type
+ raise "uri already set, two uris found with type: "+type.to_s if uri
+ uri = triple[0]
+ end
+ end
+
+ # load metadata
+ metadata = {}
+ triples.each_line do |line|
+ triple = line.to_triple
+ metadata[triple[1]] = triple[2].split('^^').first if triple[0] == uri and triple[1] != RDF['type']
+ end
+ metadata
+ end
# Generic parser for all OpenTox classes
class Generic
diff --git a/lib/rest_client_wrapper.rb b/lib/rest_client_wrapper.rb
index 7c2d719..f59dce7 100644
--- a/lib/rest_client_wrapper.rb
+++ b/lib/rest_client_wrapper.rb
@@ -14,21 +14,21 @@ module OpenTox
# @param [optional,OpenTox::Task] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
# @param [wait,Boolean] wait set to false to NOT wait for task if result is task
# @return [OpenTox::WrapperResult] a String containing the result-body of the REST call
- def self.get(uri, headers=nil, waiting_task=nil, wait=true )
- execute( "get", uri, headers, nil, waiting_task, wait)
+ def self.get(uri, headers={}, waiting_task=nil, wait=true )
+ execute( "get", uri, nil, headers, waiting_task, wait)
end
# performs a POST REST call
# raises OpenTox::Error if call fails (rescued in overwrite.rb -> halt 502)
# per default: waits for Task to finish and returns result URI of Task
# @param [String] uri destination URI
- # @param [optional,Hash] headers contains params like accept-header
# @param [optional,String] payload data posted to the service
+ # @param [optional,Hash] headers contains params like accept-header
# @param [optional,OpenTox::Task] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
# @param [wait,Boolean] wait set to false to NOT wait for task if result is task
# @return [OpenTox::WrapperResult] a String containing the result-body of the REST call
- def self.post(uri, headers, payload=nil, waiting_task=nil, wait=true )
- execute( "post", uri, headers, payload, waiting_task, wait )
+ def self.post(uri, payload=nil, headers={}, waiting_task=nil, wait=true )
+ execute( "post", uri, payload, headers, waiting_task, wait )
end
# performs a PUT REST call
@@ -37,8 +37,8 @@ module OpenTox
# @param [optional,Hash] headers contains params like accept-header
# @param [optional,String] payload data put to the service
# @return [OpenTox::WrapperResult] a String containing the result-body of the REST call
- def self.put(uri, headers, payload=nil )
- execute( "put", uri, headers, payload )
+ def self.put(uri, payload=nil, headers={} )
+ execute( "put", uri, payload, headers )
end
# performs a DELETE REST call
@@ -47,36 +47,41 @@ module OpenTox
# @param [optional,Hash] headers contains params like accept-header
# @return [OpenTox::WrapperResult] a String containing the result-body of the REST call
def self.delete(uri, headers=nil )
- execute( "delete", uri, headers, nil)
+ execute( "delete", uri, nil, headers)
end
private
- def self.execute( rest_call, uri, headers, payload=nil, waiting_task=nil, wait=true )
+ def self.execute( rest_call, uri, payload=nil, headers={}, waiting_task=nil, wait=true )
raise OpenTox::BadRequestError.new "uri is null" unless uri
raise OpenTox::BadRequestError.new "not a uri: "+uri.to_s unless uri.to_s.uri?
raise OpenTox::BadRequestError.new "headers are no hash: "+headers.inspect unless headers==nil or headers.is_a?(Hash)
raise OpenTox::BadRequestError.new "nil headers for post not allowed, use {}" if rest_call=="post" and headers==nil
headers.each{ |k,v| headers.delete(k) if v==nil } if headers #remove keys with empty values, as this can cause problems
+ raise OpenTox::BadRequestError.new "accept should go into the headers" if payload and payload.is_a?(Hash) and payload[:accept]
+ raise OpenTox::BadRequestError.new "content_type should go into the headers" if payload and payload.is_a?(Hash) and payload[:content_type]
+
+ # PENDING needed for NUTA, until we finally agree on how to send subjectid
+ headers[:subjectid] = payload.delete(:subjectid) if uri=~/ntua/ and payload and payload.is_a?(Hash) and payload.has_key?(:subjectid)
begin
#LOGGER.debug "RestCall: "+rest_call.to_s+" "+uri.to_s+" "+headers.inspect+" "+payload.inspect
- resource = RestClient::Resource.new(uri,{:timeout => 60})
- if payload
+ resource = RestClient::Resource.new(uri,{:timeout => 60})
+ if rest_call=="post" || rest_call=="put"
result = resource.send(rest_call, payload, headers)
- elsif headers
- result = resource.send(rest_call, headers)
else
- result = resource.send(rest_call)
+ result = resource.send(rest_call, headers)
end
+ # PENDING NTUA does return errors with 200
+ raise RestClient::ExceptionWithResponse.new(result) if uri=~/ntua/ and result.body =~ /about.*http:\/\/anonymous.org\/error/
+
# result is a string, with the additional fields content_type and code
res = WrapperResult.new(result.body)
res.content_type = result.headers[:content_type]
raise "content-type not set" unless res.content_type
res.code = result.code
- #LOGGER.debug "RestCall result: "+res.to_s+" "+res.code.to_s+" "+res.content_type.to_s
# TODO: Ambit returns task representation with 200 instead of result URI
return res if res.code==200 || !wait
@@ -87,10 +92,10 @@ module OpenTox
return res
rescue RestClient::RequestTimeout => ex
- received_error ex.message, 408, nil, {:rest_uri => uri, :headers => headers}
+ received_error ex.message, 408, nil, {:rest_uri => uri, :headers => headers, :payload => payload}
rescue RestClient::ExceptionWithResponse => ex
# error comming from a different webservice,
- received_error ex.http_body, ex.http_code, ex.response.net_http_res.content_type, {:rest_uri => uri, :headers => headers}
+ received_error ex.http_body, ex.http_code, ex.response.net_http_res.content_type, {:rest_uri => uri, :headers => headers, :payload => payload}
rescue OpenTox::RestCallError => ex
# already a rest-error, probably comes from wait_for_task, just pass through
raise ex
diff --git a/lib/task.rb b/lib/task.rb
index 74940de..f635b43 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -33,7 +33,7 @@ module OpenTox
def self.create( title=nil, creator=nil, max_duration=DEFAULT_TASK_MAX_DURATION, description=nil )
params = {:title=>title, :creator=>creator, :max_duration=>max_duration, :description=>description }
- task_uri = RestClientWrapper.post(CONFIG[:services]["opentox-task"], params, nil, false).to_s
+ task_uri = RestClientWrapper.post(CONFIG[:services]["opentox-task"], params, {}, false).to_s
task = Task.new(task_uri.chomp)
# measure current memory consumption
@@ -64,9 +64,8 @@ module OpenTox
task.completed(result)
rescue => error
LOGGER.error "task failed: "+error.class.to_s+": "+error.message
- # log backtrace only if code is 500 -> unwanted (Runtime)Exceptions and internal errors (see error.rb)
- LOGGER.error ":\n"+error.backtrace.join("\n") if error.http_code==500
- task.error(OpenTox::ErrorReport.new(error, creator))
+ LOGGER.error ":\n"+error.backtrace.join("\n")
+ task.error(OpenTox::ErrorReport.create(error, creator))
end
end
task.pid = task_pid
@@ -188,7 +187,7 @@ module OpenTox
# create is private now, use OpenTox::Task.as_task
#def self.create( params )
- #task_uri = RestClientWrapper.post(CONFIG[:services]["opentox-task"], params, nil, false).to_s
+ #task_uri = RestClientWrapper.post(CONFIG[:services]["opentox-task"], params, {}, false).to_s
#Task.find(task_uri.chomp)
#end
diff --git a/lib/validation.rb b/lib/validation.rb
index 76c4529..83be91a 100644
--- a/lib/validation.rb
+++ b/lib/validation.rb
@@ -9,7 +9,7 @@ module OpenTox
params[:num_folds] = 10 unless params[:num_folds]
params[:random_seed] = 2 unless params[:random_seed]
params[:stratified] = false unless params[:stratified]
- uri = OpenTox::RestClientWrapper.post(File.join(CONFIG[:services]["opentox-validation"],"/crossvalidation"),params,nil,false)
+ uri = OpenTox::RestClientWrapper.post(File.join(CONFIG[:services]["opentox-validation"],"/crossvalidation"),params,{},false)
OpenTox::Validation.new(uri)
end
--
cgit v1.2.3
From 4ca97288ad2a270c34dc4f18634ee40915a45462 Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Thu, 3 Feb 2011 09:45:18 +0100
Subject: return task method for sinatra
---
lib/overwrite.rb | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
(limited to 'lib')
diff --git a/lib/overwrite.rb b/lib/overwrite.rb
index 1e1cc43..7b53122 100644
--- a/lib/overwrite.rb
+++ b/lib/overwrite.rb
@@ -36,6 +36,27 @@ error Exception do
end
end
+class Sinatra::Base
+
+ def return_task( task )
+ code = task.running? ? 202 : 200
+ case request.env['HTTP_ACCEPT']
+ when /rdf/
+ response['Content-Type'] = "application/rdf+xml"
+ halt code,task.to_rdfxml
+ when /yaml/
+ response['Content-Type'] = "application/rdf+xml"
+ halt code,task.to_yaml # PENDING differs from task-webservice
+ when /html/
+ response['Content-Type'] = "text/html"
+ halt code,OpenTox.text_to_html(task.to_yaml)
+ else # default /uri-list/
+ response['Content-Type'] = "text/uri-list"
+ halt code,task.uri+"\n"
+ end
+ end
+end
+
class String
def task_uri?
self.uri? && !self.match(/task/).nil?
--
cgit v1.2.3
From 34ef45bf1f87c787e3ddaccc03a36a5fa2d54c7f Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Thu, 3 Feb 2011 18:10:48 +0100
Subject: update /refactor validation.rb
---
lib/algorithm.rb | 2 +-
lib/rest_client_wrapper.rb | 7 +-
lib/task.rb | 3 +-
lib/validation.rb | 180 ++++++++++++++++++++++++++++++++-------------
4 files changed, 134 insertions(+), 58 deletions(-)
(limited to 'lib')
diff --git a/lib/algorithm.rb b/lib/algorithm.rb
index ae05e16..bfa9860 100644
--- a/lib/algorithm.rb
+++ b/lib/algorithm.rb
@@ -34,7 +34,7 @@ module OpenTox
# Find Generic Opentox Algorithm via URI, and loads metadata
# @param [String] uri Algorithm URI
# @return [OpenTox::Algorithm::Generic] Algorithm instance, nil if alogrithm was not found
- def self.find(uri, subjectid)
+ def self.find(uri, subjectid=nil)
return nil unless uri
alg = Generic.new(uri)
alg.load_metadata( subjectid )
diff --git a/lib/rest_client_wrapper.rb b/lib/rest_client_wrapper.rb
index f59dce7..658f111 100644
--- a/lib/rest_client_wrapper.rb
+++ b/lib/rest_client_wrapper.rb
@@ -55,11 +55,12 @@ module OpenTox
raise OpenTox::BadRequestError.new "uri is null" unless uri
raise OpenTox::BadRequestError.new "not a uri: "+uri.to_s unless uri.to_s.uri?
- raise OpenTox::BadRequestError.new "headers are no hash: "+headers.inspect unless headers==nil or headers.is_a?(Hash)
- raise OpenTox::BadRequestError.new "nil headers for post not allowed, use {}" if rest_call=="post" and headers==nil
- headers.each{ |k,v| headers.delete(k) if v==nil } if headers #remove keys with empty values, as this can cause problems
+ raise "headers are no hash: "+headers.inspect unless headers==nil or headers.is_a?(Hash)
raise OpenTox::BadRequestError.new "accept should go into the headers" if payload and payload.is_a?(Hash) and payload[:accept]
raise OpenTox::BadRequestError.new "content_type should go into the headers" if payload and payload.is_a?(Hash) and payload[:content_type]
+ raise "__waiting_task__ must be 'nil' or '(sub)task', is "+waiting_task.class.to_s if
+ waiting_task!=nil and !(waiting_task.is_a?(Task) || waiting_task.is_a?(SubTask))
+ headers.each{ |k,v| headers.delete(k) if v==nil } if headers #remove keys with empty values, as this can cause problems
# PENDING needed for NUTA, until we finally agree on how to send subjectid
headers[:subjectid] = payload.delete(:subjectid) if uri=~/ntua/ and payload and payload.is_a?(Hash) and payload.has_key?(:subjectid)
diff --git a/lib/task.rb b/lib/task.rb
index f635b43..9c52299 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -33,7 +33,7 @@ module OpenTox
def self.create( title=nil, creator=nil, max_duration=DEFAULT_TASK_MAX_DURATION, description=nil )
params = {:title=>title, :creator=>creator, :max_duration=>max_duration, :description=>description }
- task_uri = RestClientWrapper.post(CONFIG[:services]["opentox-task"], params, {}, false).to_s
+ task_uri = RestClientWrapper.post(CONFIG[:services]["opentox-task"], params, {}, nil, false).to_s
task = Task.new(task_uri.chomp)
# measure current memory consumption
@@ -284,7 +284,6 @@ module OpenTox
raise OpenTox::BadRequestError.new ex.message+" (task-uri:"+@uri+")"
end
end
-
end
# Convenience class to split a (sub)task into subtasks
diff --git a/lib/validation.rb b/lib/validation.rb
index 83be91a..b1ccb7b 100644
--- a/lib/validation.rb
+++ b/lib/validation.rb
@@ -1,70 +1,146 @@
module OpenTox
- class Validation
+ class Crossvalidation
include OpenTox
- attr_accessor :report_uri, :qmrf_report_uri
+ attr_reader :report
+
+ # find crossvalidation, raises error if not found
+ # @param [String] uri
+ # @param [String,optional] subjectid
+ # @return [OpenTox::Crossvalidation]
+ def self.find( uri, subjectid=nil )
+ # PENDING load crossvalidation data?
+ OpenTox::RestClientWrapper.get(uri,{:subjectid => subjectid})
+ Crossvalidation.new(uri)
+ end
- def self.create_crossvalidation(params)
- params[:uri] = File.join(CONFIG[:services]['opentox-validation'], "crossvalidation")
+ # creates a crossvalidations, waits until it finishes, may take some time
+ # @param [Hash] params
+ # @param [String,optional] subjectid
+ # @param [OpenTox::Task,optional] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
+ # @return [OpenTox::Crossvalidation]
+ def self.create( params, subjectid=nil, waiting_task=nil )
+ params[:uri] = File.join(CONFIG[:services]['opentox-validation'], "crossvalidation")
params[:num_folds] = 10 unless params[:num_folds]
- params[:random_seed] = 2 unless params[:random_seed]
- params[:stratified] = false unless params[:stratified]
- uri = OpenTox::RestClientWrapper.post(File.join(CONFIG[:services]["opentox-validation"],"/crossvalidation"),params,{},false)
- OpenTox::Validation.new(uri)
- end
-
- def create_report
- @report_uri = RestClientWrapper.post(File.join(CONFIG[:services]["opentox-validation"],"/report/crossvalidation"), :validation_uris => @uri).to_s
- @report_uri
+ params[:random_seed] = 2 unless params[:random_seed]
+ params[:stratified] = false unless params[:stratified]
+ params[:subjectid] = subjectid if subjectid
+ uri = OpenTox::RestClientWrapper.post( File.join(CONFIG[:services]["opentox-validation"],"/crossvalidation"),
+ params,{:content_type => "text/uri-list"},waiting_task )
+ Crossvalidation.new(uri)
end
- def create_qmrf_report
- @qmrf_report_uri = RestClientWrapper.post(File.join(CONFIG[:services]["opentox-validation"],"/reach_report/qmrf"), :model_uri => @uri).to_s
- @qmrf_report_uri
+ # looks for report for this crossvalidation, creates a report if no report is found
+ # @param [String,optional] subjectid
+ # @param [OpenTox::Task,optional] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
+ # @return [OpenTox::CrossvalidationReport]
+ def find_or_create_report( subjectid=nil, waiting_task=nil )
+ @report = CrossvalidationReport.find_for_crossvalidation(self, subjectid) unless @report
+ @report = CrossvalidationReport.create(self, subjectid, waiting_task) unless @report
+ @report
end
- def summary(type)
- v = YAML.load RestClientWrappper.get(File.join(@uri, 'statistics'),:accept => "application/x-yaml").to_s
-
- case type
- when "classification"
- tp=0; tn=0; fp=0; fn=0; n=0
- v[:classification_statistics][:confusion_matrix][:confusion_matrix_cell].each do |cell|
- if cell[:confusion_matrix_predicted] == "true" and cell[:confusion_matrix_actual] == "true"
- tp = cell[:confusion_matrix_value]
- n += tp
- elsif cell[:confusion_matrix_predicted] == "false" and cell[:confusion_matrix_actual] == "false"
- tn = cell[:confusion_matrix_value]
- n += tn
- elsif cell[:confusion_matrix_predicted] == "false" and cell[:confusion_matrix_actual] == "true"
- fn = cell[:confusion_matrix_value]
- n += fn
- elsif cell[:confusion_matrix_predicted] == "true" and cell[:confusion_matrix_actual] == "false"
- fp = cell[:confusion_matrix_value]
- n += fp
+ # PENDING: creates summary as used for ToxCreate
+ def summary
+ v = YAML.load RestClientWrapper.get(File.join(@uri, 'statistics'),:accept => "application/x-yaml").to_s
+ if v[OT.classificationStatistics]
+ res = {
+ :nr_predictions => v[OT.numInstances] - v[OT.numUnpredicted],
+ :correct_predictions => v[OT.classificationStatistics][OT.percentCorrect],
+ :weighted_area_under_roc => v[OT.classificationStatistics][OT.weightedAreaUnderRoc],
+ }
+ v[OT.classificationStatistics][OT.classValueStatistics].each do |s|
+ if s[OT.classValue].to_s=="true"
+ res[:true_positives] = s[OT.numTruePositives]
+ res[:false_positives] = s[OT.numFalsePositives]
+ res[:true_negatives] = s[OT.numTrueNegatives]
+ res[:false_negatives] = s[OT.numFalseNegatives]
+ res[:sensitivity] = s[OT.truePositiveRate]
+ res[:specificity] = s[OT.falsePositiveRate]
+ break
end
end
+ res
+ elsif v[OT.regressionStatistics]
{
- :nr_predictions => n,
- :true_positives => tp,
- :false_positives => fp,
- :true_negatives => tn,
- :false_negatives => fn,
- :correct_predictions => 100*(tp+tn).to_f/n,
- :weighted_area_under_roc => v[:classification_statistics][:weighted_area_under_roc].to_f,
- :sensitivity => tp.to_f/(tp+fn),
- :specificity => tn.to_f/(tn+fp),
- }
- when "regression"
- {
- :nr_predictions => v[:num_instances] - v[:num_unpredicted],
- :r_square => v[:regression_statistics][:r_square],
- :root_mean_squared_error => v[:regression_statistics][:root_mean_squared_error],
- :mean_absolute_error => v[:regression_statistics][:mean_absolute_error],
+ :nr_predictions => v[OT.numInstances] - v[OT.numUnpredicted],
+ :r_square => v[OT.regressionStatistics][OT.rSquare],
+ :root_mean_squared_error => v[OT.regressionStatistics][OT.rootMeanSquaredError],
+ :mean_absolute_error => v[OT.regressionStatistics][OT.meanAbsoluteError],
}
end
end
+ end
- end
+ class CrossvalidationReport
+ include OpenTox
+
+ # finds CrossvalidationReport via uri, raises error if not found
+ # @param [String] uri
+ # @param [String,optional] subjectid
+ # @return [OpenTox::CrossvalidationReport]
+ def self.find( uri, subjectid=nil )
+ # PENDING load report data?
+ OpenTox::RestClientWrapper.get(uri,{:subjectid => subjectid})
+ CrossvalidationReport.new(uri)
+ end
+
+ # finds CrossvalidationReport for a particular crossvalidation
+ # @param [OpenTox::Crossvalidation]
+ # @param [String,optional] subjectid
+ # @return [OpenTox::CrossvalidationReport] nil if no report found
+ def self.find_for_crossvalidation( crossvalidation, subjectid=nil )
+ uris = RestClientWrapper.get(File.join(CONFIG[:services]["opentox-validation"],
+ "/report/crossvalidation?crossvalidation="+crossvalidation.uri), {:subjectid => subjectid}).chomp.split("\n")
+ uris.size==0 ? nil : CrossvalidationReport.new(uris[-1])
+ end
+
+ # creates a crossvalidation report via crossvalidation
+ # @param [OpenTox::Crossvalidation]
+ # @param [String,optional] subjectid
+ # @param [OpenTox::Task,optional] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
+ # @return [OpenTox::CrossvalidationReport]
+ def self.create( crossvalidation, subjectid=nil, waiting_task=nil )
+ uri = RestClientWrapper.post(File.join(CONFIG[:services]["opentox-validation"],"/report/crossvalidation"),
+ { :validation_uris => crossvalidation.uri, :subjectid => subjectid }, {}, waiting_task )
+ CrossvalidationReport.new(uri)
+ end
+ end
+
+ class QMRFReport
+ include OpenTox
+
+ # finds QMRFReport, raises Error if not found
+ # @param [String] uri
+ # @param [String,optional] subjectid
+ # @return [OpenTox::QMRFReport]
+ def self.find( uri, subjectid=nil )
+ # PENDING load crossvalidation data?
+ OpenTox::RestClientWrapper.get(uri,{:subjectid => subjectid})
+ QMRFReport.new(uri)
+ end
+
+ # finds QMRF report for a particular model
+ # @param [OpenTox::Crossvalidation]
+ # @param [String,optional] subjectid
+ # @return [OpenTox::QMRFReport] nil if no report found
+ def self.find_for_model( model, subjectid=nil )
+ uris = RestClientWrapper.get(File.join(CONFIG[:services]["opentox-validation"],
+ "/reach_report/qmrf?model="+model.uri), {:subjectid => subjectid}).chomp.split("\n")
+ uris.size==0 ? nil : QMRFReport.new(uris[-1])
+ end
+
+ # creates a qmrf report via model
+ # @param [OpenTox::Model]
+ # @param [String,optional] subjectid
+ # @param [OpenTox::Task,optional] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
+ # @return [OpenTox::QMRFReport]
+ def self.create( model, subjectid=nil, waiting_task=nil )
+ uri = RestClientWrapper.post(File.join(CONFIG[:services]["opentox-validation"],"/reach_report/qmrf"),
+ { :model_uri => model.uri, :subjectid => subjectid }, {}, waiting_task )
+ QMRFReport.new(uri)
+ end
+ end
+
end
--
cgit v1.2.3
From e035b7136b8c2df70de980379695fbfeaf070290 Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Fri, 4 Feb 2011 09:32:22 +0100
Subject: add missing subjectid param
---
lib/validation.rb | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
(limited to 'lib')
diff --git a/lib/validation.rb b/lib/validation.rb
index b1ccb7b..d70bba2 100644
--- a/lib/validation.rb
+++ b/lib/validation.rb
@@ -41,8 +41,8 @@ module OpenTox
end
# PENDING: creates summary as used for ToxCreate
- def summary
- v = YAML.load RestClientWrapper.get(File.join(@uri, 'statistics'),:accept => "application/x-yaml").to_s
+ def summary( subjectid=nil )
+ v = YAML.load RestClientWrapper.get(File.join(@uri, 'statistics'),{:accept => "application/x-yaml", :subjectid => subjectid}).to_s
if v[OT.classificationStatistics]
res = {
:nr_predictions => v[OT.numInstances] - v[OT.numUnpredicted],
--
cgit v1.2.3
From 5ea8356992751af875812f0e244f08760eb30aee Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Fri, 4 Feb 2011 16:13:25 +0100
Subject: added delete to opentox objects, cosmetics
---
lib/opentox.rb | 5 +++++
lib/validation.rb | 12 ++++--------
2 files changed, 9 insertions(+), 8 deletions(-)
(limited to 'lib')
diff --git a/lib/opentox.rb b/lib/opentox.rb
index f1af5c3..1992896 100644
--- a/lib/opentox.rb
+++ b/lib/opentox.rb
@@ -43,5 +43,10 @@ module OpenTox
s.to_rdfxml
end
+ # deletes the resource, deletion should have worked when no RestCallError raised
+ def delete(subjectid=nil)
+ RestClientWrapper.delete(uri,:subjectid => subjectid)
+ end
+
end
diff --git a/lib/validation.rb b/lib/validation.rb
index d70bba2..c256d1d 100644
--- a/lib/validation.rb
+++ b/lib/validation.rb
@@ -1,8 +1,8 @@
module OpenTox
- class Crossvalidation
+ class Crossvalidation
include OpenTox
- attr_reader :report
+ attr_reader :report
# find crossvalidation, raises error if not found
# @param [String] uri
@@ -15,17 +15,13 @@ module OpenTox
end
# creates a crossvalidations, waits until it finishes, may take some time
- # @param [Hash] params
+ # @param [Hash] params (required:algorithm_uri,dataset_uri,prediction_feature, optional:algorithm_params,num_folds(10),random_seed(1),stratified(false))
# @param [String,optional] subjectid
# @param [OpenTox::Task,optional] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
# @return [OpenTox::Crossvalidation]
def self.create( params, subjectid=nil, waiting_task=nil )
- params[:uri] = File.join(CONFIG[:services]['opentox-validation'], "crossvalidation")
- params[:num_folds] = 10 unless params[:num_folds]
- params[:random_seed] = 2 unless params[:random_seed]
- params[:stratified] = false unless params[:stratified]
params[:subjectid] = subjectid if subjectid
- uri = OpenTox::RestClientWrapper.post( File.join(CONFIG[:services]["opentox-validation"],"/crossvalidation"),
+ uri = OpenTox::RestClientWrapper.post( File.join(CONFIG[:services]["opentox-validation"],"crossvalidation"),
params,{:content_type => "text/uri-list"},waiting_task )
Crossvalidation.new(uri)
end
--
cgit v1.2.3
From 9848197e9e0830c569ae2addcd404c59c0a53180 Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Mon, 7 Feb 2011 10:07:34 +0100
Subject: add Dataset.exist as find loads all data
---
lib/dataset.rb | 13 +++++++++++++
1 file changed, 13 insertions(+)
(limited to 'lib')
diff --git a/lib/dataset.rb b/lib/dataset.rb
index a4716dc..02b89cb 100644
--- a/lib/dataset.rb
+++ b/lib/dataset.rb
@@ -56,6 +56,19 @@ module OpenTox
dataset.load_all(subjectid)
dataset
end
+
+ # replaces find as exist check, takes not as long, does NOT raise an un-authorized exception
+ # @param [String] uri Dataset URI
+ # @return [Boolean] true if dataset exists and user has get rights, false else
+ def self.exist?(uri, subjectid=nil)
+ return false unless uri
+ dataset = Dataset.new(uri, subjectid)
+ begin
+ dataset.load_metadata( subjectid ).size > 0
+ rescue
+ false
+ end
+ end
# Get all datasets from a service
# @param [optional,String] uri URI of the dataset service, defaults to service specified in configuration
--
cgit v1.2.3
From 281a0bade2ca1d1bb040c54704650b69f6da24a5 Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Mon, 7 Feb 2011 15:35:53 +0100
Subject: .find method raises error if opentox-object not found, extending
validation.rb
---
lib/algorithm.rb | 11 ++---
lib/model.rb | 11 ++---
lib/task.rb | 1 +
lib/validation.rb | 144 +++++++++++++++++++++++++++++++++++++-----------------
4 files changed, 108 insertions(+), 59 deletions(-)
(limited to 'lib')
diff --git a/lib/algorithm.rb b/lib/algorithm.rb
index bfa9860..af8dfaf 100644
--- a/lib/algorithm.rb
+++ b/lib/algorithm.rb
@@ -31,18 +31,15 @@ module OpenTox
class Generic
include Algorithm
- # Find Generic Opentox Algorithm via URI, and loads metadata
+ # Find Generic Opentox Algorithm via URI, and loads metadata, could raise NotFound/NotAuthorized error
# @param [String] uri Algorithm URI
- # @return [OpenTox::Algorithm::Generic] Algorithm instance, nil if alogrithm was not found
+ # @return [OpenTox::Algorithm::Generic] Algorithm instance
def self.find(uri, subjectid=nil)
return nil unless uri
alg = Generic.new(uri)
alg.load_metadata( subjectid )
- if alg.metadata==nil or alg.metadata.size==0
- nil
- else
- alg
- end
+ raise "cannot load algorithm metadata" if alg.metadata==nil or alg.metadata.size==0
+ alg
end
end
diff --git a/lib/model.rb b/lib/model.rb
index 7cf52ad..ae793e8 100644
--- a/lib/model.rb
+++ b/lib/model.rb
@@ -24,18 +24,15 @@ module OpenTox
class Generic
include Model
- # Find Generic Opentox Model via URI, and loads metadata
+ # Find Generic Opentox Model via URI, and loads metadata, could raise NotFound/NotAuthorized error
# @param [String] uri Model URI
- # @return [OpenTox::Model::Generic] Model instance, nil if model was not found
+ # @return [OpenTox::Model::Generic] Model instance
def self.find(uri,subjectid=nil)
return nil unless uri
model = Generic.new(uri)
model.load_metadata(subjectid)
- if model.metadata==nil or model.metadata.size==0
- nil
- else
- model
- end
+ raise "could not load model metadata" if model.metadata==nil or model.metadata.size==0
+ model
end
# provides feature type, possible types are "regression" or "classification"
diff --git a/lib/task.rb b/lib/task.rb
index 9c52299..73d880e 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -80,6 +80,7 @@ module OpenTox
return nil unless uri
task = Task.new(uri)
task.load_metadata
+ raise "could not load task metadata" if task.metadata==nil or task.metadata.size==0
task
end
diff --git a/lib/validation.rb b/lib/validation.rb
index c256d1d..f0c5297 100644
--- a/lib/validation.rb
+++ b/lib/validation.rb
@@ -1,4 +1,63 @@
module OpenTox
+ class Validation
+ include OpenTox
+
+ # find validation, raises error if not found
+ # @param [String] uri
+ # @param [String,optional] subjectid
+ # @return [OpenTox::Validation]
+ def self.find( uri, subjectid=nil )
+ val = Validation.new(uri)
+ val.load_metadata( subjectid )
+ val
+ end
+
+ # creates a validation object from crossvaldiation statistics, raise error if not found
+ # (as crossvaldiation statistics are returned as an average valdidation over all folds)
+ # @param [String] crossvalidation uri
+ # @param [String,optional] subjectid
+ # @return [OpenTox::Validation]
+ def self.from_cv_statistics( crossvalidation_uri, subjectid=nil )
+ find( File.join(crossvalidation_uri, 'statistics'),subjectid )
+ end
+
+ # loads metadata via yaml from validation object
+ # fields (like for example the validated model) can be acces via validation.metadata[OT.model]
+ def load_metadata( subjectid=nil )
+ @metadata = YAML.load(OpenTox::RestClientWrapper.get(uri,{:subjectid => subjectid, :accept => "application/x-yaml"}))
+ end
+
+ # PENDING: creates summary as used for ToxCreate
+ def summary
+ if @metadata[OT.classificationStatistics]
+ res = {
+ :nr_predictions => @metadata[OT.numInstances] - @metadata[OT.numUnpredicted],
+ :correct_predictions => @metadata[OT.classificationStatistics][OT.percentCorrect],
+ :weighted_area_under_roc => @metadata[OT.classificationStatistics][OT.weightedAreaUnderRoc],
+ }
+ @metadata[OT.classificationStatistics][OT.classValueStatistics].each do |s|
+ if s[OT.classValue].to_s=="true"
+ res[:true_positives] = s[OT.numTruePositives]
+ res[:false_positives] = s[OT.numFalsePositives]
+ res[:true_negatives] = s[OT.numTrueNegatives]
+ res[:false_negatives] = s[OT.numFalseNegatives]
+ res[:sensitivity] = s[OT.truePositiveRate]
+ res[:specificity] = s[OT.falsePositiveRate]
+ break
+ end
+ end
+ res
+ elsif @metadata[OT.regressionStatistics]
+ {
+ :nr_predictions => @metadata[OT.numInstances] - @metadata[OT.numUnpredicted],
+ :r_square => @metadata[OT.regressionStatistics][OT.rSquare],
+ :root_mean_squared_error => @metadata[OT.regressionStatistics][OT.rootMeanSquaredError],
+ :mean_absolute_error => @metadata[OT.regressionStatistics][OT.meanAbsoluteError],
+ }
+ end
+ end
+ end
+
class Crossvalidation
include OpenTox
@@ -9,9 +68,9 @@ module OpenTox
# @param [String,optional] subjectid
# @return [OpenTox::Crossvalidation]
def self.find( uri, subjectid=nil )
- # PENDING load crossvalidation data?
- OpenTox::RestClientWrapper.get(uri,{:subjectid => subjectid})
- Crossvalidation.new(uri)
+ cv = Crossvalidation.new(uri)
+ cv.load_metadata( subjectid )
+ cv
end
# creates a crossvalidations, waits until it finishes, may take some time
@@ -31,42 +90,37 @@ module OpenTox
# @param [OpenTox::Task,optional] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
# @return [OpenTox::CrossvalidationReport]
def find_or_create_report( subjectid=nil, waiting_task=nil )
- @report = CrossvalidationReport.find_for_crossvalidation(self, subjectid) unless @report
- @report = CrossvalidationReport.create(self, subjectid, waiting_task) unless @report
+ @report = CrossvalidationReport.find_for_crossvalidation(@uri, subjectid) unless @report
+ @report = CrossvalidationReport.create(@uri, subjectid, waiting_task) unless @report
@report
end
-
+
+ # loads metadata via yaml from crossvalidation object
+ # fields (like for example the validations) can be acces via validation.metadata[OT.validation]
+ def load_metadata( subjectid=nil )
+ @metadata = YAML.load(OpenTox::RestClientWrapper.get(uri,{:subjectid => subjectid, :accept => "application/x-yaml"}))
+ end
+
# PENDING: creates summary as used for ToxCreate
def summary( subjectid=nil )
- v = YAML.load RestClientWrapper.get(File.join(@uri, 'statistics'),{:accept => "application/x-yaml", :subjectid => subjectid}).to_s
- if v[OT.classificationStatistics]
- res = {
- :nr_predictions => v[OT.numInstances] - v[OT.numUnpredicted],
- :correct_predictions => v[OT.classificationStatistics][OT.percentCorrect],
- :weighted_area_under_roc => v[OT.classificationStatistics][OT.weightedAreaUnderRoc],
- }
- v[OT.classificationStatistics][OT.classValueStatistics].each do |s|
- if s[OT.classValue].to_s=="true"
- res[:true_positives] = s[OT.numTruePositives]
- res[:false_positives] = s[OT.numFalsePositives]
- res[:true_negatives] = s[OT.numTrueNegatives]
- res[:false_negatives] = s[OT.numFalseNegatives]
- res[:sensitivity] = s[OT.truePositiveRate]
- res[:specificity] = s[OT.falsePositiveRate]
- break
- end
- end
- res
- elsif v[OT.regressionStatistics]
- {
- :nr_predictions => v[OT.numInstances] - v[OT.numUnpredicted],
- :r_square => v[OT.regressionStatistics][OT.rSquare],
- :root_mean_squared_error => v[OT.regressionStatistics][OT.rootMeanSquaredError],
- :mean_absolute_error => v[OT.regressionStatistics][OT.meanAbsoluteError],
- }
- end
+ Validation.from_cv_statistics( @uri, subjectid ).summary
end
end
+
+ class ValidationReport
+ include OpenTox
+
+ # finds ValidationReport for a particular validation
+ # @param [String] crossvalidation uri
+ # @param [String,optional] subjectid
+ # @return [OpenTox::ValidationReport] nil if no report found
+ def self.find_for_validation( validation_uri, subjectid=nil )
+ uris = RestClientWrapper.get(File.join(CONFIG[:services]["opentox-validation"],
+ "/report/validation?validation="+validation_uri), {:subjectid => subjectid}).chomp.split("\n")
+ uris.size==0 ? nil : ValidationReport.new(uris[-1])
+ end
+
+ end
class CrossvalidationReport
include OpenTox
@@ -82,23 +136,23 @@ module OpenTox
end
# finds CrossvalidationReport for a particular crossvalidation
- # @param [OpenTox::Crossvalidation]
+ # @param [String] crossvalidation uri
# @param [String,optional] subjectid
# @return [OpenTox::CrossvalidationReport] nil if no report found
- def self.find_for_crossvalidation( crossvalidation, subjectid=nil )
+ def self.find_for_crossvalidation( crossvalidation_uri, subjectid=nil )
uris = RestClientWrapper.get(File.join(CONFIG[:services]["opentox-validation"],
- "/report/crossvalidation?crossvalidation="+crossvalidation.uri), {:subjectid => subjectid}).chomp.split("\n")
+ "/report/crossvalidation?crossvalidation="+crossvalidation_uri), {:subjectid => subjectid}).chomp.split("\n")
uris.size==0 ? nil : CrossvalidationReport.new(uris[-1])
end
# creates a crossvalidation report via crossvalidation
- # @param [OpenTox::Crossvalidation]
+ # @param [String] crossvalidation uri
# @param [String,optional] subjectid
# @param [OpenTox::Task,optional] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
# @return [OpenTox::CrossvalidationReport]
- def self.create( crossvalidation, subjectid=nil, waiting_task=nil )
+ def self.create( crossvalidation_uri, subjectid=nil, waiting_task=nil )
uri = RestClientWrapper.post(File.join(CONFIG[:services]["opentox-validation"],"/report/crossvalidation"),
- { :validation_uris => crossvalidation.uri, :subjectid => subjectid }, {}, waiting_task )
+ { :validation_uris => crossvalidation_uri, :subjectid => subjectid }, {}, waiting_task )
CrossvalidationReport.new(uri)
end
end
@@ -117,23 +171,23 @@ module OpenTox
end
# finds QMRF report for a particular model
- # @param [OpenTox::Crossvalidation]
+ # @param [String] model_uri
# @param [String,optional] subjectid
# @return [OpenTox::QMRFReport] nil if no report found
- def self.find_for_model( model, subjectid=nil )
+ def self.find_for_model( model_uri, subjectid=nil )
uris = RestClientWrapper.get(File.join(CONFIG[:services]["opentox-validation"],
- "/reach_report/qmrf?model="+model.uri), {:subjectid => subjectid}).chomp.split("\n")
+ "/reach_report/qmrf?model="+model_uri), {:subjectid => subjectid}).chomp.split("\n")
uris.size==0 ? nil : QMRFReport.new(uris[-1])
end
# creates a qmrf report via model
- # @param [OpenTox::Model]
+ # @param [String] model_uri
# @param [String,optional] subjectid
# @param [OpenTox::Task,optional] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
# @return [OpenTox::QMRFReport]
- def self.create( model, subjectid=nil, waiting_task=nil )
+ def self.create( model_uri, subjectid=nil, waiting_task=nil )
uri = RestClientWrapper.post(File.join(CONFIG[:services]["opentox-validation"],"/reach_report/qmrf"),
- { :model_uri => model.uri, :subjectid => subjectid }, {}, waiting_task )
+ { :model_uri => model_uri, :subjectid => subjectid }, {}, waiting_task )
QMRFReport.new(uri)
end
end
--
cgit v1.2.3
From c37cc91893457cb91ddb2a32b9ac76090bd6c521 Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Tue, 8 Feb 2011 08:57:31 +0100
Subject: not using rapper directly, use rest client and tmp-file
---
lib/model.rb | 4 ++--
lib/parser.rb | 12 ++++++++++--
lib/task.rb | 2 +-
3 files changed, 13 insertions(+), 5 deletions(-)
(limited to 'lib')
diff --git a/lib/model.rb b/lib/model.rb
index ae793e8..64d178f 100644
--- a/lib/model.rb
+++ b/lib/model.rb
@@ -31,7 +31,7 @@ module OpenTox
return nil unless uri
model = Generic.new(uri)
model.load_metadata(subjectid)
- raise "could not load model metadata" if model.metadata==nil or model.metadata.size==0
+ raise "could not load model metadata '"+uri.to_s+"'" if model.metadata==nil or model.metadata.size==0
model
end
@@ -134,7 +134,7 @@ module OpenTox
OT.parameters => [{DC.title => "dataset_uri", OT.paramValue => dataset_uri}]
})
d = Dataset.new(dataset_uri,subjectid)
- d.load_compounds
+ d.load_compounds(subjectid)
count = 0
d.compounds.each do |compound_uri|
begin
diff --git a/lib/parser.rb b/lib/parser.rb
index e055eec..27dfeee 100644
--- a/lib/parser.rb
+++ b/lib/parser.rb
@@ -35,10 +35,18 @@ module OpenTox
else
uri = @uri
end
- uri += "?subjectid=#{CGI.escape(subjectid)}" if subjectid
+ # avoid using rapper directly because of 2 reasons:
+ # * http errors wont be noticed
+ # * subjectid cannot be sent as header
+ ##uri += "?subjectid=#{CGI.escape(subjectid)}" if subjectid
+ ## `rapper -i rdfxml -o ntriples #{uri} 2>/dev/null`.each_line do |line|
+ file = Tempfile.new("ot-rdfxml")
+ file.puts OpenTox::RestClientWrapper.get @uri,{:subjectid => subjectid,:accept => "application/rdf+xml"}
+ file.close
+ file = "file://"+file.path
statements = []
parameter_ids = []
- `rapper -i rdfxml -o ntriples #{uri} 2>/dev/null`.each_line do |line|
+ `rapper -i rdfxml -o ntriples #{file} 2>/dev/null`.each_line do |line|
triple = line.to_triple
@metadata[triple[1]] = triple[2].split('^^').first if triple[0] == @uri and triple[1] != RDF['type']
statements << triple
diff --git a/lib/task.rb b/lib/task.rb
index 73d880e..ca18d7b 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -303,7 +303,7 @@ module OpenTox
class SubTask
def initialize(task, min, max)
- raise "not a task or subtask" unless task.is_a?(Task) or task.is_a?(SubTask)
+ raise "not a task or subtask" if task!=nil and !(task.is_a?(Task) or task.is_a?(SubTask))
raise "invalid max ("+max.to_s+"), min ("+min.to_s+") params" unless
min.is_a?(Numeric) and max.is_a?(Numeric) and min >= 0 and max <= 100 and max > min
@task = task
--
cgit v1.2.3
From e4a32e37ab8708aa8ae4dbfc6069e5ea75928f3f Mon Sep 17 00:00:00 2001
From: mr
Date: Tue, 8 Feb 2011 12:58:30 +0100
Subject: manually insert code from mguetlein repository |
restclientwrapper.post event with changed method call
---
lib/algorithm.rb | 15 ++-
lib/authorization.rb | 11 +--
lib/dataset.rb | 15 ++-
lib/environment.rb | 4 +-
lib/error.rb | 37 +++++--
lib/helper.rb | 5 +-
lib/model.rb | 17 ++--
lib/opentox.rb | 5 +
lib/overwrite.rb | 28 +++++-
lib/parser.rb | 44 ++++++++-
lib/rest_client_wrapper.rb | 44 +++++----
lib/task.rb | 22 +++--
lib/validation.rb | 240 ++++++++++++++++++++++++++++++++++-----------
13 files changed, 357 insertions(+), 130 deletions(-)
(limited to 'lib')
diff --git a/lib/algorithm.rb b/lib/algorithm.rb
index ee3109c..af8dfaf 100644
--- a/lib/algorithm.rb
+++ b/lib/algorithm.rb
@@ -16,7 +16,7 @@ module OpenTox
# @param [optional,OpenTox::Task] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
# @return [String] URI of new resource (dataset, model, ...)
def run(params=nil, waiting_task=nil)
- RestClientWrapper.post(@uri, {:accept => 'text/uri-list'}, params, waiting_task).to_s
+ RestClientWrapper.post(@uri, params, {:accept => 'text/uri-list'}, waiting_task).to_s
end
# Get OWL-DL representation in RDF/XML format
@@ -31,18 +31,15 @@ module OpenTox
class Generic
include Algorithm
- # Find Generic Opentox Algorithm via URI, and loads metadata
+ # Find Generic Opentox Algorithm via URI, and loads metadata, could raise NotFound/NotAuthorized error
# @param [String] uri Algorithm URI
- # @return [OpenTox::Algorithm::Generic] Algorithm instance, nil if alogrithm was not found
- def self.find(uri, subjectid)
+ # @return [OpenTox::Algorithm::Generic] Algorithm instance
+ def self.find(uri, subjectid=nil)
return nil unless uri
alg = Generic.new(uri)
alg.load_metadata( subjectid )
- if alg.metadata==nil or alg.metadata.size==0
- nil
- else
- alg
- end
+ raise "cannot load algorithm metadata" if alg.metadata==nil or alg.metadata.size==0
+ alg
end
end
diff --git a/lib/authorization.rb b/lib/authorization.rb
index 12be037..16f1ee4 100644
--- a/lib/authorization.rb
+++ b/lib/authorization.rb
@@ -192,10 +192,10 @@ module OpenTox
# return [Boolean] returns true if policy is created
def self.create_policy(policy, subjectid)
begin
-# resource = RestClient::Resource.new("#{AA_SERVER}/Pol/opensso-pol")
+ resource = RestClient::Resource.new("#{AA_SERVER}/Pol/opensso-pol")
LOGGER.debug "OpenTox::Authorization.create_policy policy: #{policy[168,43]} with token:" + subjectid.to_s + " length: " + subjectid.length.to_s
-# return true if resource.post(policy, :subjectid => subjectid, :content_type => "application/xml")
- return true if RestClientWrapper.post("#{AA_SERVER}/pol", {:subjectid => subjectid, :content_type => "application/xml"}, policy)
+ return true if resource.post(policy, :subjectid => subjectid, :content_type => "application/xml")
+ #return true if RestClientWrapper.post("#{AA_SERVER}/pol", {:subjectid => subjectid, :content_type => "application/xml"}, policy)
rescue
return false
end
@@ -306,7 +306,6 @@ module OpenTox
# if no policy exists, create a policy, return result of send policy
send_policy(uri, subjectid)
else
- LOGGER.debug "OpenTox::Authorization.check_policy URI: #{uri} has already a Policy."
# if policy exists check for POST rights
if authorize(uri, "POST", subjectid)
true
@@ -356,7 +355,6 @@ module OpenTox
def self.free_uri?(uri, request_method)
if CONFIG[:authorization][:free_uris]
CONFIG[:authorization][:free_uris].each do |request_methods,uris|
- LOGGER.info "free uris "+request_methods.inspect+" -> "+uris.inspect
if request_methods and uris and request_methods.include?(request_method.to_sym)
uris.each do |u|
return true if u.match uri
@@ -380,9 +378,6 @@ module OpenTox
return false
end
-
-
-
end
end
diff --git a/lib/dataset.rb b/lib/dataset.rb
index 9c20968..02b89cb 100644
--- a/lib/dataset.rb
+++ b/lib/dataset.rb
@@ -56,6 +56,19 @@ module OpenTox
dataset.load_all(subjectid)
dataset
end
+
+ # replaces find as exist check, takes not as long, does NOT raise an un-authorized exception
+ # @param [String] uri Dataset URI
+ # @return [Boolean] true if dataset exists and user has get rights, false else
+ def self.exist?(uri, subjectid=nil)
+ return false unless uri
+ dataset = Dataset.new(uri, subjectid)
+ begin
+ dataset.load_metadata( subjectid ).size > 0
+ rescue
+ false
+ end
+ end
# Get all datasets from a service
# @param [optional,String] uri URI of the dataset service, defaults to service specified in configuration
@@ -285,7 +298,7 @@ module OpenTox
@compounds.uniq!
if @uri
if (CONFIG[:yaml_hosts].include?(URI.parse(@uri).host))
- RestClientWrapper.post(@uri,{:content_type => "application/x-yaml", :subjectid => subjectid},self.to_yaml)
+ RestClientWrapper.post(@uri,self.to_yaml,{:content_type => "application/x-yaml", :subjectid => subjectid})
else
File.open("ot-post-file.rdf","w+") { |f| f.write(self.to_rdfxml); @path = f.path }
task_uri = RestClient.post(@uri, {:file => File.new(@path)},{:accept => "text/uri-list" , :subjectid => subjectid}).to_s.chomp
diff --git a/lib/environment.rb b/lib/environment.rb
index 203ebc6..b30b3f3 100644
--- a/lib/environment.rb
+++ b/lib/environment.rb
@@ -54,8 +54,8 @@ else
end
# Regular expressions for parsing classification data
-TRUE_REGEXP = /^(true|active|1|1.0)$/i
-FALSE_REGEXP = /^(false|inactive|0|0.0)$/i
+TRUE_REGEXP = /^(true|active|1|1.0|tox)$/i
+FALSE_REGEXP = /^(false|inactive|0|0.0|low tox)$/i
# Task durations
DEFAULT_TASK_MAX_DURATION = 36000
diff --git a/lib/error.rb b/lib/error.rb
index 8c666f3..d086928 100644
--- a/lib/error.rb
+++ b/lib/error.rb
@@ -18,6 +18,10 @@ module OpenTox
class NotFoundError < RuntimeError
def http_code; 404; end
end
+
+ class ServiceUnavailableError < RuntimeError
+ def http_code; 503; end
+ end
class RestCallError < RuntimeError
attr_accessor :rest_params
@@ -28,18 +32,31 @@ module OpenTox
# TODO replace params with URIs (errorCause -> OT.errorCause)
attr_reader :message, :actor, :errorCause, :http_code, :errorDetails, :errorType
+
+ private
+ def initialize( http_code, erroType, message, actor, errorCause, rest_params=nil, backtrace=nil )
+ @http_code = http_code
+ @errorType = erroType
+ @message = message
+ @actor = actor
+ @errorCause = errorCause
+ @rest_params = rest_params
+ @backtrace = backtrace
+ end
+ public
# creates a error report object, from an ruby-exception object
- # @param [Exception] error
- # @param [String] actor, URI of the call that cause the error
- def initialize( error, actor )
- @http_code = error.http_code
- @errorType = error.class.to_s
- @message = error.message
- @actor = actor
- @errorCause = error.errorCause if error.errorCause
- @rest_params = error.rest_params if error.is_a?(OpenTox::RestCallError) and error.rest_params
- @backtrace = error.backtrace.short_backtrace if CONFIG[:backtrace]
+ # @param [Exception] error
+ # @param [String] actor, URI of the call that cause the error
+ def self.create( error, actor )
+ rest_params = error.rest_params if error.is_a?(OpenTox::RestCallError) and error.rest_params
+ backtrace = error.backtrace.short_backtrace if CONFIG[:backtrace]
+ ErrorReport.new( error.http_code, error.class.to_s, error.message, actor, error.errorCause, rest_params, backtrace )
+ end
+
+ def self.from_rdf(rdf)
+ metadata = OpenTox::Parser::Owl.metadata_from_rdf( rdf, OT.ErrorReport )
+ ErrorReport.new(metadata[OT.statusCode], metadata[OT.errorCode], metadata[OT.message], metadata[OT.actor], metadata[OT.errorCause])
end
# overwrite sorting to make easier readable
diff --git a/lib/helper.rb b/lib/helper.rb
index 0bb489c..6ca3901 100644
--- a/lib/helper.rb
+++ b/lib/helper.rb
@@ -28,8 +28,9 @@ helpers do
#cleans URI from querystring and file-extension. Sets port 80 to emptystring
# @param [String] uri
def clean_uri(uri)
+ uri = uri.sub(" ", "%20")
out = URI.parse(uri)
- out.path = out.path[0, out.path.rindex(/[0-9]/) + 1] if out.path.rindex(/[0-9]/) #cuts after id for a&a
+ out.path = out.path[0, out.path.index(/[0-9]/)] if out.path.index(/[0-9]/) #cuts after id for a&a
"#{out.scheme}:" + (out.port != 80 ? out.port : "") + "//#{out.host}#{out.path.chomp('/')}"
end
@@ -51,7 +52,7 @@ before do
subjectid = CGI.unescape(subjectid) if subjectid.include?("%23")
@subjectid = subjectid
rescue
- LOGGER.debug "OpenTox ruby api wrapper: helper before filter: NO subjectid for URI: #{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}#{request.env['REQUEST_URI']}"
+ #LOGGER.debug "OpenTox ruby api wrapper: helper before filter: NO subjectid for URI: #{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}#{request.env['REQUEST_URI']}"
subjectid = ""
end
@subjectid = subjectid
diff --git a/lib/model.rb b/lib/model.rb
index 0073ea4..64d178f 100644
--- a/lib/model.rb
+++ b/lib/model.rb
@@ -17,25 +17,22 @@ module OpenTox
end
end
LOGGER.info "running model "+@uri.to_s+", params: "+params.inspect+", accept: "+accept_header.to_s
- RestClientWrapper.post(@uri,{:accept => accept_header},params,waiting_task).to_s
+ RestClientWrapper.post(@uri,params,{:accept => accept_header},waiting_task).to_s
end
# Generic OpenTox model class for all API compliant services
class Generic
include Model
- # Find Generic Opentox Model via URI, and loads metadata
+ # Find Generic Opentox Model via URI, and loads metadata, could raise NotFound/NotAuthorized error
# @param [String] uri Model URI
- # @return [OpenTox::Model::Generic] Model instance, nil if model was not found
+ # @return [OpenTox::Model::Generic] Model instance
def self.find(uri,subjectid=nil)
return nil unless uri
model = Generic.new(uri)
model.load_metadata(subjectid)
- if model.metadata==nil or model.metadata.size==0
- nil
- else
- model
- end
+ raise "could not load model metadata '"+uri.to_s+"'" if model.metadata==nil or model.metadata.size==0
+ model
end
# provides feature type, possible types are "regression" or "classification"
@@ -46,7 +43,7 @@ module OpenTox
@algorithm = OpenTox::Algorithm::Generic.find(@metadata[OT.algorithm], subjectid) unless @algorithm
algorithm_title = @algorithm ? @algorithm.metadata[DC.title] : nil
- @dependentVariable = OpenTox::Feature.find( @metadata[OT.dependentVariables], subjectid) unless @dependentVariable
+ @dependentVariable = OpenTox::Feature.find( @metadata[OT.dependentVariables],subjectid ) unless @dependentVariable
[@dependentVariable.feature_type, @metadata[OT.isA], @metadata[DC.title], @uri, algorithm_title].each do |type|
case type
@@ -303,7 +300,7 @@ module OpenTox
# Save model at model service
def save(subjectid)
- self.uri = RestClientWrapper.post(@uri,{:content_type => "application/x-yaml", :subjectid => subjectid},self.to_yaml)
+ self.uri = RestClientWrapper.post(@uri,self.to_yaml,{:content_type => "application/x-yaml", :subjectid => subjectid})
end
# Delete model at model service
diff --git a/lib/opentox.rb b/lib/opentox.rb
index f1af5c3..1992896 100644
--- a/lib/opentox.rb
+++ b/lib/opentox.rb
@@ -43,5 +43,10 @@ module OpenTox
s.to_rdfxml
end
+ # deletes the resource, deletion should have worked when no RestCallError raised
+ def delete(subjectid=nil)
+ RestClientWrapper.delete(uri,:subjectid => subjectid)
+ end
+
end
diff --git a/lib/overwrite.rb b/lib/overwrite.rb
index e52618c..7b53122 100644
--- a/lib/overwrite.rb
+++ b/lib/overwrite.rb
@@ -16,13 +16,12 @@ before {
# IMPT: set sinatra settings :show_exceptions + :raise_errors to false in config.ru, otherwise Rack::Showexceptions takes over
error Exception do
error = request.env['sinatra.error']
- # log error to logfile
+ # log error message and backtrace to logfile
LOGGER.error error.class.to_s+": "+error.message
- # log backtrace only if code is 500 -> unwanted (Runtime)Exceptions and internal errors (see error.rb)
- LOGGER.error ":\n"+error.backtrace.join("\n") if error.http_code==500
+ LOGGER.error ":\n"+error.backtrace.join("\n")
actor = "#{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}#{request.env['REQUEST_URI']}"
- rep = OpenTox::ErrorReport.new(error, actor)
+ rep = OpenTox::ErrorReport.create(error, actor)
case request.env['HTTP_ACCEPT']
when /rdf/
@@ -37,6 +36,27 @@ error Exception do
end
end
+class Sinatra::Base
+
+ def return_task( task )
+ code = task.running? ? 202 : 200
+ case request.env['HTTP_ACCEPT']
+ when /rdf/
+ response['Content-Type'] = "application/rdf+xml"
+ halt code,task.to_rdfxml
+ when /yaml/
+ response['Content-Type'] = "application/rdf+xml"
+ halt code,task.to_yaml # PENDING differs from task-webservice
+ when /html/
+ response['Content-Type'] = "text/html"
+ halt code,OpenTox.text_to_html(task.to_yaml)
+ else # default /uri-list/
+ response['Content-Type'] = "text/uri-list"
+ halt code,task.uri+"\n"
+ end
+ end
+end
+
class String
def task_uri?
self.uri? && !self.match(/task/).nil?
diff --git a/lib/parser.rb b/lib/parser.rb
index a913cf2..1a872a0 100644
--- a/lib/parser.rb
+++ b/lib/parser.rb
@@ -36,10 +36,18 @@ module OpenTox
else
uri = @uri
end
- uri += "?subjectid=#{CGI.escape(subjectid)}" if subjectid
+ # avoid using rapper directly because of 2 reasons:
+ # * http errors wont be noticed
+ # * subjectid cannot be sent as header
+ ##uri += "?subjectid=#{CGI.escape(subjectid)}" if subjectid
+ ## `rapper -i rdfxml -o ntriples #{uri} 2>/dev/null`.each_line do |line|
+ file = Tempfile.new("ot-rdfxml")
+ file.puts OpenTox::RestClientWrapper.get @uri,{:subjectid => subjectid,:accept => "application/rdf+xml"}
+ file.close
+ file = "file://"+file.path
statements = []
parameter_ids = []
- `rapper -i rdfxml -o ntriples #{uri} 2>/dev/null`.each_line do |line|
+ `rapper -i rdfxml -o ntriples #{file} 2>/dev/null`.each_line do |line|
triple = line.to_triple
@metadata[triple[1]] = triple[2].split('^^').first if triple[0] == @uri and triple[1] != RDF['type']
statements << triple
@@ -55,6 +63,38 @@ module OpenTox
end
@metadata
end
+
+ # loads metadata from rdf-data
+ # @param [String] rdf
+ # @param [String] type of the info (e.g. OT.Task, OT.ErrorReport) needed to get the subject-uri
+ # @return [Hash] metadata
+ def self.metadata_from_rdf( rdf, type )
+ # write to file and read convert with rapper into tripples
+ file = Tempfile.new("ot-rdfxml")
+ file.puts rdf
+ file.close
+ file = "file://"+file.path
+ #puts "cmd: rapper -i rdfxml -o ntriples #{file} 2>/dev/null"
+ triples = `rapper -i rdfxml -o ntriples #{file} 2>/dev/null`
+
+ # load uri via type
+ uri = nil
+ triples.each_line do |line|
+ triple = line.to_triple
+ if triple[1] == RDF['type'] and triple[2]==type
+ raise "uri already set, two uris found with type: "+type.to_s if uri
+ uri = triple[0]
+ end
+ end
+
+ # load metadata
+ metadata = {}
+ triples.each_line do |line|
+ triple = line.to_triple
+ metadata[triple[1]] = triple[2].split('^^').first if triple[0] == uri and triple[1] != RDF['type']
+ end
+ metadata
+ end
# Generic parser for all OpenTox classes
class Generic
diff --git a/lib/rest_client_wrapper.rb b/lib/rest_client_wrapper.rb
index 7c2d719..658f111 100644
--- a/lib/rest_client_wrapper.rb
+++ b/lib/rest_client_wrapper.rb
@@ -14,21 +14,21 @@ module OpenTox
# @param [optional,OpenTox::Task] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
# @param [wait,Boolean] wait set to false to NOT wait for task if result is task
# @return [OpenTox::WrapperResult] a String containing the result-body of the REST call
- def self.get(uri, headers=nil, waiting_task=nil, wait=true )
- execute( "get", uri, headers, nil, waiting_task, wait)
+ def self.get(uri, headers={}, waiting_task=nil, wait=true )
+ execute( "get", uri, nil, headers, waiting_task, wait)
end
# performs a POST REST call
# raises OpenTox::Error if call fails (rescued in overwrite.rb -> halt 502)
# per default: waits for Task to finish and returns result URI of Task
# @param [String] uri destination URI
- # @param [optional,Hash] headers contains params like accept-header
# @param [optional,String] payload data posted to the service
+ # @param [optional,Hash] headers contains params like accept-header
# @param [optional,OpenTox::Task] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
# @param [wait,Boolean] wait set to false to NOT wait for task if result is task
# @return [OpenTox::WrapperResult] a String containing the result-body of the REST call
- def self.post(uri, headers, payload=nil, waiting_task=nil, wait=true )
- execute( "post", uri, headers, payload, waiting_task, wait )
+ def self.post(uri, payload=nil, headers={}, waiting_task=nil, wait=true )
+ execute( "post", uri, payload, headers, waiting_task, wait )
end
# performs a PUT REST call
@@ -37,8 +37,8 @@ module OpenTox
# @param [optional,Hash] headers contains params like accept-header
# @param [optional,String] payload data put to the service
# @return [OpenTox::WrapperResult] a String containing the result-body of the REST call
- def self.put(uri, headers, payload=nil )
- execute( "put", uri, headers, payload )
+ def self.put(uri, payload=nil, headers={} )
+ execute( "put", uri, payload, headers )
end
# performs a DELETE REST call
@@ -47,36 +47,42 @@ module OpenTox
# @param [optional,Hash] headers contains params like accept-header
# @return [OpenTox::WrapperResult] a String containing the result-body of the REST call
def self.delete(uri, headers=nil )
- execute( "delete", uri, headers, nil)
+ execute( "delete", uri, nil, headers)
end
private
- def self.execute( rest_call, uri, headers, payload=nil, waiting_task=nil, wait=true )
+ def self.execute( rest_call, uri, payload=nil, headers={}, waiting_task=nil, wait=true )
raise OpenTox::BadRequestError.new "uri is null" unless uri
raise OpenTox::BadRequestError.new "not a uri: "+uri.to_s unless uri.to_s.uri?
- raise OpenTox::BadRequestError.new "headers are no hash: "+headers.inspect unless headers==nil or headers.is_a?(Hash)
- raise OpenTox::BadRequestError.new "nil headers for post not allowed, use {}" if rest_call=="post" and headers==nil
+ raise "headers are no hash: "+headers.inspect unless headers==nil or headers.is_a?(Hash)
+ raise OpenTox::BadRequestError.new "accept should go into the headers" if payload and payload.is_a?(Hash) and payload[:accept]
+ raise OpenTox::BadRequestError.new "content_type should go into the headers" if payload and payload.is_a?(Hash) and payload[:content_type]
+ raise "__waiting_task__ must be 'nil' or '(sub)task', is "+waiting_task.class.to_s if
+ waiting_task!=nil and !(waiting_task.is_a?(Task) || waiting_task.is_a?(SubTask))
headers.each{ |k,v| headers.delete(k) if v==nil } if headers #remove keys with empty values, as this can cause problems
+ # PENDING needed for NUTA, until we finally agree on how to send subjectid
+ headers[:subjectid] = payload.delete(:subjectid) if uri=~/ntua/ and payload and payload.is_a?(Hash) and payload.has_key?(:subjectid)
+
begin
#LOGGER.debug "RestCall: "+rest_call.to_s+" "+uri.to_s+" "+headers.inspect+" "+payload.inspect
- resource = RestClient::Resource.new(uri,{:timeout => 60})
- if payload
+ resource = RestClient::Resource.new(uri,{:timeout => 60})
+ if rest_call=="post" || rest_call=="put"
result = resource.send(rest_call, payload, headers)
- elsif headers
- result = resource.send(rest_call, headers)
else
- result = resource.send(rest_call)
+ result = resource.send(rest_call, headers)
end
+ # PENDING NTUA does return errors with 200
+ raise RestClient::ExceptionWithResponse.new(result) if uri=~/ntua/ and result.body =~ /about.*http:\/\/anonymous.org\/error/
+
# result is a string, with the additional fields content_type and code
res = WrapperResult.new(result.body)
res.content_type = result.headers[:content_type]
raise "content-type not set" unless res.content_type
res.code = result.code
- #LOGGER.debug "RestCall result: "+res.to_s+" "+res.code.to_s+" "+res.content_type.to_s
# TODO: Ambit returns task representation with 200 instead of result URI
return res if res.code==200 || !wait
@@ -87,10 +93,10 @@ module OpenTox
return res
rescue RestClient::RequestTimeout => ex
- received_error ex.message, 408, nil, {:rest_uri => uri, :headers => headers}
+ received_error ex.message, 408, nil, {:rest_uri => uri, :headers => headers, :payload => payload}
rescue RestClient::ExceptionWithResponse => ex
# error comming from a different webservice,
- received_error ex.http_body, ex.http_code, ex.response.net_http_res.content_type, {:rest_uri => uri, :headers => headers}
+ received_error ex.http_body, ex.http_code, ex.response.net_http_res.content_type, {:rest_uri => uri, :headers => headers, :payload => payload}
rescue OpenTox::RestCallError => ex
# already a rest-error, probably comes from wait_for_task, just pass through
raise ex
diff --git a/lib/task.rb b/lib/task.rb
index 74940de..1a684df 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -33,7 +33,7 @@ module OpenTox
def self.create( title=nil, creator=nil, max_duration=DEFAULT_TASK_MAX_DURATION, description=nil )
params = {:title=>title, :creator=>creator, :max_duration=>max_duration, :description=>description }
- task_uri = RestClientWrapper.post(CONFIG[:services]["opentox-task"], params, nil, false).to_s
+ task_uri = RestClientWrapper.post(CONFIG[:services]["opentox-task"], params, {}, nil, false).to_s
task = Task.new(task_uri.chomp)
# measure current memory consumption
@@ -64,9 +64,8 @@ module OpenTox
task.completed(result)
rescue => error
LOGGER.error "task failed: "+error.class.to_s+": "+error.message
- # log backtrace only if code is 500 -> unwanted (Runtime)Exceptions and internal errors (see error.rb)
- LOGGER.error ":\n"+error.backtrace.join("\n") if error.http_code==500
- task.error(OpenTox::ErrorReport.new(error, creator))
+ LOGGER.error ":\n"+error.backtrace.join("\n")
+ task.error(OpenTox::ErrorReport.create(error, creator))
end
end
task.pid = task_pid
@@ -81,9 +80,20 @@ module OpenTox
return nil unless uri
task = Task.new(uri)
task.load_metadata
+ raise "could not load task metadata" if task.metadata==nil or task.metadata.size==0
task
end
+ # Find a task for querying, status changes
+ # @param [String] uri Task URI
+ # @return [OpenTox::Task] Task object
+ def self.exist?(uri)
+ begin
+ return find(uri)
+ rescue
+ end
+ end
+
# Get a list of all tasks
# @param [optional, String] uri URI of task service
# @return [text/uri-list] Task URIs
@@ -188,7 +198,7 @@ module OpenTox
# create is private now, use OpenTox::Task.as_task
#def self.create( params )
- #task_uri = RestClientWrapper.post(CONFIG[:services]["opentox-task"], params, nil, false).to_s
+ #task_uri = RestClientWrapper.post(CONFIG[:services]["opentox-task"], params, {}, false).to_s
#Task.find(task_uri.chomp)
#end
@@ -304,7 +314,7 @@ module OpenTox
class SubTask
def initialize(task, min, max)
- raise "not a task or subtask" unless task.is_a?(Task) or task.is_a?(SubTask)
+ raise "not a task or subtask" if task!=nil and !(task.is_a?(Task) or task.is_a?(SubTask))
raise "invalid max ("+max.to_s+"), min ("+min.to_s+") params" unless
min.is_a?(Numeric) and max.is_a?(Numeric) and min >= 0 and max <= 100 and max > min
@task = task
diff --git a/lib/validation.rb b/lib/validation.rb
index 23b246b..2ea19a9 100644
--- a/lib/validation.rb
+++ b/lib/validation.rb
@@ -1,70 +1,196 @@
module OpenTox
- class Validation
+ class Validation
include OpenTox
-
- attr_accessor :report_uri, :qmrf_report_uri
-
- def self.create_crossvalidation(params)
- params[:uri] = File.join(CONFIG[:services]['opentox-validation'], "crossvalidation")
- params[:num_folds] = 10 unless params[:num_folds]
- params[:random_seed] = 2 unless params[:random_seed]
- params[:stratified] = false unless params[:stratified]
- uri = OpenTox::RestClientWrapper.post(File.join(CONFIG[:services]["opentox-validation"],"/crossvalidation"),params,nil,false)
- OpenTox::Validation.new(uri)
- end
-
- def create_report(subjectid=nil)
- @report_uri = OpenTox::RestClientWrapper.post(File.join(CONFIG[:services]["opentox-validation"],"/report/crossvalidation"), {:validation_uris => @uri, :subjectid => subjectid}).to_s
- @report_uri
+
+ # find validation, raises error if not found
+ # @param [String] uri
+ # @param [String,optional] subjectid
+ # @return [OpenTox::Validation]
+ def self.find( uri, subjectid=nil )
+ val = Validation.new(uri)
+ val.load_metadata( subjectid )
+ val
end
-
- def create_qmrf_report(subjectid=nil)
- @qmrf_report_uri = OpenTox::RestClientWrapper.post(File.join(CONFIG[:services]["opentox-validation"],"/reach_report/qmrf"), {:model_uri => @uri, :subjectid => subjectid}).to_s
- @qmrf_report_uri
+
+ # creates a validation object from crossvaldiation statistics, raise error if not found
+ # (as crossvaldiation statistics are returned as an average valdidation over all folds)
+ # @param [String] crossvalidation uri
+ # @param [String,optional] subjectid
+ # @return [OpenTox::Validation]
+ def self.from_cv_statistics( crossvalidation_uri, subjectid=nil )
+ find( File.join(crossvalidation_uri, 'statistics'),subjectid )
end
-
- def summary(type, subjectid=nil)
- v = YAML.load OpenTox::RestClientWrapper.get(File.join(@uri, 'statistics'),{:accept => "application/x-yaml", :subjectid => subjectid}).to_s
-
- case type
- when "classification"
- tp=0; tn=0; fp=0; fn=0; n=0
- v[:classification_statistics][:confusion_matrix][:confusion_matrix_cell].each do |cell|
- if cell[:confusion_matrix_predicted] == "true" and cell[:confusion_matrix_actual] == "true"
- tp = cell[:confusion_matrix_value]
- n += tp
- elsif cell[:confusion_matrix_predicted] == "false" and cell[:confusion_matrix_actual] == "false"
- tn = cell[:confusion_matrix_value]
- n += tn
- elsif cell[:confusion_matrix_predicted] == "false" and cell[:confusion_matrix_actual] == "true"
- fn = cell[:confusion_matrix_value]
- n += fn
- elsif cell[:confusion_matrix_predicted] == "true" and cell[:confusion_matrix_actual] == "false"
- fp = cell[:confusion_matrix_value]
- n += fp
+
+ # loads metadata via yaml from validation object
+ # fields (like for example the validated model) can be acces via validation.metadata[OT.model]
+ def load_metadata( subjectid=nil )
+ @metadata = YAML.load(OpenTox::RestClientWrapper.get(uri,{:subjectid => subjectid, :accept => "application/x-yaml"}))
+ end
+
+ # PENDING: creates summary as used for ToxCreate
+ def summary
+ if @metadata[OT.classificationStatistics]
+ res = {
+ :nr_predictions => @metadata[OT.numInstances] - @metadata[OT.numUnpredicted],
+ :correct_predictions => @metadata[OT.classificationStatistics][OT.percentCorrect],
+ :weighted_area_under_roc => @metadata[OT.classificationStatistics][OT.weightedAreaUnderRoc],
+ }
+ @metadata[OT.classificationStatistics][OT.classValueStatistics].each do |s|
+ if s[OT.classValue].to_s=="true"
+ res[:true_positives] = s[OT.numTruePositives]
+ res[:false_positives] = s[OT.numFalsePositives]
+ res[:true_negatives] = s[OT.numTrueNegatives]
+ res[:false_negatives] = s[OT.numFalseNegatives]
+ res[:sensitivity] = s[OT.truePositiveRate]
+ res[:specificity] = s[OT.falsePositiveRate]
+ break
end
end
+ res
+ elsif @metadata[OT.regressionStatistics]
{
- :nr_predictions => n,
- :true_positives => tp,
- :false_positives => fp,
- :true_negatives => tn,
- :false_negatives => fn,
- :correct_predictions => 100*(tp+tn).to_f/n,
- :weighted_area_under_roc => v[:classification_statistics][:weighted_area_under_roc].to_f,
- :sensitivity => tp.to_f/(tp+fn),
- :specificity => tn.to_f/(tn+fp),
- }
- when "regression"
- {
- :nr_predictions => v[:num_instances] - v[:num_unpredicted],
- :r_square => v[:regression_statistics][:r_square],
- :root_mean_squared_error => v[:regression_statistics][:root_mean_squared_error],
- :mean_absolute_error => v[:regression_statistics][:mean_absolute_error],
+ :nr_predictions => @metadata[OT.numInstances] - @metadata[OT.numUnpredicted],
+ :r_square => @metadata[OT.regressionStatistics][OT.rSquare],
+ :root_mean_squared_error => @metadata[OT.regressionStatistics][OT.rootMeanSquaredError],
+ :mean_absolute_error => @metadata[OT.regressionStatistics][OT.meanAbsoluteError],
}
end
end
+ end
+
+ class Crossvalidation
+ include OpenTox
+
+ attr_reader :report
+
+ # find crossvalidation, raises error if not found
+ # @param [String] uri
+ # @param [String,optional] subjectid
+ # @return [OpenTox::Crossvalidation]
+ def self.find( uri, subjectid=nil )
+ cv = Crossvalidation.new(uri)
+ cv.load_metadata( subjectid )
+ cv
+ end
+
+ # creates a crossvalidations, waits until it finishes, may take some time
+ # @param [Hash] params (required:algorithm_uri,dataset_uri,prediction_feature, optional:algorithm_params,num_folds(10),random_seed(1),stratified(false))
+ # @param [String,optional] subjectid
+ # @param [OpenTox::Task,optional] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
+ # @return [OpenTox::Crossvalidation]
+ def self.create( params, subjectid=nil, waiting_task=nil )
+ params[:subjectid] = subjectid if subjectid
+ uri = OpenTox::RestClientWrapper.post( File.join(CONFIG[:services]["opentox-validation"],"crossvalidation"),
+ params,{:content_type => "text/uri-list"},waiting_task )
+ Crossvalidation.new(uri)
+ end
- end
+ # looks for report for this crossvalidation, creates a report if no report is found
+ # @param [String,optional] subjectid
+ # @param [OpenTox::Task,optional] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
+ # @return [OpenTox::CrossvalidationReport]
+ def find_or_create_report( subjectid=nil, waiting_task=nil )
+ @report = CrossvalidationReport.find_for_crossvalidation(@uri, subjectid) unless @report
+ @report = CrossvalidationReport.create(@uri, subjectid, waiting_task) unless @report
+ @report.uri
+ end
+
+ # loads metadata via yaml from crossvalidation object
+ # fields (like for example the validations) can be acces via validation.metadata[OT.validation]
+ def load_metadata( subjectid=nil )
+ @metadata = YAML.load(OpenTox::RestClientWrapper.get(uri,{:subjectid => subjectid, :accept => "application/x-yaml"}))
+ end
+
+ # PENDING: creates summary as used for ToxCreate
+ def summary( subjectid=nil )
+ Validation.from_cv_statistics( @uri, subjectid ).summary
+ end
+ end
+
+ class ValidationReport
+ include OpenTox
+
+ # finds ValidationReport for a particular validation
+ # @param [String] crossvalidation uri
+ # @param [String,optional] subjectid
+ # @return [OpenTox::ValidationReport] nil if no report found
+ def self.find_for_validation( validation_uri, subjectid=nil )
+ uris = RestClientWrapper.get(File.join(CONFIG[:services]["opentox-validation"],
+ "/report/validation?validation="+validation_uri), {:subjectid => subjectid}).chomp.split("\n")
+ uris.size==0 ? nil : ValidationReport.new(uris[-1])
+ end
+
+ end
+
+ class CrossvalidationReport
+ include OpenTox
+
+ # finds CrossvalidationReport via uri, raises error if not found
+ # @param [String] uri
+ # @param [String,optional] subjectid
+ # @return [OpenTox::CrossvalidationReport]
+ def self.find( uri, subjectid=nil )
+ # PENDING load report data?
+ OpenTox::RestClientWrapper.get(uri,{:subjectid => subjectid})
+ CrossvalidationReport.new(uri)
+ end
+
+ # finds CrossvalidationReport for a particular crossvalidation
+ # @param [String] crossvalidation uri
+ # @param [String,optional] subjectid
+ # @return [OpenTox::CrossvalidationReport] nil if no report found
+ def self.find_for_crossvalidation( crossvalidation_uri, subjectid=nil )
+ uris = RestClientWrapper.get(File.join(CONFIG[:services]["opentox-validation"],
+ "/report/crossvalidation?crossvalidation="+crossvalidation_uri), {:subjectid => subjectid}).chomp.split("\n")
+ uris.size==0 ? nil : CrossvalidationReport.new(uris[-1])
+ end
+
+ # creates a crossvalidation report via crossvalidation
+ # @param [String] crossvalidation uri
+ # @param [String,optional] subjectid
+ # @param [OpenTox::Task,optional] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
+ # @return [OpenTox::CrossvalidationReport]
+ def self.create( crossvalidation_uri, subjectid=nil, waiting_task=nil )
+ uri = RestClientWrapper.post(File.join(CONFIG[:services]["opentox-validation"],"/report/crossvalidation"),
+ { :validation_uris => crossvalidation_uri, :subjectid => subjectid }, {}, waiting_task )
+ CrossvalidationReport.new(uri)
+ end
+ end
+
+ class QMRFReport
+ include OpenTox
+
+ # finds QMRFReport, raises Error if not found
+ # @param [String] uri
+ # @param [String,optional] subjectid
+ # @return [OpenTox::QMRFReport]
+ def self.find( uri, subjectid=nil )
+ # PENDING load crossvalidation data?
+ OpenTox::RestClientWrapper.get(uri,{:subjectid => subjectid})
+ QMRFReport.new(uri)
+ end
+
+ # finds QMRF report for a particular model
+ # @param [String] model_uri
+ # @param [String,optional] subjectid
+ # @return [OpenTox::QMRFReport] nil if no report found
+ def self.find_for_model( model_uri, subjectid=nil )
+ uris = RestClientWrapper.get(File.join(CONFIG[:services]["opentox-validation"],
+ "/reach_report/qmrf?model="+model_uri), {:subjectid => subjectid}).chomp.split("\n")
+ uris.size==0 ? nil : QMRFReport.new(uris[-1])
+ end
+
+ # creates a qmrf report via model
+ # @param [String] model_uri
+ # @param [String,optional] subjectid
+ # @param [OpenTox::Task,optional] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
+ # @return [OpenTox::QMRFReport]
+ def self.create( model_uri, subjectid=nil, waiting_task=nil )
+ uri = RestClientWrapper.post(File.join(CONFIG[:services]["opentox-validation"],"/reach_report/qmrf"),
+ { :model_uri => model_uri, :subjectid => subjectid }, {}, waiting_task )
+ QMRFReport.new(uri)
+ end
+ end
+
end
--
cgit v1.2.3
From f907690dc7d3f82c75a51718a3abfa7750dedaa5 Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Tue, 8 Feb 2011 16:58:32 +0100
Subject: set waiting_for in task
---
lib/task.rb | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
(limited to 'lib')
diff --git a/lib/task.rb b/lib/task.rb
index ca18d7b..742afb4 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -139,7 +139,7 @@ module OpenTox
end
def cancel
- RestClientWrapper.put(File.join(@uri,'Cancelled'))
+ RestClientWrapper.put(File.join(@uri,'Cancelled'),{:cannot_be => "empty"})
load_metadata
end
@@ -237,6 +237,7 @@ module OpenTox
# @param [optional,Numeric] dur seconds pausing before cheking again for completion
def wait_for_completion( waiting_task=nil, dur=0.3)
+ waiting_task.waiting_for(self.uri) if waiting_task
due_to_time = Time.new + DEFAULT_TASK_MAX_DURATION
LOGGER.debug "start waiting for task "+@uri.to_s+" at: "+Time.new.to_s+", waiting at least until "+due_to_time.to_s
@@ -252,7 +253,7 @@ module OpenTox
raise "max wait time exceeded ("+DEFAULT_TASK_MAX_DURATION.to_s+"sec), task: '"+@uri.to_s+"'"
end
end
-
+ waiting_task.waiting_for(nil) if waiting_task
LOGGER.debug "Task '"+@metadata[OT.hasStatus].to_s+"': "+@uri.to_s+", Result: "+@metadata[OT.resultURI].to_s
end
@@ -268,6 +269,10 @@ module OpenTox
end
end
+ def waiting_for(task_uri)
+ RestClientWrapper.put(File.join(@uri,'Running'),{:waiting_for => task_uri})
+ end
+
private
def check_state
begin
@@ -321,6 +326,10 @@ module OpenTox
end
end
+ def waiting_for(task_uri)
+ @task.waiting_for(task_uri)
+ end
+
def progress(pct)
raise "no numeric >= 0 and <= 100 : '"+pct.to_s+"'" unless pct.is_a?(Numeric) and pct>=0 and pct<=100
#puts "subtask := "+pct.to_s+" -> task := "+(@min + @delta * pct.to_f * 0.01).to_s
--
cgit v1.2.3
From 9a523f0fb2d5ee0058af5b5b82e01f39549f68fb Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Wed, 9 Feb 2011 14:06:12 +0100
Subject: fix rdf parsing to work with ambit dataset service with a&a, minor
changes
---
lib/error.rb | 2 +-
lib/model.rb | 9 +++++----
lib/parser.rb | 41 +++++++++++++++++++++++++++--------------
lib/rest_client_wrapper.rb | 13 ++++++++-----
lib/task.rb | 26 +++++++++-----------------
5 files changed, 50 insertions(+), 41 deletions(-)
(limited to 'lib')
diff --git a/lib/error.rb b/lib/error.rb
index 49756d5..7ca9767 100644
--- a/lib/error.rb
+++ b/lib/error.rb
@@ -55,7 +55,7 @@ module OpenTox
end
def self.from_rdf(rdf)
- metadata = OpenTox::Parser::Owl.metadata_from_rdf( rdf, OT.ErrorReport )
+ metadata = OpenTox::Parser::Owl.from_rdf( rdf, OT.ErrorReport ).metadata
ErrorReport.new(metadata[OT.statusCode], metadata[OT.errorCode], metadata[OT.message], metadata[OT.actor], metadata[OT.errorCause])
end
diff --git a/lib/model.rb b/lib/model.rb
index 64d178f..9622d65 100644
--- a/lib/model.rb
+++ b/lib/model.rb
@@ -43,9 +43,11 @@ module OpenTox
@algorithm = OpenTox::Algorithm::Generic.find(@metadata[OT.algorithm], subjectid) unless @algorithm
algorithm_title = @algorithm ? @algorithm.metadata[DC.title] : nil
+ algorithm_type = @algorithm ? @algorithm.metadata[OT.isA] : nil
@dependentVariable = OpenTox::Feature.find( @metadata[OT.dependentVariables],subjectid ) unless @dependentVariable
-
- [@dependentVariable.feature_type, @metadata[OT.isA], @metadata[DC.title], @uri, algorithm_title].each do |type|
+ type_indicators = [@dependentVariable.feature_type, @metadata[OT.isA], @metadata[DC.title],
+ @uri, algorithm_type, algorithm_title]
+ type_indicators.each do |type|
case type
when /(?i)classification/
return "classification"
@@ -53,8 +55,7 @@ module OpenTox
return "regression"
end
end
- raise "unknown model "+[@dependentVariable.feature_type, @metadata[OT.isA],
- @metadata[DC.title], @uri, algorithm_title].inspect
+ raise "unknown model "+type_indicators.inspect
end
end
diff --git a/lib/parser.rb b/lib/parser.rb
index 27dfeee..2f59d15 100644
--- a/lib/parser.rb
+++ b/lib/parser.rb
@@ -41,17 +41,17 @@ module OpenTox
##uri += "?subjectid=#{CGI.escape(subjectid)}" if subjectid
## `rapper -i rdfxml -o ntriples #{uri} 2>/dev/null`.each_line do |line|
file = Tempfile.new("ot-rdfxml")
- file.puts OpenTox::RestClientWrapper.get @uri,{:subjectid => subjectid,:accept => "application/rdf+xml"}
+ file.puts OpenTox::RestClientWrapper.get @uri,{:subjectid => subjectid,:accept => "application/rdf+xml"},nil,false
file.close
- file = "file://"+file.path
statements = []
parameter_ids = []
- `rapper -i rdfxml -o ntriples #{file} 2>/dev/null`.each_line do |line|
+ `rapper -i rdfxml -o ntriples file://#{file.path} 2>/dev/null`.each_line do |line|
triple = line.to_triple
@metadata[triple[1]] = triple[2].split('^^').first if triple[0] == @uri and triple[1] != RDF['type']
statements << triple
parameter_ids << triple[2] if triple[1] == OT.parameters
end
+ File.delete(file.path)
unless parameter_ids.empty?
@metadata[OT.parameters] = []
parameter_ids.each do |p|
@@ -63,18 +63,17 @@ module OpenTox
@metadata
end
- # loads metadata from rdf-data
+ # creates owl object from rdf-data
# @param [String] rdf
# @param [String] type of the info (e.g. OT.Task, OT.ErrorReport) needed to get the subject-uri
- # @return [Hash] metadata
- def self.metadata_from_rdf( rdf, type )
+ # @return [Owl] with uri and metadata set
+ def self.from_rdf( rdf, type )
# write to file and read convert with rapper into tripples
file = Tempfile.new("ot-rdfxml")
file.puts rdf
file.close
- file = "file://"+file.path
#puts "cmd: rapper -i rdfxml -o ntriples #{file} 2>/dev/null"
- triples = `rapper -i rdfxml -o ntriples #{file} 2>/dev/null`
+ triples = `rapper -i rdfxml -o ntriples file://#{file.path} 2>/dev/null`
# load uri via type
uri = nil
@@ -85,19 +84,23 @@ module OpenTox
uri = triple[0]
end
end
-
+ File.delete(file)
# load metadata
metadata = {}
triples.each_line do |line|
triple = line.to_triple
metadata[triple[1]] = triple[2].split('^^').first if triple[0] == uri and triple[1] != RDF['type']
end
- metadata
+ owl = Owl::Generic.new(uri)
+ owl.metadata = metadata
+ owl
end
-
+
# Generic parser for all OpenTox classes
class Generic
include Owl
+
+ attr_accessor :uri, :metadata
end
# OWL-DL parser for datasets
@@ -128,12 +131,21 @@ module OpenTox
# @return [Hash] Internal dataset representation
def load_uri(subjectid=nil)
uri = @uri
- uri += "?subjectid=#{CGI.escape(subjectid)}" if subjectid
+
+ # avoid using rapper directly because of 2 reasons:
+ # * http errors wont be noticed
+ # * subjectid cannot be sent as header
+ ##uri += "?subjectid=#{CGI.escape(subjectid)}" if subjectid
+ ##`rapper -i rdfxml -o ntriples #{file} 2>/dev/null`.each_line do |line|
+ file = Tempfile.new("ot-rdfxml")
+ file.puts OpenTox::RestClientWrapper.get @uri,{:subjectid => subjectid,:accept => "application/rdf+xml"},nil,false
+ file.close
+
data = {}
feature_values = {}
feature = {}
other_statements = {}
- `rapper -i rdfxml -o ntriples #{uri} 2>/dev/null`.each_line do |line|
+ `rapper -i rdfxml -o ntriples file://#{file.path} 2>/dev/null`.each_line do |line|
triple = line.chomp.split(' ',3)
triple = triple[0..2].collect{|i| i.sub(/\s+.$/,'').gsub(/[<>"]/,'')}
case triple[1]
@@ -150,6 +162,7 @@ module OpenTox
else
end
end
+ File.delete(file.path)
data.each do |id,entry|
entry[:values].each do |value_id|
value = feature_values[value_id].split(/\^\^/).first # remove XSD.type
@@ -157,7 +170,7 @@ module OpenTox
end
end
load_features
- @dataset.metadata = load_metadata
+ @dataset.metadata = load_metadata(subjectid)
@dataset
end
diff --git a/lib/rest_client_wrapper.rb b/lib/rest_client_wrapper.rb
index 658f111..fcc0d08 100644
--- a/lib/rest_client_wrapper.rb
+++ b/lib/rest_client_wrapper.rb
@@ -61,9 +61,8 @@ module OpenTox
raise "__waiting_task__ must be 'nil' or '(sub)task', is "+waiting_task.class.to_s if
waiting_task!=nil and !(waiting_task.is_a?(Task) || waiting_task.is_a?(SubTask))
headers.each{ |k,v| headers.delete(k) if v==nil } if headers #remove keys with empty values, as this can cause problems
-
- # PENDING needed for NUTA, until we finally agree on how to send subjectid
- headers[:subjectid] = payload.delete(:subjectid) if uri=~/ntua/ and payload and payload.is_a?(Hash) and payload.has_key?(:subjectid)
+ ## PENDING partner services accept subjectid only in header
+ headers[:subjectid] = payload.delete(:subjectid) if payload and payload.is_a?(Hash) and payload.has_key?(:subjectid)
begin
#LOGGER.debug "RestCall: "+rest_call.to_s+" "+uri.to_s+" "+headers.inspect+" "+payload.inspect
@@ -94,6 +93,8 @@ module OpenTox
rescue RestClient::RequestTimeout => ex
received_error ex.message, 408, nil, {:rest_uri => uri, :headers => headers, :payload => payload}
+ rescue Errno::ECONNREFUSED => ex
+ received_error ex.message, 500, nil, {:rest_uri => uri, :headers => headers, :payload => payload}
rescue RestClient::ExceptionWithResponse => ex
# error comming from a different webservice,
received_error ex.http_body, ex.http_code, ex.response.net_http_res.content_type, {:rest_uri => uri, :headers => headers, :payload => payload}
@@ -107,7 +108,9 @@ module OpenTox
end
def self.wait_for_task( res, base_uri, waiting_task=nil )
-
+ #TODO remove TUM hack
+ content_type = "text/uri-list" if base_uri =~/tu-muenchen/ and res.content_type == "application/x-www-form-urlencoded;charset=UTF-8"
+s
task = nil
case res.content_type
when /application\/rdf\+xml/
@@ -118,7 +121,7 @@ module OpenTox
raise "uri list has more than one entry, should be a task" if res.content_type=~/text\/uri-list/ and res.split("\n").size > 1 #if uri list contains more then one uri, its not a task
task = OpenTox::Task.find(res.to_s.chomp) if res.to_s.uri?
else
- raise "unknown content-type for task: '"+res.content_type.to_s+"'" #+"' content: "+res[0..200].to_s
+ raise "unknown content-type for task : '"+res.content_type.to_s+"'"+" content: "+res[0..200].to_s
end
LOGGER.debug "result is a task '"+task.uri.to_s+"', wait for completion"
diff --git a/lib/task.rb b/lib/task.rb
index 742afb4..27dc1c2 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -94,23 +94,11 @@ module OpenTox
def self.from_yaml(yaml)
@metadata = YAML.load(yaml)
end
-
def self.from_rdfxml(rdfxml)
- file = Tempfile.new("ot-rdfxml")
- file.puts rdfxml
- file.close
- file = "file://"+file.path
-
- # PENDING
- raise "Parse from file not working: what is the base-object-uri??? (omitted in triples)"
-
- parser = Parser::Owl::Generic.new file
- metadata = parser.load_metadata
- puts metadata.inspect
-
- task = Task.new(uri)
- task.add_metadata(metadata)
+ owl = OpenTox::Parser::Owl.from_rdf(rdfxml, OT.Task)
+ task = Task.new(owl.uri)
+ task.add_metadata(owl.metadata)
task
end
@@ -176,7 +164,7 @@ module OpenTox
end
def load_metadata
- if (CONFIG[:yaml_hosts].include?(URI.parse(uri).host))
+ if (CONFIG[:yaml_hosts].include?(URI.parse(@uri).host))
result = RestClientWrapper.get(@uri, {:accept => 'application/x-yaml'}, nil, false)
@metadata = YAML.load result.to_s
@http_code = result.code
@@ -184,6 +172,7 @@ module OpenTox
@metadata = Parser::Owl::Generic.new(@uri).load_metadata
@http_code = RestClientWrapper.get(uri, {:accept => 'application/rdf+xml'}, nil, false).code
end
+ raise "could not load task metadata for task "+@uri.to_s if @metadata==nil || @metadata.size==0
end
# create is private now, use OpenTox::Task.as_task
@@ -274,11 +263,14 @@ module OpenTox
end
private
+ VALID_TASK_STATES = ["Cancelled", "Completed", "Running", "Error"]
+
def check_state
begin
+ raise "illegal task state, invalid status: '"+@metadata[OT.hasStatus].to_s+"'" unless
+ @metadata[OT.hasStatus] unless VALID_TASK_STATES.include?(@metadata[OT.hasStatus])
raise "illegal task state, task is completed, resultURI is no URI: '"+@metadata[OT.resultURI].to_s+
"'" unless @metadata[OT.resultURI] and @metadata[OT.resultURI].to_s.uri? if completed?
-
if @http_code == 202
raise "#{@uri}: illegal task state, code is 202, but hasStatus is not Running: '"+@metadata[OT.hasStatus]+"'" unless running?
elsif @http_code == 201
--
cgit v1.2.3
From d83015ff26c43ecbb06553403589b35388b3e3e9 Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Wed, 9 Feb 2011 14:11:41 +0100
Subject: remove letter
---
lib/rest_client_wrapper.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/rest_client_wrapper.rb b/lib/rest_client_wrapper.rb
index fcc0d08..d0e6727 100644
--- a/lib/rest_client_wrapper.rb
+++ b/lib/rest_client_wrapper.rb
@@ -110,7 +110,7 @@ module OpenTox
def self.wait_for_task( res, base_uri, waiting_task=nil )
#TODO remove TUM hack
content_type = "text/uri-list" if base_uri =~/tu-muenchen/ and res.content_type == "application/x-www-form-urlencoded;charset=UTF-8"
-s
+
task = nil
case res.content_type
when /application\/rdf\+xml/
--
cgit v1.2.3
From e8b8f16cffc0401f4f51c7b5c68198dbe2b89ad2 Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Wed, 9 Feb 2011 14:43:39 +0100
Subject: fix tum hack
---
lib/rest_client_wrapper.rb | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
(limited to 'lib')
diff --git a/lib/rest_client_wrapper.rb b/lib/rest_client_wrapper.rb
index d0e6727..626f94f 100644
--- a/lib/rest_client_wrapper.rb
+++ b/lib/rest_client_wrapper.rb
@@ -109,7 +109,7 @@ module OpenTox
def self.wait_for_task( res, base_uri, waiting_task=nil )
#TODO remove TUM hack
- content_type = "text/uri-list" if base_uri =~/tu-muenchen/ and res.content_type == "application/x-www-form-urlencoded;charset=UTF-8"
+ res.content_type = "text/uri-list" if base_uri =~/tu-muenchen/ and res.content_type == "application/x-www-form-urlencoded;charset=UTF-8"
task = nil
case res.content_type
@@ -121,7 +121,7 @@ module OpenTox
raise "uri list has more than one entry, should be a task" if res.content_type=~/text\/uri-list/ and res.split("\n").size > 1 #if uri list contains more then one uri, its not a task
task = OpenTox::Task.find(res.to_s.chomp) if res.to_s.uri?
else
- raise "unknown content-type for task : '"+res.content_type.to_s+"'"+" content: "+res[0..200].to_s
+ raise "unknown content-type for task : '"+res.content_type.to_s+"'"+" base-uri: "+base_uri.to_s+" content: "+res[0..200].to_s
end
LOGGER.debug "result is a task '"+task.uri.to_s+"', wait for completion"
--
cgit v1.2.3
From 4109a5256e953a9962a6e46acb074b2d7d8d2bd9 Mon Sep 17 00:00:00 2001
From: mr
Date: Wed, 9 Feb 2011 15:53:46 +0100
Subject: minor fix
---
lib/authorization.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/authorization.rb b/lib/authorization.rb
index 16f1ee4..b647bca 100644
--- a/lib/authorization.rb
+++ b/lib/authorization.rb
@@ -58,7 +58,7 @@ module OpenTox
# @param [String, String]Username,Password
# @return [String, nil] gives subjectid or nil
def self.authenticate(user, pw)
- return true if !AA_SERVER
+ return nil if !AA_SERVER
begin
resource = RestClient::Resource.new("#{AA_SERVER}/auth/authenticate")
out = resource.post(:username=>user, :password => pw).sub("token.id=","").sub("\n","")
--
cgit v1.2.3
From 87fa8c2c74484d85da3f581929a603f31ecc92d0 Mon Sep 17 00:00:00 2001
From: mr
Date: Wed, 9 Feb 2011 17:12:51 +0100
Subject: task with subtask from mguetlein
---
lib/task.rb | 30 ++++++++++++++----------------
1 file changed, 14 insertions(+), 16 deletions(-)
(limited to 'lib')
diff --git a/lib/task.rb b/lib/task.rb
index 1a684df..7aa3dd5 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -107,20 +107,9 @@ module OpenTox
def self.from_rdfxml(rdfxml)
- file = Tempfile.new("ot-rdfxml")
- file.puts rdfxml
- file.close
- file = "file://"+file.path
-
- # PENDING
- raise "Parse from file not working: what is the base-object-uri??? (omitted in triples)"
-
- parser = Parser::Owl::Generic.new file
- metadata = parser.load_metadata
- puts metadata.inspect
-
- task = Task.new(uri)
- task.add_metadata(metadata)
+ owl = OpenTox::Parser::Owl.from_rdf(rdfxml, OT.Task)
+ task = Task.new(owl.uri)
+ task.add_metadata(owl.metadata)
task
end
@@ -149,7 +138,7 @@ module OpenTox
end
def cancel
- RestClientWrapper.put(File.join(@uri,'Cancelled'))
+ RestClientWrapper.put(File.join(@uri,'Cancelled'),{:cannot_be => "empty"})
load_metadata
end
@@ -247,6 +236,7 @@ module OpenTox
# @param [optional,Numeric] dur seconds pausing before cheking again for completion
def wait_for_completion( waiting_task=nil, dur=0.3)
+ waiting_task.waiting_for(self.uri) if waiting_task
due_to_time = Time.new + DEFAULT_TASK_MAX_DURATION
LOGGER.debug "start waiting for task "+@uri.to_s+" at: "+Time.new.to_s+", waiting at least until "+due_to_time.to_s
@@ -262,7 +252,7 @@ module OpenTox
raise "max wait time exceeded ("+DEFAULT_TASK_MAX_DURATION.to_s+"sec), task: '"+@uri.to_s+"'"
end
end
-
+ waiting_task.waiting_for(nil) if waiting_task
LOGGER.debug "Task '"+@metadata[OT.hasStatus].to_s+"': "+@uri.to_s+", Result: "+@metadata[OT.resultURI].to_s
end
@@ -278,6 +268,10 @@ module OpenTox
end
end
+ def waiting_for(task_uri)
+ RestClientWrapper.put(File.join(@uri,'Running'),{:waiting_for => task_uri})
+ end
+
private
def check_state
begin
@@ -332,6 +326,10 @@ module OpenTox
end
end
+ def waiting_for(task_uri)
+ @task.waiting_for(task_uri)
+ end
+
def progress(pct)
raise "no numeric >= 0 and <= 100 : '"+pct.to_s+"'" unless pct.is_a?(Numeric) and pct>=0 and pct<=100
#puts "subtask := "+pct.to_s+" -> task := "+(@min + @delta * pct.to_f * 0.01).to_s
--
cgit v1.2.3
From 766d0eccb1a5d9f3016d9d85469dc68641b779ff Mon Sep 17 00:00:00 2001
From: mr
Date: Thu, 10 Feb 2011 08:51:15 +0100
Subject: config.yaml with new settings for A&A
---
lib/templates/config.yaml | 38 +++++++++++++++++++++++++++++++++++---
1 file changed, 35 insertions(+), 3 deletions(-)
(limited to 'lib')
diff --git a/lib/templates/config.yaml b/lib/templates/config.yaml
index 116f462..8a5e460 100644
--- a/lib/templates/config.yaml
+++ b/lib/templates/config.yaml
@@ -39,16 +39,48 @@
# Uncomment for verbose logging
# :logger: debug
-
+# :backtrace: 1
+
+
# OpenSSO Authorization
# set ":server: " to disable A&A
:authorization:
:server: "https://opensso.in-silico.ch"
- :free_request: #not controlled by A&A
- - "GET"
+ :free_request: #request-method not controlled by A&A
+ - "GET"
:authenticate_request: #only for authenticated user
- "POST"
:authorize_request: #only for authenticated and authorizeduser
- "DELETE"
- "PUT"
+ # Exceptions:
+ :free_uris: #request-method for uri not controlled by A&A
+ ? - :GET
+ : - !ruby/regexp /localhost\/algorithm/
+ - "http://localhost/dataset"
+ - "http://localhost/model"
+ - "http://localhost/validation"
+ - "http://localhost/validation/crossvalidation"
+ - "http://localhost/validation/reach_report"
+ - "http://localhost/validation/reach_report/crossvalidation"
+ - "http://localhost/validation/report"
+ - "http://localhost/validation/report/crossvalidation"
+ - "http://localhost/validation/reach_report/qmrf"
+ ? - :GET
+ - :POST
+ : - !ruby/regexp /localhost\/toxcreate/
+ - !ruby/regexp /localhost\/task/
+ - !ruby/regexp /localhost\/compound/
+ ? - :PUT
+ : - !ruby/regexp /localhost\/task/
+
+ :authorize_exceptions: #request-method for uri only authenticated, no authorization
+ ? - :POST
+ : - !ruby/regexp /localhost\/algorithm/
+ - "http://localhost/dataset"
+ - "http://localhost/model"
+ - "http://localhost/validation"
+ - !ruby/regexp /localhost\/validation\/[a-z,A-Z,\/,_\-]*$/
+
+
\ No newline at end of file
--
cgit v1.2.3
From 03795f02e06b3a9c635abf92c112a9dec142364b Mon Sep 17 00:00:00 2001
From: mr
Date: Thu, 10 Feb 2011 09:20:20 +0100
Subject: A&A fixes
---
lib/helper.rb | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
(limited to 'lib')
diff --git a/lib/helper.rb b/lib/helper.rb
index 6ca3901..415ca11 100644
--- a/lib/helper.rb
+++ b/lib/helper.rb
@@ -9,7 +9,7 @@ helpers do
end
elsif !env["session"] && subjectid
unless authorized?(subjectid)
- LOGGER.debug "URI not authorized: #{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}#{request.env['REQUEST_URI']} with request: #{request.env['REQUEST_METHOD']}"
+ LOGGER.debug "URI not authorized: clean: " + clean_uri("#{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}#{request.env['REQUEST_URI']}").to_s + " full: #{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}#{request.env['REQUEST_URI']} with request: #{request.env['REQUEST_METHOD']}"
raise OpenTox::NotAuthorizedError.new "Not authorized"
end
else
@@ -28,9 +28,11 @@ helpers do
#cleans URI from querystring and file-extension. Sets port 80 to emptystring
# @param [String] uri
def clean_uri(uri)
- uri = uri.sub(" ", "%20")
+ uri = uri.sub(" ", "%20") #dirty hacks => to fix
+ uri = uri[0,uri.index("InChI=")]
+
out = URI.parse(uri)
- out.path = out.path[0, out.path.index(/[0-9]/)] if out.path.index(/[0-9]/) #cuts after id for a&a
+ out.path = out.path[0, out.path.length - (out.path.reverse.rindex(/\/{1}\d+\/{1}/))] if out.path.index(/\/{1}\d+\/{1}/) #cuts after /id/ for a&a
"#{out.scheme}:" + (out.port != 80 ? out.port : "") + "//#{out.host}#{out.path.chomp('/')}"
end
--
cgit v1.2.3
From 65f6d64e57c81ae7b6dd72209fbeffee2d60da71 Mon Sep 17 00:00:00 2001
From: mr
Date: Thu, 10 Feb 2011 09:22:13 +0100
Subject: A&A fixes
---
lib/helper.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/helper.rb b/lib/helper.rb
index 415ca11..5a2436f 100644
--- a/lib/helper.rb
+++ b/lib/helper.rb
@@ -29,7 +29,7 @@ helpers do
# @param [String] uri
def clean_uri(uri)
uri = uri.sub(" ", "%20") #dirty hacks => to fix
- uri = uri[0,uri.index("InChI=")]
+ uri = uri[0,uri.index("InChI=")] if uri.index("InChI=")
out = URI.parse(uri)
out.path = out.path[0, out.path.length - (out.path.reverse.rindex(/\/{1}\d+\/{1}/))] if out.path.index(/\/{1}\d+\/{1}/) #cuts after /id/ for a&a
--
cgit v1.2.3
From 1f6625cffbb49ec93f6b4647ca1d11d01c5d11ea Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Thu, 10 Feb 2011 15:25:48 +0100
Subject: A&A hack for report svgs
---
lib/helper.rb | 2 ++
1 file changed, 2 insertions(+)
(limited to 'lib')
diff --git a/lib/helper.rb b/lib/helper.rb
index 5a2436f..191b932 100644
--- a/lib/helper.rb
+++ b/lib/helper.rb
@@ -19,6 +19,8 @@ helpers do
#Check Authorization for URI with method and subjectid.
def authorized?(subjectid)
+ # hack for reports, address problem as soon as subjectid is not longer allowed as param
+ return true if request.env['REQUEST_URI'] =~ /validation\/report\/.*svg$/
request_method = request.env['REQUEST_METHOD']
uri = clean_uri("#{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}#{request.env['REQUEST_URI']}")
request_method = "GET" if request_method == "POST" && uri =~ /\/model\/\d+\/?$/
--
cgit v1.2.3
From 616bb4b7aefed40cda0e09c88dc35ce1a82f8106 Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Thu, 10 Feb 2011 15:49:04 +0100
Subject: small fixes
---
lib/parser.rb | 2 +-
lib/rest_client_wrapper.rb | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/parser.rb b/lib/parser.rb
index 2f59d15..a2a96be 100644
--- a/lib/parser.rb
+++ b/lib/parser.rb
@@ -84,7 +84,7 @@ module OpenTox
uri = triple[0]
end
end
- File.delete(file)
+ File.delete(file.path)
# load metadata
metadata = {}
triples.each_line do |line|
diff --git a/lib/rest_client_wrapper.rb b/lib/rest_client_wrapper.rb
index 7a6ed2a..d3136c7 100644
--- a/lib/rest_client_wrapper.rb
+++ b/lib/rest_client_wrapper.rb
@@ -62,6 +62,7 @@ module OpenTox
waiting_task!=nil and !(waiting_task.is_a?(Task) || waiting_task.is_a?(SubTask))
headers.each{ |k,v| headers.delete(k) if v==nil } if headers #remove keys with empty values, as this can cause problems
## PENDING partner services accept subjectid only in header
+ headers = {} unless headers
headers[:subjectid] = payload.delete(:subjectid) if payload and payload.is_a?(Hash) and payload.has_key?(:subjectid)
# PENDING needed for NUTA, until we finally agree on how to send subjectid
--
cgit v1.2.3
From 85096197c1618cea45d7a1a8d5e4810ce1166083 Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Thu, 10 Feb 2011 15:55:30 +0100
Subject: render https as link
---
lib/to-html.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/to-html.rb b/lib/to-html.rb
index e9764ef..4de5ee6 100755
--- a/lib/to-html.rb
+++ b/lib/to-html.rb
@@ -7,7 +7,7 @@ class String
# encloses URI in text with with link tag
# @return [String] new text with marked links
def link_urls
- self.gsub(/(?i)http:\/\/[^\r\n\s']*/, '\0')
+ self.gsub(/(?i)http(s?):\/\/[^\r\n\s']*/, '\0')
end
end
--
cgit v1.2.3
From 1e2d28baa88f3a021604787c1356d6be1077be7e Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Thu, 10 Feb 2011 17:39:17 +0100
Subject: adjust rdf dataset parsing: take XSD type into account
---
lib/parser.rb | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/parser.rb b/lib/parser.rb
index a2a96be..c8a573f 100644
--- a/lib/parser.rb
+++ b/lib/parser.rb
@@ -165,7 +165,13 @@ module OpenTox
File.delete(file.path)
data.each do |id,entry|
entry[:values].each do |value_id|
- value = feature_values[value_id].split(/\^\^/).first # remove XSD.type
+ split = feature_values[value_id].split(/\^\^/)
+ case split[-1]
+ when XSD.double
+ value = split.first.to_f
+ else
+ value = split.first
+ end
@dataset.add entry[:compound],feature[value_id],value
end
end
--
cgit v1.2.3
From 3c7e4de0e3f4c9bbf8df55c88f155b40f575b3ab Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Fri, 11 Feb 2011 10:51:01 +0100
Subject: fix read from rdf file
---
lib/dataset.rb | 7 ++++++-
lib/parser.rb | 39 ++++++++++++++++++++++-----------------
2 files changed, 28 insertions(+), 18 deletions(-)
(limited to 'lib')
diff --git a/lib/dataset.rb b/lib/dataset.rb
index 02b89cb..a843cea 100644
--- a/lib/dataset.rb
+++ b/lib/dataset.rb
@@ -85,7 +85,12 @@ module OpenTox
end
def load_rdfxml(rdfxml)
- load_rdfxml_file Tempfile.open("ot-rdfxml"){|f| f.write(rdfxml)}.path
+ raise "rdfxml data is empty" if rdfxml.to_s.size==0
+ file = Tempfile.new("ot-rdfxml")
+ file.puts rdfxml
+ file.close
+ load_rdfxml_file file
+ file.delete
end
# Load RDF/XML representation from a file
diff --git a/lib/parser.rb b/lib/parser.rb
index c8a573f..f79b5e2 100644
--- a/lib/parser.rb
+++ b/lib/parser.rb
@@ -30,28 +30,29 @@ module OpenTox
# Read metadata from opentox service
# @return [Hash] Object metadata
def load_metadata(subjectid=nil)
- if @dataset
- uri = File.join(@uri,"metadata")
- else
- uri = @uri
- end
# avoid using rapper directly because of 2 reasons:
# * http errors wont be noticed
# * subjectid cannot be sent as header
##uri += "?subjectid=#{CGI.escape(subjectid)}" if subjectid
## `rapper -i rdfxml -o ntriples #{uri} 2>/dev/null`.each_line do |line|
- file = Tempfile.new("ot-rdfxml")
- file.puts OpenTox::RestClientWrapper.get @uri,{:subjectid => subjectid,:accept => "application/rdf+xml"},nil,false
- file.close
+ if File.exist?(@uri)
+ file = File.new(@uri)
+ else
+ file = Tempfile.new("ot-rdfxml")
+ uri = @dataset ? File.join(@uri,"metadata") : @uri
+ file.puts OpenTox::RestClientWrapper.get uri,{:subjectid => subjectid,:accept => "application/rdf+xml"},nil,false
+ file.close
+ to_delete = file.path
+ end
statements = []
parameter_ids = []
- `rapper -i rdfxml -o ntriples file://#{file.path} 2>/dev/null`.each_line do |line|
+ `rapper -i rdfxml -o ntriples #{file.path} 2>/dev/null`.each_line do |line|
triple = line.to_triple
@metadata[triple[1]] = triple[2].split('^^').first if triple[0] == @uri and triple[1] != RDF['type']
statements << triple
parameter_ids << triple[2] if triple[1] == OT.parameters
end
- File.delete(file.path)
+ File.delete(to_delete) if to_delete
unless parameter_ids.empty?
@metadata[OT.parameters] = []
parameter_ids.each do |p|
@@ -73,7 +74,7 @@ module OpenTox
file.puts rdf
file.close
#puts "cmd: rapper -i rdfxml -o ntriples #{file} 2>/dev/null"
- triples = `rapper -i rdfxml -o ntriples file://#{file.path} 2>/dev/null`
+ triples = `rapper -i rdfxml -o ntriples #{file.path} 2>/dev/null`
# load uri via type
uri = nil
@@ -130,22 +131,26 @@ module OpenTox
# dataset.save
# @return [Hash] Internal dataset representation
def load_uri(subjectid=nil)
- uri = @uri
# avoid using rapper directly because of 2 reasons:
# * http errors wont be noticed
# * subjectid cannot be sent as header
##uri += "?subjectid=#{CGI.escape(subjectid)}" if subjectid
##`rapper -i rdfxml -o ntriples #{file} 2>/dev/null`.each_line do |line|
- file = Tempfile.new("ot-rdfxml")
- file.puts OpenTox::RestClientWrapper.get @uri,{:subjectid => subjectid,:accept => "application/rdf+xml"},nil,false
- file.close
+ if File.exist?(@uri)
+ file = File.new(@uri)
+ else
+ file = Tempfile.new("ot-rdfxml")
+ file.puts OpenTox::RestClientWrapper.get @uri,{:subjectid => subjectid,:accept => "application/rdf+xml"},nil,false
+ file.close
+ to_delete = file.path
+ end
data = {}
feature_values = {}
feature = {}
other_statements = {}
- `rapper -i rdfxml -o ntriples file://#{file.path} 2>/dev/null`.each_line do |line|
+ `rapper -i rdfxml -o ntriples #{file.path} 2>/dev/null`.each_line do |line|
triple = line.chomp.split(' ',3)
triple = triple[0..2].collect{|i| i.sub(/\s+.$/,'').gsub(/[<>"]/,'')}
case triple[1]
@@ -162,7 +167,7 @@ module OpenTox
else
end
end
- File.delete(file.path)
+ File.delete(to_delete) if to_delete
data.each do |id,entry|
entry[:values].each do |value_id|
split = feature_values[value_id].split(/\^\^/)
--
cgit v1.2.3
From 1898a5353d790a17c3065e4349435642e1b7f701 Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Fri, 11 Feb 2011 16:34:41 +0100
Subject: adjust parser that dataset = daset.to_rdf.from rdf
---
lib/parser.rb | 20 +++++++++++++++-----
1 file changed, 15 insertions(+), 5 deletions(-)
(limited to 'lib')
diff --git a/lib/parser.rb b/lib/parser.rb
index f79b5e2..d2beeac 100644
--- a/lib/parser.rb
+++ b/lib/parser.rb
@@ -172,8 +172,10 @@ module OpenTox
entry[:values].each do |value_id|
split = feature_values[value_id].split(/\^\^/)
case split[-1]
- when XSD.double
+ when XSD.double, XSD.float
value = split.first.to_f
+ when XSD.boolean
+ value = split.first=~/(?i)true/ ? true : false
else
value = split.first
end
@@ -188,15 +190,23 @@ module OpenTox
# Read only features from a dataset service.
# @return [Hash] Internal features representation
def load_features(subjectid=nil)
- uri = File.join(@uri,"features")
- uri += "?subjectid=#{CGI.escape(subjectid)}" if subjectid
+ if File.exist?(@uri)
+ file = File.new(@uri)
+ else
+ file = Tempfile.new("ot-rdfxml")
+ uri = File.join(@uri,"features")
+ file.puts OpenTox::RestClientWrapper.get uri,{:subjectid => subjectid,:accept => "application/rdf+xml"},nil,false
+ file.close
+ to_delete = file.path
+ end
statements = []
features = Set.new
- `rapper -i rdfxml -o ntriples #{uri} 2>/dev/null`.each_line do |line|
+ `rapper -i rdfxml -o ntriples #{file.path} 2>/dev/null`.each_line do |line|
triple = line.chomp.split('> ').collect{|i| i.sub(/\s+.$/,'').gsub(/[<>"]/,'')}[0..2]
statements << triple
- features << triple[0] if triple[1] == RDF['type'] and triple[2] == OT.Feature
+ features << triple[0] if triple[1] == RDF['type'] and (triple[2] == OT.Feature || triple[2] == OT.NumericFeature)
end
+ File.delete(to_delete) if to_delete
statements.each do |triple|
if features.include? triple[0]
@dataset.features[triple[0]] = {} unless @dataset.features[triple[0]]
--
cgit v1.2.3
From 7dd4c74bf118285d567b0b221d091511b6a77b2f Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Sun, 13 Feb 2011 09:55:38 +0100
Subject: more debug out when authentication fails
---
lib/authorization.rb | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
(limited to 'lib')
diff --git a/lib/authorization.rb b/lib/authorization.rb
index 1942e95..eab20df 100644
--- a/lib/authorization.rb
+++ b/lib/authorization.rb
@@ -334,15 +334,15 @@ module OpenTox
true
elsif CONFIG[:authorization][:authenticate_request].include?(request_method)
ret = OpenTox::Authorization.is_token_valid(subjectid)
- #LOGGER.debug "authorized? >>#{ret}<< (token is in/valid), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}"
+ LOGGER.debug "authorized? >>#{ret}<< (token is in/valid), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}" unless ret
ret
elsif OpenTox::Authorization.authorize_exception?(uri, request_method)
ret = OpenTox::Authorization.is_token_valid(subjectid)
- #LOGGER.debug "authorized? >>#{ret}<< (uris is authorize exception, token is in/valid), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}"
+ LOGGER.debug "authorized? >>#{ret}<< (uris is authorize exception, token is in/valid), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}" unless ret
ret
elsif CONFIG[:authorization][:authorize_request].include?(request_method)
ret = OpenTox::Authorization.authorize(uri, request_method, subjectid)
- LOGGER.debug "authorized? >>#{ret}<< (uri (not) authorized), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}"
+ LOGGER.debug "authorized? >>#{ret}<< (uri (not) authorized), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}" unless ret
ret
else
LOGGER.error "invalid request/uri method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}"
--
cgit v1.2.3
From d4eb231a35c23a5fdb36fd6220b5ab706e7528ba Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Mon, 14 Feb 2011 17:48:26 +0100
Subject: read from subjectcookie, fix read feature_type
---
lib/feature.rb | 10 ++++++++--
lib/helper.rb | 3 +--
lib/model.rb | 22 +++++++++++++---------
lib/overwrite.rb | 2 +-
4 files changed, 23 insertions(+), 14 deletions(-)
(limited to 'lib')
diff --git a/lib/feature.rb b/lib/feature.rb
index be063dd..c0729a7 100644
--- a/lib/feature.rb
+++ b/lib/feature.rb
@@ -16,8 +16,14 @@ module OpenTox
# provides domain (possible target values) of classification feature
# @return [Array] list with possible target values
def domain
- #TODO derieve from metadata / ontology
- return [true, false]
+ if metadata[OT.acceptValue]
+ raise "accept value found, remove hack and implement correctly"
+ else
+ if @uri=~/feature\/26221/ || @uri=~/feature\/221726/
+ return ["mutagen" , "nonmutagen"]
+ end
+ return [true, false]
+ end
end
# provides feature type, possible types are "regression" or "classification"
diff --git a/lib/helper.rb b/lib/helper.rb
index 191b932..a1590d7 100644
--- a/lib/helper.rb
+++ b/lib/helper.rb
@@ -19,8 +19,6 @@ helpers do
#Check Authorization for URI with method and subjectid.
def authorized?(subjectid)
- # hack for reports, address problem as soon as subjectid is not longer allowed as param
- return true if request.env['REQUEST_URI'] =~ /validation\/report\/.*svg$/
request_method = request.env['REQUEST_METHOD']
uri = clean_uri("#{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}#{request.env['REQUEST_URI']}")
request_method = "GET" if request_method == "POST" && uri =~ /\/model\/\d+\/?$/
@@ -52,6 +50,7 @@ before do
subjectid = session[:subjectid] if session[:subjectid]
subjectid = params[:subjectid] if params[:subjectid] and !subjectid
subjectid = request.env['HTTP_SUBJECTID'] if request.env['HTTP_SUBJECTID'] and !subjectid
+ subjectid = request.cookies["subjectid"] unless subjectid
# see http://rack.rubyforge.org/doc/SPEC.html
subjectid = CGI.unescape(subjectid) if subjectid.include?("%23")
@subjectid = subjectid
diff --git a/lib/model.rb b/lib/model.rb
index 9622d65..74408d8 100644
--- a/lib/model.rb
+++ b/lib/model.rb
@@ -38,24 +38,28 @@ module OpenTox
# provides feature type, possible types are "regression" or "classification"
# @return [String] feature type, "unknown" if type could not be estimated
def feature_type(subjectid=nil)
+ return @feature_type if @feature_type
+
# dynamically perform restcalls if necessary
load_metadata(subjectid) if @metadata==nil or @metadata.size==0 or (@metadata.size==1 && @metadata.values[0]==@uri)
-
- @algorithm = OpenTox::Algorithm::Generic.find(@metadata[OT.algorithm], subjectid) unless @algorithm
- algorithm_title = @algorithm ? @algorithm.metadata[DC.title] : nil
- algorithm_type = @algorithm ? @algorithm.metadata[OT.isA] : nil
- @dependentVariable = OpenTox::Feature.find( @metadata[OT.dependentVariables],subjectid ) unless @dependentVariable
- type_indicators = [@dependentVariable.feature_type, @metadata[OT.isA], @metadata[DC.title],
+ algorithm = OpenTox::Algorithm::Generic.find(@metadata[OT.algorithm], subjectid)
+ algorithm_title = algorithm ? algorithm.metadata[DC.title] : nil
+ algorithm_type = algorithm ? algorithm.metadata[OT.isA] : nil
+ dependent_variable = OpenTox::Feature.find( @metadata[OT.dependentVariables],subjectid )
+ dependent_variable_type = dependent_variable ? dependent_variable.feature_type : nil
+ type_indicators = [dependent_variable_type, @metadata[OT.isA], @metadata[DC.title],
@uri, algorithm_type, algorithm_title]
type_indicators.each do |type|
case type
when /(?i)classification/
- return "classification"
+ @feature_type = "classification"
+ break
when /(?i)regression/
- return "regression"
+ @feature_type = "regression"
end
end
- raise "unknown model "+type_indicators.inspect
+ raise "unknown model "+type_indicators.inspect unless @feature_type
+ @feature_type
end
end
diff --git a/lib/overwrite.rb b/lib/overwrite.rb
index 7b53122..29a2860 100644
--- a/lib/overwrite.rb
+++ b/lib/overwrite.rb
@@ -45,7 +45,7 @@ class Sinatra::Base
response['Content-Type'] = "application/rdf+xml"
halt code,task.to_rdfxml
when /yaml/
- response['Content-Type'] = "application/rdf+xml"
+ response['Content-Type'] = "application/x-yaml"
halt code,task.to_yaml # PENDING differs from task-webservice
when /html/
response['Content-Type'] = "text/html"
--
cgit v1.2.3
From 8921d20b9d399274b0674794301ff3567ac7c816 Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Mon, 14 Feb 2011 18:01:42 +0100
Subject: handle nil values in split
---
lib/dataset.rb | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
(limited to 'lib')
diff --git a/lib/dataset.rb b/lib/dataset.rb
index a843cea..a0f99b1 100644
--- a/lib/dataset.rb
+++ b/lib/dataset.rb
@@ -237,7 +237,7 @@ module OpenTox
@features[feature] = {} unless @features[feature]
@data_entries[compound] = {} unless @data_entries[compound]
@data_entries[compound][feature] = [] unless @data_entries[compound][feature]
- @data_entries[compound][feature] << value
+ @data_entries[compound][feature] << value unless value
end
# Add/modify metadata, existing entries will be overwritten
@@ -283,8 +283,12 @@ module OpenTox
else
compounds.each do |c|
features.each do |f|
- @data_entries[c][f].each do |v|
- dataset.add(c,f,v)
+ unless @data_entries[c][f]
+ dataset.add(c,f,nil)
+ else
+ @data_entries[c][f].each do |v|
+ dataset.add(c,f,v)
+ end
end
end
end
--
cgit v1.2.3
From 267b691017202c2fccf69dbeecfd4ed524a73fc2 Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Mon, 14 Feb 2011 18:28:12 +0100
Subject: fix: handle nil values in split
---
lib/dataset.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/dataset.rb b/lib/dataset.rb
index a0f99b1..efab0a3 100644
--- a/lib/dataset.rb
+++ b/lib/dataset.rb
@@ -237,7 +237,7 @@ module OpenTox
@features[feature] = {} unless @features[feature]
@data_entries[compound] = {} unless @data_entries[compound]
@data_entries[compound][feature] = [] unless @data_entries[compound][feature]
- @data_entries[compound][feature] << value unless value
+ @data_entries[compound][feature] << value if value
end
# Add/modify metadata, existing entries will be overwritten
--
cgit v1.2.3
From 1bac8bd64f9f703d7e20a65da0ffb05cb150e90f Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Sat, 19 Feb 2011 11:26:24 +0100
Subject: add login functionality to webservices
---
lib/overwrite.rb | 4 +--
lib/to-html.rb | 99 ++++++++++++++++++++++++++++++++++++--------------------
2 files changed, 66 insertions(+), 37 deletions(-)
(limited to 'lib')
diff --git a/lib/overwrite.rb b/lib/overwrite.rb
index 29a2860..b5c3942 100644
--- a/lib/overwrite.rb
+++ b/lib/overwrite.rb
@@ -29,7 +29,7 @@ error Exception do
halt error.http_code,rep.to_rdfxml
when /html/
content_type 'text/html'
- halt error.http_code,(OpenTox.text_to_html rep.to_yaml)
+ halt error.http_code,(OpenTox.text_to_html rep.to_yaml, @subjectid)
else
content_type 'application/x-yaml'
halt error.http_code,rep.to_yaml
@@ -49,7 +49,7 @@ class Sinatra::Base
halt code,task.to_yaml # PENDING differs from task-webservice
when /html/
response['Content-Type'] = "text/html"
- halt code,OpenTox.text_to_html(task.to_yaml)
+ halt code,OpenTox.text_to_html(task.to_yaml, @subjectid)
else # default /uri-list/
response['Content-Type'] = "text/uri-list"
halt code,task.uri+"\n"
diff --git a/lib/to-html.rb b/lib/to-html.rb
index 4de5ee6..1f30ca1 100755
--- a/lib/to-html.rb
+++ b/lib/to-html.rb
@@ -1,7 +1,6 @@
OT_LOGO = "http://opentox.informatik.uni-freiburg.de/ot-logo.png"
-
class String
# encloses URI in text with with link tag
@@ -25,29 +24,30 @@ module OpenTox
# @param [optional,String] description general info
# @param [optional,Array] post_params, array of arrays containing info on POST operation, see example
# @return [String] html page
- def self.text_to_html( text, related_links=nil, description=nil, post_params=nil )
+ def self.text_to_html( text, subjectid=nil, related_links=nil, description=nil, post_params=nil )
# TODO add title as parameter
title = nil #$sinatra.url_for($sinatra.request.env['PATH_INFO'], :full) if $sinatra
-
- html = <
-EOF
- html.chomp!
+ html = ""
html += ""+title+"" if title
- html += <
-
-EOF
- html.chomp!
- html += "
Description
"+description.link_urls+"
" if description
- html += "
Related links
"+related_links.link_urls+"
" if related_links
- if post_params
+ html += ""
+
+ if AA_SERVER
+ user = OpenTox::Authorization.get_user(subjectid) if subjectid
+ html += "
"
+ unless user
+ html += "You are currently not logged in to "+$url_provider.url_for("",:full)+
+ ", login"
+ else
+ html += "You are logged in as '#{user}' to "+$url_provider.url_for("",:full)+
+ ", logout"
+ end
+ html += "
"
+ end
+
+ html += "
Description
"+description.link_urls+"
" if description
+ html += "
Related links
"+related_links.link_urls+"
" if related_links
+ if post_params
html += "
POST parameters
"
count = 0
post_params.each do |p|
@@ -59,23 +59,52 @@ EOF
html += "
"
count += 1
end
- end
- html += "
Content
" if description || related_links
- html += <
-
-EOF
- html.chomp!
- html += text.link_urls
- html += <
-
-
-
-EOF
+ end
+ html += "
Content
" if description || related_links
+ html += "
"
+ html += text.link_urls
+ html += "
"
html
end
+ def self.login( msg=nil )
+ html = "Login"
+ html += "
"
+ html
+ end
+end
+
+get '/logout/?' do
+ response.set_cookie("subjectid",{:value=>nil})
+ content_type "text/html"
+ content = "Sucessfully logged out from "+$url_provider.url_for("",:full)
+ OpenTox.text_to_html(content)
+end
+
+get '/login/?' do
+ content_type "text/html"
+ OpenTox.login
+end
+
+post '/login/?' do
+ subjectid = OpenTox::Authorization.authenticate(params[:user], params[:password])
+ if (subjectid)
+ response.set_cookie("subjectid",{:value=>subjectid})
+ content_type "text/html"
+ content = "Sucessfully logged in as '"+params[:user]+"' to "+$url_provider.url_for("",:full)
+ OpenTox.text_to_html(content,subjectid)
+ else
+ content_type "text/html"
+ OpenTox.login("Login failed, please try again")
+ end
end
-#puts OpenTox.text_to_html("bla")
\ No newline at end of file
--
cgit v1.2.3
From 80d49f60ac55cc2fb1c7974752e1e947fa3f3f70 Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Mon, 21 Feb 2011 13:52:00 +0100
Subject: clean uri now works for https, rdf parsing issues: /features and
?feature_uris, missing subjectid
---
lib/dataset.rb | 2 ++
lib/helper.rb | 5 +++--
lib/parser.rb | 43 +++++++++++++++++++++++++++++--------------
lib/rest_client_wrapper.rb | 3 ++-
4 files changed, 36 insertions(+), 17 deletions(-)
(limited to 'lib')
diff --git a/lib/dataset.rb b/lib/dataset.rb
index efab0a3..3f530e6 100644
--- a/lib/dataset.rb
+++ b/lib/dataset.rb
@@ -141,8 +141,10 @@ module OpenTox
if (CONFIG[:yaml_hosts].include?(URI.parse(@uri).host))
copy YAML.load(RestClientWrapper.get(@uri, {:accept => "application/x-yaml", :subjectid => subjectid}))
else
+ puts "loading all.."
parser = Parser::Owl::Dataset.new(@uri, subjectid)
copy parser.load_uri(subjectid)
+ puts "..done"
end
end
diff --git a/lib/helper.rb b/lib/helper.rb
index a1590d7..b30908c 100644
--- a/lib/helper.rb
+++ b/lib/helper.rb
@@ -32,8 +32,9 @@ helpers do
uri = uri[0,uri.index("InChI=")] if uri.index("InChI=")
out = URI.parse(uri)
- out.path = out.path[0, out.path.length - (out.path.reverse.rindex(/\/{1}\d+\/{1}/))] if out.path.index(/\/{1}\d+\/{1}/) #cuts after /id/ for a&a
- "#{out.scheme}:" + (out.port != 80 ? out.port : "") + "//#{out.host}#{out.path.chomp('/')}"
+ out.path = out.path[0, out.path.length - (out.path.reverse.rindex(/\/{1}\d+\/{1}/))] if out.path.index(/\/{1}\d+\/{1}/) #cuts after /id/ for a&a
+ port = (out.scheme=="http" && out.port==80)||(out.scheme=="https" && out.port==443) ? "" : ":#{out.port.to_s}"
+ "#{out.scheme}://#{out.host}#{port}#{out.path.chomp("/")}" #"
end
#unprotected uri for login
diff --git a/lib/parser.rb b/lib/parser.rb
index d2beeac..f1249ad 100644
--- a/lib/parser.rb
+++ b/lib/parser.rb
@@ -39,7 +39,14 @@ module OpenTox
file = File.new(@uri)
else
file = Tempfile.new("ot-rdfxml")
- uri = @dataset ? File.join(@uri,"metadata") : @uri
+ if @dataset
+ # do not concat /metadata to uri string, this would not work for dataset/R401577?max=3
+ uri = URI::parse(@uri)
+ uri.path = File.join(uri.path,"metadata")
+ uri = uri.to_s
+ else
+ uri = @uri
+ end
file.puts OpenTox::RestClientWrapper.get uri,{:subjectid => subjectid,:accept => "application/rdf+xml"},nil,false
file.close
to_delete = file.path
@@ -163,26 +170,31 @@ module OpenTox
data[triple[0]] = {:compound => "", :values => []} unless data[triple[0]]
data[triple[0]][:compound] = triple[2]
when /#{OT.feature}/i
- feature[triple[0]] = triple[2]
+ feature[triple[0]] = triple[2]
else
end
end
File.delete(to_delete) if to_delete
data.each do |id,entry|
- entry[:values].each do |value_id|
- split = feature_values[value_id].split(/\^\^/)
- case split[-1]
- when XSD.double, XSD.float
- value = split.first.to_f
- when XSD.boolean
- value = split.first=~/(?i)true/ ? true : false
- else
- value = split.first
+ if entry[:values].size==0
+ # no feature values add plain compounds
+ @dataset.add_compound(entry[:compound])
+ else
+ entry[:values].each do |value_id|
+ split = feature_values[value_id].split(/\^\^/)
+ case split[-1]
+ when XSD.double, XSD.float
+ value = split.first.to_f
+ when XSD.boolean
+ value = split.first=~/(?i)true/ ? true : false
+ else
+ value = split.first
+ end
+ @dataset.add entry[:compound],feature[value_id],value
end
- @dataset.add entry[:compound],feature[value_id],value
end
end
- load_features
+ load_features subjectid
@dataset.metadata = load_metadata(subjectid)
@dataset
end
@@ -194,7 +206,10 @@ module OpenTox
file = File.new(@uri)
else
file = Tempfile.new("ot-rdfxml")
- uri = File.join(@uri,"features")
+ # do not concat /features to uri string, this would not work for dataset/R401577?max=3
+ uri = URI::parse(@uri)
+ uri.path = File.join(uri.path,"features")
+ uri = uri.to_s
file.puts OpenTox::RestClientWrapper.get uri,{:subjectid => subjectid,:accept => "application/rdf+xml"},nil,false
file.close
to_delete = file.path
diff --git a/lib/rest_client_wrapper.rb b/lib/rest_client_wrapper.rb
index d3136c7..dac24dc 100644
--- a/lib/rest_client_wrapper.rb
+++ b/lib/rest_client_wrapper.rb
@@ -76,7 +76,8 @@ module OpenTox
else
result = resource.send(rest_call, headers)
end
-
+ #LOGGER.debug "result body size: #{result.body.size}"
+
# PENDING NTUA does return errors with 200
raise RestClient::ExceptionWithResponse.new(result) if uri=~/ntua/ and result.body =~ /about.*http:\/\/anonymous.org\/error/
--
cgit v1.2.3
From 53dec3e3b1a59760ac9440749d159edc7ac09359 Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Mon, 21 Feb 2011 14:10:44 +0100
Subject: removing debug msg
---
lib/dataset.rb | 2 --
1 file changed, 2 deletions(-)
(limited to 'lib')
diff --git a/lib/dataset.rb b/lib/dataset.rb
index 3f530e6..efab0a3 100644
--- a/lib/dataset.rb
+++ b/lib/dataset.rb
@@ -141,10 +141,8 @@ module OpenTox
if (CONFIG[:yaml_hosts].include?(URI.parse(@uri).host))
copy YAML.load(RestClientWrapper.get(@uri, {:accept => "application/x-yaml", :subjectid => subjectid}))
else
- puts "loading all.."
parser = Parser::Owl::Dataset.new(@uri, subjectid)
copy parser.load_uri(subjectid)
- puts "..done"
end
end
--
cgit v1.2.3
From 9bc9d1c5c11aa64d410200cc21d07acc39cc3019 Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Mon, 21 Feb 2011 15:44:24 +0100
Subject: fix for Datset#add false values, fix for parsing compounds without
values
---
lib/dataset.rb | 2 +-
lib/parser.rb | 4 ++++
2 files changed, 5 insertions(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/dataset.rb b/lib/dataset.rb
index efab0a3..2c47502 100644
--- a/lib/dataset.rb
+++ b/lib/dataset.rb
@@ -237,7 +237,7 @@ module OpenTox
@features[feature] = {} unless @features[feature]
@data_entries[compound] = {} unless @data_entries[compound]
@data_entries[compound][feature] = [] unless @data_entries[compound][feature]
- @data_entries[compound][feature] << value if value
+ @data_entries[compound][feature] << value if value!=nil
end
# Add/modify metadata, existing entries will be overwritten
diff --git a/lib/parser.rb b/lib/parser.rb
index f1249ad..f33017d 100644
--- a/lib/parser.rb
+++ b/lib/parser.rb
@@ -171,6 +171,10 @@ module OpenTox
data[triple[0]][:compound] = triple[2]
when /#{OT.feature}/i
feature[triple[0]] = triple[2]
+ when /#{RDF.type}/i
+ if triple[2]=~/#{OT.Compound}/i and !data[triple[0]]
+ data[triple[0]] = {:compound => triple[0], :values => []}
+ end
else
end
end
--
cgit v1.2.3
From 2b61ab65d17b6c80b0afdee33956c263cd7f9c21 Mon Sep 17 00:00:00 2001
From: root
Date: Thu, 24 Feb 2011 11:59:56 +0000
Subject: set :lock, true in config_ru.rb, detect accept header in before
filter
---
lib/config/config_ru.rb | 1 +
lib/helper.rb | 20 ++++++++++++++++++++
2 files changed, 21 insertions(+)
(limited to 'lib')
diff --git a/lib/config/config_ru.rb b/lib/config/config_ru.rb
index 3d8dce2..93df867 100644
--- a/lib/config/config_ru.rb
+++ b/lib/config/config_ru.rb
@@ -12,6 +12,7 @@ $stdout.sync = true
$stderr.sync = true
set :logging, false
set :raise_errors, true
+set :lock, true
['public','tmp'].each do |dir|
FileUtils.mkdir_p dir unless File.exists?(dir)
diff --git a/lib/helper.rb b/lib/helper.rb
index b30908c..37238bd 100644
--- a/lib/helper.rb
+++ b/lib/helper.rb
@@ -61,6 +61,26 @@ before do
end
@subjectid = subjectid
protected!(subjectid)
+
+ extension = File.extname(request.path_info) # params[:id] is not yet available
+ unless extension.empty?
+ #request.path_info.sub!(/\.#{extension}$/,'')
+ case extension
+ when "html"
+ @accept = 'text/html'
+ when "yaml"
+ @accept = 'application/x-yaml'
+ when "csv"
+ @accept = 'text/csv'
+ when "rdfxml"
+ @accept = 'application/rdf+xml'
+ when "xls"
+ @accept = 'application/ms-excel'
+ else
+ halt 404, "File format #{extension} not supported."
+ end
+ end
+
end
end
--
cgit v1.2.3
From 96e7db0a280ed3f28266a117a27cc69cb800063f Mon Sep 17 00:00:00 2001
From: root
Date: Fri, 25 Feb 2011 11:45:05 +0000
Subject: experiments with db adapters
---
lib/environment.rb | 14 ++++++++++++++
1 file changed, 14 insertions(+)
(limited to 'lib')
diff --git a/lib/environment.rb b/lib/environment.rb
index b30b3f3..5b16e4a 100644
--- a/lib/environment.rb
+++ b/lib/environment.rb
@@ -25,11 +25,17 @@ end
# database
if CONFIG[:database]
['dm-core', 'dm-serializer', 'dm-timestamps', 'dm-types', 'dm-migrations', 'dm-validations' ].each{|lib| require lib }
+=begin
+=end
case CONFIG[:database][:adapter]
when /sqlite/i
db_dir = File.join(basedir, "db")
FileUtils.mkdir_p db_dir
DataMapper::setup(:default, "sqlite3://#{db_dir}/opentox.sqlite3")
+ #when /yaml/i
+ #db_dir = File.join(basedir, "db")
+ #FileUtils.mkdir_p db_dir
+ #DataMapper::setup(:default, {:adapter => "yaml", :directory => 'db'})
else
DataMapper.setup(:default, {
:adapter => CONFIG[:database][:adapter],
@@ -38,6 +44,14 @@ if CONFIG[:database]
:password => CONFIG[:database][:password],
:host => CONFIG[:database][:host]})
end
+ #db_dir = File.join(basedir, "db")
+ #FileUtils.mkdir_p db_dir
+ #DataMapper::setup(:in_memory, "in_memory")
+ #require 'redis'
+
+ #DataMapper.setup(:default, {:adapter => "redis"})
+
+ #DataMapper::Model.raise_on_save_failure = true
end
# load mail settings for error messages
--
cgit v1.2.3
From d3dfccb8e46e1d5677877b833fa81acad4d026d4 Mon Sep 17 00:00:00 2001
From: root
Date: Fri, 25 Feb 2011 17:54:39 +0000
Subject: ohm/redis backend
---
lib/environment.rb | 2 ++
lib/opentox-ruby.rb | 2 +-
lib/overwrite.rb | 6 ++++++
3 files changed, 9 insertions(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/environment.rb b/lib/environment.rb
index 5b16e4a..73df64e 100644
--- a/lib/environment.rb
+++ b/lib/environment.rb
@@ -52,6 +52,8 @@ if CONFIG[:database]
#DataMapper.setup(:default, {:adapter => "redis"})
#DataMapper::Model.raise_on_save_failure = true
+ require 'ohm'
+ Ohm.connect :thread_safe => true
end
# load mail settings for error messages
diff --git a/lib/opentox-ruby.rb b/lib/opentox-ruby.rb
index 735b845..ab8d824 100644
--- a/lib/opentox-ruby.rb
+++ b/lib/opentox-ruby.rb
@@ -1,4 +1,4 @@
-['rubygems', 'sinatra', 'sinatra/url_for', 'rest_client', 'yaml', 'cgi', 'spork', 'error', 'overwrite', 'environment'].each do |lib|
+['rubygems', 'sinatra', 'sinatra/url_for', 'ohm', 'rest_client', 'yaml', 'cgi', 'spork', 'error', 'overwrite', 'environment'].each do |lib|
require lib
end
diff --git a/lib/overwrite.rb b/lib/overwrite.rb
index b5c3942..fbe775d 100644
--- a/lib/overwrite.rb
+++ b/lib/overwrite.rb
@@ -137,3 +137,9 @@ class OTLogger < Logger
end
+# make migration from datamapper more straightforward
+class Ohm::Model
+ def self.get(id)
+ self[id]
+ end
+end
--
cgit v1.2.3
From 9f91e5438a32f0b3b5b3755adfa20d4e0d36566b Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Sun, 27 Feb 2011 09:32:57 +0100
Subject: code cleanup
---
lib/environment.rb | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
(limited to 'lib')
diff --git a/lib/environment.rb b/lib/environment.rb
index 73df64e..4f04e48 100644
--- a/lib/environment.rb
+++ b/lib/environment.rb
@@ -23,10 +23,9 @@ else
end
# database
+=begin
if CONFIG[:database]
['dm-core', 'dm-serializer', 'dm-timestamps', 'dm-types', 'dm-migrations', 'dm-validations' ].each{|lib| require lib }
-=begin
-=end
case CONFIG[:database][:adapter]
when /sqlite/i
db_dir = File.join(basedir, "db")
@@ -52,9 +51,10 @@ if CONFIG[:database]
#DataMapper.setup(:default, {:adapter => "redis"})
#DataMapper::Model.raise_on_save_failure = true
- require 'ohm'
- Ohm.connect :thread_safe => true
end
+=end
+require 'ohm'
+Ohm.connect :thread_safe => true
# load mail settings for error messages
load File.join config_dir,"mail.rb" if File.exists?(File.join config_dir,"mail.rb")
--
cgit v1.2.3
From 2b0ad7c00ec9559d05e07e78cee5f7846d51ee5f Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Thu, 3 Mar 2011 11:35:54 +0100
Subject: login methods in to-html.rb removed, interferes with ToxCreate login
---
lib/to-html.rb | 2 ++
1 file changed, 2 insertions(+)
mode change 100755 => 100644 lib/to-html.rb
(limited to 'lib')
diff --git a/lib/to-html.rb b/lib/to-html.rb
old mode 100755
new mode 100644
index 1f30ca1..6785974
--- a/lib/to-html.rb
+++ b/lib/to-html.rb
@@ -83,6 +83,7 @@ module OpenTox
end
end
+=begin
get '/logout/?' do
response.set_cookie("subjectid",{:value=>nil})
content_type "text/html"
@@ -107,4 +108,5 @@ post '/login/?' do
OpenTox.login("Login failed, please try again")
end
end
+=end
--
cgit v1.2.3
From 1ffb44de021b276d3ae25fc9d9b09ec1f0f9aa16 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Wed, 9 Mar 2011 10:24:49 +0100
Subject: old database config removed
---
lib/environment.rb | 32 +-------------------------------
lib/helper.rb | 13 +++++++++++++
2 files changed, 14 insertions(+), 31 deletions(-)
(limited to 'lib')
diff --git a/lib/environment.rb b/lib/environment.rb
index 4f04e48..59578c1 100644
--- a/lib/environment.rb
+++ b/lib/environment.rb
@@ -23,37 +23,7 @@ else
end
# database
-=begin
-if CONFIG[:database]
- ['dm-core', 'dm-serializer', 'dm-timestamps', 'dm-types', 'dm-migrations', 'dm-validations' ].each{|lib| require lib }
- case CONFIG[:database][:adapter]
- when /sqlite/i
- db_dir = File.join(basedir, "db")
- FileUtils.mkdir_p db_dir
- DataMapper::setup(:default, "sqlite3://#{db_dir}/opentox.sqlite3")
- #when /yaml/i
- #db_dir = File.join(basedir, "db")
- #FileUtils.mkdir_p db_dir
- #DataMapper::setup(:default, {:adapter => "yaml", :directory => 'db'})
- else
- DataMapper.setup(:default, {
- :adapter => CONFIG[:database][:adapter],
- :database => CONFIG[:database][:database],
- :username => CONFIG[:database][:username],
- :password => CONFIG[:database][:password],
- :host => CONFIG[:database][:host]})
- end
- #db_dir = File.join(basedir, "db")
- #FileUtils.mkdir_p db_dir
- #DataMapper::setup(:in_memory, "in_memory")
- #require 'redis'
-
- #DataMapper.setup(:default, {:adapter => "redis"})
-
- #DataMapper::Model.raise_on_save_failure = true
-end
-=end
-require 'ohm'
+`redis-server /opt/redis/redis.conf` unless File.exists? "/var/run/redis.pid"
Ohm.connect :thread_safe => true
# load mail settings for error messages
diff --git a/lib/helper.rb b/lib/helper.rb
index 37238bd..3031b74 100644
--- a/lib/helper.rb
+++ b/lib/helper.rb
@@ -42,6 +42,19 @@ helpers do
return env['REQUEST_URI'] =~ /\/login$/
end
+ def uri_available?(urlStr)
+ url = URI.parse(urlStr)
+ unless @subjectid
+ Net::HTTP.start(url.host, url.port) do |http|
+ return http.head(url.request_uri).code == "200"
+ end
+ else
+ Net::HTTP.start(url.host, url.port) do |http|
+ return http.post(url.request_uri, "subjectid=#{@subjectid}").code == "202"
+ end
+ end
+ end
+
end
before do
--
cgit v1.2.3
From c802bfd6c899d4d37e3bd2ee274c1bc3ffb7cd94 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Wed, 16 Mar 2011 14:11:37 +0100
Subject: doc for Feature.find, load_features in feature_type
---
lib/algorithm.rb | 3 +--
lib/dataset.rb | 3 ++-
lib/feature.rb | 3 +++
3 files changed, 6 insertions(+), 3 deletions(-)
(limited to 'lib')
diff --git a/lib/algorithm.rb b/lib/algorithm.rb
index af8dfaf..c8cb116 100644
--- a/lib/algorithm.rb
+++ b/lib/algorithm.rb
@@ -190,8 +190,7 @@ module OpenTox
gram_matrix[i][i] = 1.0
end
- LOGGER.debug gram_matrix.to_yaml
-
+ #LOGGER.debug gram_matrix.to_yaml
@r = RinRuby.new(false,false) # global R instance leads to Socket errors after a large number of requests
@r.eval "library('kernlab')" # this requires R package "kernlab" to be installed
LOGGER.debug "Setting R data ..."
diff --git a/lib/dataset.rb b/lib/dataset.rb
index 2c47502..c61d86f 100644
--- a/lib/dataset.rb
+++ b/lib/dataset.rb
@@ -165,7 +165,8 @@ module OpenTox
# Detect feature type(s) in the dataset
# @return [String] `classification", "regression", "mixed" or unknown`
- def feature_type
+ def feature_type(subjectid=nil)
+ load_features(subjectid)
feature_types = @features.collect{|f,metadata| metadata[OT.isA]}.uniq
if feature_types.size > 1
"mixed"
diff --git a/lib/feature.rb b/lib/feature.rb
index c0729a7..e768f7b 100644
--- a/lib/feature.rb
+++ b/lib/feature.rb
@@ -2,6 +2,9 @@ module OpenTox
class Feature
include OpenTox
+ # Find a feature
+ # @param [String] uri Feature URI
+ # @return [OpenTox::Task] Feature object
def self.find(uri, subjectid=nil)
return nil unless uri
feature = Feature.new uri
--
cgit v1.2.3
From 91781c18c8c2c33783f30e64172f11ae9180a6d1 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Wed, 16 Mar 2011 15:40:46 +0100
Subject: conversion to float in Math.gauss
---
lib/algorithm.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/algorithm.rb b/lib/algorithm.rb
index c8cb116..167c964 100644
--- a/lib/algorithm.rb
+++ b/lib/algorithm.rb
@@ -246,7 +246,7 @@ module OpenTox
# Gauss kernel
# @return [Float]
def self.gauss(x, sigma = 0.3)
- d = 1.0 - x
+ d = 1.0 - x.to_f
Math.exp(-(d*d)/(2*sigma*sigma))
end
--
cgit v1.2.3
From c0bef2dc83d2ce1fea6434ca73586d49865bb810 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Thu, 31 Mar 2011 13:44:02 +0200
Subject: ohm-contrib added
---
lib/environment.rb | 2 +-
lib/ontology.rb | 55 +++++++++++++++++++++++++++++++++++++++++++++++++
lib/ontology_service.rb | 43 --------------------------------------
lib/opentox-ruby.rb | 2 +-
4 files changed, 57 insertions(+), 45 deletions(-)
create mode 100644 lib/ontology.rb
delete mode 100644 lib/ontology_service.rb
(limited to 'lib')
diff --git a/lib/environment.rb b/lib/environment.rb
index 59578c1..57ae014 100644
--- a/lib/environment.rb
+++ b/lib/environment.rb
@@ -74,7 +74,7 @@ CONFIG[:authorization][:authenticate_request] = [""] unless CONFIG[:authorizatio
CONFIG[:authorization][:authorize_request] = [""] unless CONFIG[:authorization][:authorize_request]
CONFIG[:authorization][:free_request] = [""] unless CONFIG[:authorization][:free_request]
-RDF = OwlNamespace.new 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'
+#RDF = OwlNamespace.new 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'
OWL = OwlNamespace.new 'http://www.w3.org/2002/07/owl#'
DC = OwlNamespace.new 'http://purl.org/dc/elements/1.1/'
OT = OwlNamespace.new 'http://www.opentox.org/api/1.1#'
diff --git a/lib/ontology.rb b/lib/ontology.rb
new file mode 100644
index 0000000..c3952c3
--- /dev/null
+++ b/lib/ontology.rb
@@ -0,0 +1,55 @@
+module OpenTox
+ module Ontology
+ module Echa
+ require 'sparql/client'
+ @sparql = SPARQL::Client.new("http://apps.ideaconsult.net:8080/ontology")
+ def self.qs(classname="Endpoints")
+ return "PREFIX ot:
+ PREFIX ota:
+ PREFIX owl:
+ PREFIX dc:
+ PREFIX rdfs:
+ PREFIX rdf:
+ PREFIX otee:
+ PREFIX toxcast:
+ select *
+ where {
+ ?endpoint rdfs:subClassOf otee:#{classname}.
+ ?endpoint dc:title ?title.
+ }"
+ end
+
+ def self.make_option_list(endpoint="Endpoints", level=1)
+ out = ""
+ results = @sparql.query(qs(endpoint)) rescue results = []
+ results.each do |result|
+ endpointname = result.Endpoints.to_s.split('#').last
+ title = result.bound?(:title) ? result.title : endpointname
+ out += "\n"
+ out += make_option_list(endpointname, level + 1)
+ end
+ return out
+ end
+
+ def self.get_endpoint_selectlist(include_blank=true)
+ out = "\n"
+ return out
+ end
+
+ def self.endpoints#(endpoint="Endpoints")
+ endpoint_datasets = {}
+ RestClientWrapper.get("http://apps.ideaconsult.net:8080/ambit2/query/ndatasets_endpoint",:accept => "text/csv").each do |line|
+ if line.match(/^http/)
+ e = line.split(',')
+ endpoint_datasets["#{e.first} (#{e[1]})"] = RestClientWrapper.get(e.last, :accept => "text/uri-list").split("\n")#[0..e[1].to_i-1] # hack to get only the first count entries
+ end
+ end
+ endpoint_datasets
+ end
+ end
+
+ end
+end
diff --git a/lib/ontology_service.rb b/lib/ontology_service.rb
deleted file mode 100644
index 4ff688f..0000000
--- a/lib/ontology_service.rb
+++ /dev/null
@@ -1,43 +0,0 @@
-module OpenTox
- module OntologyService
- module Endpoints
- require 'sparql/client'
- @sparql = SPARQL::Client.new("http://apps.ideaconsult.net:8080/ontology")
- def self.qs(classname="Endpoints")
- return "PREFIX ot:
- PREFIX ota:
- PREFIX owl:
- PREFIX dc:
- PREFIX rdfs:
- PREFIX rdf:
- PREFIX otee:
- PREFIX toxcast:
- select ?Endpoints ?title ?id
- where {?Endpoints rdfs:subClassOf otee:#{classname}.
- OPTIONAL {?Endpoints dc:title ?title}.
- OPTIONAL {?Endpoints dc:identifier ?id}.}
- ORDER BY ?title"
- end
-
- def self.make_option_list(endpoint="Endpoints", level=1)
- out = ""
- results = @sparql.query(qs(endpoint)) rescue results = []
- results.each do |result|
- endpointname = result.Endpoints.to_s.split('#').last
- title = result.bound?(:title) ? result.title : endpointname
- out += "\n"
- out += make_option_list(endpointname, level + 1)
- end
- return out
- end
-
- def self.get_endpoint_selectlist(include_blank=true)
- out = "\n"
- return out
- end
- end
- end
-end
\ No newline at end of file
diff --git a/lib/opentox-ruby.rb b/lib/opentox-ruby.rb
index ab8d824..ae05cb2 100644
--- a/lib/opentox-ruby.rb
+++ b/lib/opentox-ruby.rb
@@ -9,6 +9,6 @@ rescue LoadError
end
['opentox', 'compound','dataset', 'parser','serializer', 'algorithm','model','task','validation','feature',
- 'rest_client_wrapper', 'authorization', 'policy', 'helper', 'to-html' ].each do |lib|
+ 'rest_client_wrapper', 'authorization', 'policy', 'helper', 'to-html', 'ontology' ].each do |lib|
require lib
end
--
cgit v1.2.3
From 1daec5badcff31c591377017b32055aac775dbb7 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Mon, 4 Apr 2011 18:46:22 +0200
Subject: OT.isA substituted by RDF.type, identification of feature_types by
RDF.type
---
lib/dataset.rb | 31 +++++++++++------
lib/environment.rb | 2 +-
lib/error.rb | 4 +--
lib/feature.rb | 12 ++++++-
lib/model.rb | 15 ++++-----
lib/ontology.rb | 18 +++++-----
lib/opentox.rb | 9 ++++-
lib/parser.rb | 11 ++++--
lib/serializer.rb | 2 +-
lib/templates/config.yaml | 86 -----------------------------------------------
10 files changed, 68 insertions(+), 122 deletions(-)
delete mode 100644 lib/templates/config.yaml
(limited to 'lib')
diff --git a/lib/dataset.rb b/lib/dataset.rb
index c61d86f..93fce18 100644
--- a/lib/dataset.rb
+++ b/lib/dataset.rb
@@ -163,24 +163,33 @@ module OpenTox
@features
end
+ def feature_classes(feature)
+ if Feature.find(feature).feature_type == "classification"
+ classes = []
+ @data_entries.each do |c,e|
+ e[feature].each { |v| classes << v.to_s }
+ end
+ classes.uniq.sort
+ else
+ nil
+ end
+ end
+
+=begin
# Detect feature type(s) in the dataset
# @return [String] `classification", "regression", "mixed" or unknown`
def feature_type(subjectid=nil)
load_features(subjectid)
- feature_types = @features.collect{|f,metadata| metadata[OT.isA]}.uniq
- if feature_types.size > 1
- "mixed"
+ feature_types = @features.collect{|f,metadata| metadata[RDF.type]}.flatten.uniq
+ if feature_types.include?(OT.NominalFeature)
+ "classification"
+ elsif feature_types.include?(OT.NumericFeature)
+ "regression"
else
- case feature_types.first
- when /NominalFeature/
- "classification"
- when /NumericFeature/
- "regression"
- else
- "unknown"
- end
+ "unknown"
end
end
+=end
# Get Spreadsheet representation
# @return [Spreadsheet::Workbook] Workbook which can be written with the spreadsheet gem (data_entries only, metadata will will be discarded))
diff --git a/lib/environment.rb b/lib/environment.rb
index 57ae014..59578c1 100644
--- a/lib/environment.rb
+++ b/lib/environment.rb
@@ -74,7 +74,7 @@ CONFIG[:authorization][:authenticate_request] = [""] unless CONFIG[:authorizatio
CONFIG[:authorization][:authorize_request] = [""] unless CONFIG[:authorization][:authorize_request]
CONFIG[:authorization][:free_request] = [""] unless CONFIG[:authorization][:free_request]
-#RDF = OwlNamespace.new 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'
+RDF = OwlNamespace.new 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'
OWL = OwlNamespace.new 'http://www.w3.org/2002/07/owl#'
DC = OwlNamespace.new 'http://purl.org/dc/elements/1.1/'
OT = OwlNamespace.new 'http://www.opentox.org/api/1.1#'
diff --git a/lib/error.rb b/lib/error.rb
index 7ca9767..b92f2a4 100644
--- a/lib/error.rb
+++ b/lib/error.rb
@@ -69,7 +69,7 @@ module OpenTox
def rdf_content()
c = {
- RDF.type => OT.ErrorReport,
+ RDF.type => [OT.ErrorReport],
OT.statusCode => @http_code,
OT.message => @message,
OT.actor => @actor,
@@ -96,4 +96,4 @@ class Array
end
short.join("\n")
end
-end
\ No newline at end of file
+end
diff --git a/lib/feature.rb b/lib/feature.rb
index e768f7b..f6e2dfd 100644
--- a/lib/feature.rb
+++ b/lib/feature.rb
@@ -32,7 +32,16 @@ module OpenTox
# provides feature type, possible types are "regression" or "classification"
# @return [String] feature type, unknown if OT.isA property is unknown/ not set
def feature_type
- case metadata[OT.isA]
+ if metadata[RDF.type].flatten.include?(OT.NominalFeature)
+ "classification"
+ elsif metadata[RDF.type].flatten.include?(OT.NumericFeature)
+ "regression"
+ else
+ #"unknown"
+ metadata[RDF.type].inspect
+ end
+=begin
+ case metadata[RDF.type]
when /NominalFeature/
"classification"
when /NumericFeature/
@@ -40,6 +49,7 @@ module OpenTox
else
"unknown"
end
+=end
end
end
diff --git a/lib/model.rb b/lib/model.rb
index 74408d8..422acd2 100644
--- a/lib/model.rb
+++ b/lib/model.rb
@@ -44,11 +44,10 @@ module OpenTox
load_metadata(subjectid) if @metadata==nil or @metadata.size==0 or (@metadata.size==1 && @metadata.values[0]==@uri)
algorithm = OpenTox::Algorithm::Generic.find(@metadata[OT.algorithm], subjectid)
algorithm_title = algorithm ? algorithm.metadata[DC.title] : nil
- algorithm_type = algorithm ? algorithm.metadata[OT.isA] : nil
+ algorithm_type = algorithm ? algorithm.metadata[RDF.type] : nil
dependent_variable = OpenTox::Feature.find( @metadata[OT.dependentVariables],subjectid )
dependent_variable_type = dependent_variable ? dependent_variable.feature_type : nil
- type_indicators = [dependent_variable_type, @metadata[OT.isA], @metadata[DC.title],
- @uri, algorithm_type, algorithm_title]
+ type_indicators = [dependent_variable_type, @metadata[RDF.type], @metadata[DC.title], @uri, algorithm_type, algorithm_title].flatten
type_indicators.each do |type|
case type
when /(?i)classification/
@@ -187,7 +186,7 @@ module OpenTox
if @neighbors.size == 0
@prediction_dataset.add_feature(prediction_feature_uri, {
- OT.isA => OT.MeasuredFeature,
+ RDF.type => [OT.MeasuredFeature],
OT.hasSource => @uri,
DC.creator => @uri,
DC.title => URI.decode(File.basename( @metadata[OT.dependentVariables] )),
@@ -198,7 +197,7 @@ module OpenTox
else
@prediction_dataset.add_feature(prediction_feature_uri, {
- OT.isA => OT.ModelPrediction,
+ RDF.type => [OT.ModelPrediction],
OT.hasSource => @uri,
DC.creator => @uri,
DC.title => URI.decode(File.basename( @metadata[OT.dependentVariables] )),
@@ -215,7 +214,7 @@ module OpenTox
feature_uri = File.join( @prediction_dataset.uri, "feature", "descriptor", f.to_s)
features[feature] = feature_uri
@prediction_dataset.add_feature(feature_uri, {
- OT.isA => OT.Substructure,
+ RDF.type => [OT.Substructure],
OT.smarts => feature,
OT.pValue => @p_values[feature],
OT.effect => @effects[feature]
@@ -236,7 +235,7 @@ module OpenTox
OT.compound => neighbor[:compound],
OT.similarity => neighbor[:similarity],
OT.measuredActivity => neighbor[:activity],
- OT.isA => OT.Neighbor
+ RDF.type => [OT.Neighbor]
})
@prediction_dataset.add @compound.uri, neighbor_uri, true
f = 0 unless f
@@ -250,7 +249,7 @@ module OpenTox
unless features.has_key? feature
features[feature] = feature_uri
@prediction_dataset.add_feature(feature_uri, {
- OT.isA => OT.Substructure,
+ RDF.type => [OT.Substructure],
OT.smarts => feature,
OT.pValue => @p_values[feature],
OT.effect => @effects[feature]
diff --git a/lib/ontology.rb b/lib/ontology.rb
index c3952c3..fa4ea6f 100644
--- a/lib/ontology.rb
+++ b/lib/ontology.rb
@@ -1,6 +1,7 @@
module OpenTox
module Ontology
module Echa
+=begin
require 'sparql/client'
@sparql = SPARQL::Client.new("http://apps.ideaconsult.net:8080/ontology")
def self.qs(classname="Endpoints")
@@ -38,17 +39,16 @@ module OpenTox
out += "\n"
return out
end
+=end
- def self.endpoints#(endpoint="Endpoints")
- endpoint_datasets = {}
- RestClientWrapper.get("http://apps.ideaconsult.net:8080/ambit2/query/ndatasets_endpoint",:accept => "text/csv").each do |line|
- if line.match(/^http/)
- e = line.split(',')
- endpoint_datasets["#{e.first} (#{e[1]})"] = RestClientWrapper.get(e.last, :accept => "text/uri-list").split("\n")#[0..e[1].to_i-1] # hack to get only the first count entries
- end
- end
- endpoint_datasets
+ def self.endpoints
+ RestClientWrapper.get("http://apps.ideaconsult.net:8080/ambit2/query/ndatasets_endpoint",:accept => "text/csv").collect { |line| line.split(',').first if line.match(/^http/) }.compact
+ end
+
+ def self.datasets(endpoint)
+ RestClientWrapper.get("http://apps.ideaconsult.net:8080/ambit2/dataset?feature_sameas=#{URI.encode endpoint}", :accept => "text/uri-list").split("\n")
end
+
end
end
diff --git a/lib/opentox.rb b/lib/opentox.rb
index 1992896..c76e21a 100644
--- a/lib/opentox.rb
+++ b/lib/opentox.rb
@@ -31,7 +31,14 @@ module OpenTox
end
def add_metadata(metadata)
- metadata.each { |k,v| @metadata[k] = v }
+ metadata.each do |k,v|
+ if v.is_a? Array
+ @metadata[k] = [] unless @metadata[k]
+ @metadata[k] << v
+ else
+ @metadata[k] = v
+ end
+ end
end
# Get OWL-DL representation in RDF/XML format
diff --git a/lib/parser.rb b/lib/parser.rb
index f33017d..cc5f1c8 100644
--- a/lib/parser.rb
+++ b/lib/parser.rb
@@ -55,7 +55,14 @@ module OpenTox
parameter_ids = []
`rapper -i rdfxml -o ntriples #{file.path} 2>/dev/null`.each_line do |line|
triple = line.to_triple
- @metadata[triple[1]] = triple[2].split('^^').first if triple[0] == @uri and triple[1] != RDF['type']
+ if triple[0] == @uri
+ if triple[1] == RDF.type # allow multiple types
+ @metadata[triple[1]] = [] unless @metadata[triple[1]]
+ @metadata[triple[1]] << triple[2].split('^^').first
+ else
+ @metadata[triple[1]] = triple[2].split('^^').first
+ end
+ end
statements << triple
parameter_ids << triple[2] if triple[1] == OT.parameters
end
@@ -289,7 +296,7 @@ module OpenTox
else
type = types.first
end
- @dataset.add_feature_metadata(feature,{OT.isA => type})
+ @dataset.add_feature_metadata(feature,{RDF.type => [type]})
info += "\"#{@dataset.feature_name(feature)}\" detected as #{type.split('#').last}."
# TODO: rewrite feature values
diff --git a/lib/serializer.rb b/lib/serializer.rb
index 44b4414..644a09f 100644
--- a/lib/serializer.rb
+++ b/lib/serializer.rb
@@ -67,7 +67,7 @@ module OpenTox
DC.creator => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
DC.description => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
DC.date => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.isA => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ #OT.isA => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
OT.Warnings => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
XSD.anyURI => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
OT.hasStatus => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
diff --git a/lib/templates/config.yaml b/lib/templates/config.yaml
deleted file mode 100644
index 8a5e460..0000000
--- a/lib/templates/config.yaml
+++ /dev/null
@@ -1,86 +0,0 @@
-# Example configuration for OpenTox, please adjust to your settings
-#
-# Database setup:
-#
-# Example MySql:
-#
-:database:
- :adapter: mysql
- :database: production
- :username: root
- :password: opentox
- :host: localhost
-#
-# Example 1: Using external test services
-#
-# :services:
-# opentox-compound: "http://webservices.in-silico.ch/compound/"
-# opentox-dataset: "http://webservices.in-silico.ch/dataset/"
-# opentox-algorithm: "http://webservices.in-silico.ch/algorithm/"
-# opentox-model: "http://webservices.in-silico.ch/model/"
-# opentox-task: "http://webservices.in-silico.ch/task/"
-# opentox-validation: "http://opentox.informatik.uni-freiburg.de/validation/"
-#
-# Example 2: Using local services
-:base_dir: /home/ist/webservices
-:webserver: passenger
-:services:
- opentox-compound: "http://localhost/compound/"
- opentox-dataset: "http://localhost/dataset/"
- opentox-algorithm: "http://localhost/algorithm/"
- opentox-model: "http://localhost/model/"
- opentox-task: "http://localhost/task/"
- opentox-validation: "http://localhost/validation/"
-#
-# Yaml capable hosts (faster than OWL-DL)
-#
-:yaml_hosts:
- - "localhost"
-
-# Uncomment for verbose logging
-# :logger: debug
-# :backtrace: 1
-
-
-# OpenSSO Authorization
-# set ":server: " to disable A&A
-:authorization:
- :server: "https://opensso.in-silico.ch"
- :free_request: #request-method not controlled by A&A
- - "GET"
- :authenticate_request: #only for authenticated user
- - "POST"
- :authorize_request: #only for authenticated and authorizeduser
- - "DELETE"
- - "PUT"
- # Exceptions:
- :free_uris: #request-method for uri not controlled by A&A
- ? - :GET
- : - !ruby/regexp /localhost\/algorithm/
- - "http://localhost/dataset"
- - "http://localhost/model"
- - "http://localhost/validation"
- - "http://localhost/validation/crossvalidation"
- - "http://localhost/validation/reach_report"
- - "http://localhost/validation/reach_report/crossvalidation"
- - "http://localhost/validation/report"
- - "http://localhost/validation/report/crossvalidation"
- - "http://localhost/validation/reach_report/qmrf"
- ? - :GET
- - :POST
- : - !ruby/regexp /localhost\/toxcreate/
- - !ruby/regexp /localhost\/task/
- - !ruby/regexp /localhost\/compound/
- ? - :PUT
- : - !ruby/regexp /localhost\/task/
-
- :authorize_exceptions: #request-method for uri only authenticated, no authorization
- ? - :POST
- : - !ruby/regexp /localhost\/algorithm/
- - "http://localhost/dataset"
- - "http://localhost/model"
- - "http://localhost/validation"
- - !ruby/regexp /localhost\/validation\/[a-z,A-Z,\/,_\-]*$/
-
-
-
\ No newline at end of file
--
cgit v1.2.3
From 80c2562c0f84f65b0e3ed02c3293c530d0dc4ce2 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Tue, 5 Apr 2011 19:12:04 +0200
Subject: Parser.load_features fixed for Substructures
---
lib/parser.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/parser.rb b/lib/parser.rb
index cc5f1c8..db746c1 100644
--- a/lib/parser.rb
+++ b/lib/parser.rb
@@ -230,7 +230,7 @@ module OpenTox
`rapper -i rdfxml -o ntriples #{file.path} 2>/dev/null`.each_line do |line|
triple = line.chomp.split('> ').collect{|i| i.sub(/\s+.$/,'').gsub(/[<>"]/,'')}[0..2]
statements << triple
- features << triple[0] if triple[1] == RDF['type'] and (triple[2] == OT.Feature || triple[2] == OT.NumericFeature)
+ features << triple[0] if triple[1] == RDF.type and (triple[2] =~ /Feature|Substructure/)
end
File.delete(to_delete) if to_delete
statements.each do |triple|
--
cgit v1.2.3
From a12f491fc42b058168fb43b32e8769694e821658 Mon Sep 17 00:00:00 2001
From: mr
Date: Wed, 6 Apr 2011 09:59:04 +0200
Subject: A&A fixes, code cleaning
---
lib/algorithm.rb | 2 +-
lib/helper.rb | 57 +++++++++++++++++++++++++++++---------------------------
lib/model.rb | 3 ++-
3 files changed, 33 insertions(+), 29 deletions(-)
(limited to 'lib')
diff --git a/lib/algorithm.rb b/lib/algorithm.rb
index c8cb116..167c964 100644
--- a/lib/algorithm.rb
+++ b/lib/algorithm.rb
@@ -246,7 +246,7 @@ module OpenTox
# Gauss kernel
# @return [Float]
def self.gauss(x, sigma = 0.3)
- d = 1.0 - x
+ d = 1.0 - x.to_f
Math.exp(-(d*d)/(2*sigma*sigma))
end
diff --git a/lib/helper.rb b/lib/helper.rb
index 3031b74..af92419 100644
--- a/lib/helper.rb
+++ b/lib/helper.rb
@@ -55,10 +55,7 @@ helpers do
end
end
-end
-
-before do
- unless !AA_SERVER or login_requests or CONFIG[:authorization][:free_request].include?(env['REQUEST_METHOD'])
+ def get_subjectid
begin
subjectid = nil
subjectid = session[:subjectid] if session[:subjectid]
@@ -69,31 +66,37 @@ before do
subjectid = CGI.unescape(subjectid) if subjectid.include?("%23")
@subjectid = subjectid
rescue
- #LOGGER.debug "OpenTox ruby api wrapper: helper before filter: NO subjectid for URI: #{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}#{request.env['REQUEST_URI']}"
- subjectid = ""
+ subjectid = nil
end
- @subjectid = subjectid
- protected!(subjectid)
-
- extension = File.extname(request.path_info) # params[:id] is not yet available
+ end
+ def get_extension
+ extension = File.extname(request.path_info)
unless extension.empty?
- #request.path_info.sub!(/\.#{extension}$/,'')
- case extension
- when "html"
- @accept = 'text/html'
- when "yaml"
- @accept = 'application/x-yaml'
- when "csv"
- @accept = 'text/csv'
- when "rdfxml"
- @accept = 'application/rdf+xml'
- when "xls"
- @accept = 'application/ms-excel'
- else
- halt 404, "File format #{extension} not supported."
- end
- end
-
+ case extension.gsub(".","")
+ when "html"
+ @accept = 'text/html'
+ when "yaml"
+ @accept = 'application/x-yaml'
+ when "csv"
+ @accept = 'text/csv'
+ when "rdfxml"
+ @accept = 'application/rdf+xml'
+ when "xls"
+ @accept = 'application/ms-excel'
+ when "css"
+ @accept = 'text/css'
+ else
+ # halt 404, "File format #{extension} not supported."
+ end
+ end
+ end
+end
+
+before do
+ @subjectid = get_subjectid()
+ @accept = get_extension()
+ unless !AA_SERVER or login_requests or CONFIG[:authorization][:free_request].include?(env['REQUEST_METHOD'])
+ protected!(@subjectid)
end
end
diff --git a/lib/model.rb b/lib/model.rb
index 74408d8..c46f2a0 100644
--- a/lib/model.rb
+++ b/lib/model.rb
@@ -113,9 +113,10 @@ module OpenTox
# @param [optional,Hash] params Parameters for the lazar algorithm (OpenTox::Algorithm::Lazar)
# @return [OpenTox::Model::Lazar] lazar model
def self.create(params)
+ subjectid = params[:subjectid]
lazar_algorithm = OpenTox::Algorithm::Generic.new File.join( CONFIG[:services]["opentox-algorithm"],"lazar")
model_uri = lazar_algorithm.run(params)
- OpenTox::Model::Lazar.find(model_uri, params[:subjectid])
+ OpenTox::Model::Lazar.find(model_uri, subjectid)
end
# Get a parameter value
--
cgit v1.2.3
From d0a2babc27dd0545c0a8a9465dd03ae247151aa4 Mon Sep 17 00:00:00 2001
From: mr
Date: Fri, 8 Apr 2011 15:37:01 +0200
Subject: A&A fixes
---
lib/dataset.rb | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
(limited to 'lib')
diff --git a/lib/dataset.rb b/lib/dataset.rb
index 93fce18..0a2f770 100644
--- a/lib/dataset.rb
+++ b/lib/dataset.rb
@@ -163,8 +163,8 @@ module OpenTox
@features
end
- def feature_classes(feature)
- if Feature.find(feature).feature_type == "classification"
+ def feature_classes(feature, subjectid=nil)
+ if Feature.find(feature, subjectid).feature_type == "classification"
classes = []
@data_entries.each do |c,e|
e[feature].each { |v| classes << v.to_s }
--
cgit v1.2.3
From 796614bf4431d3560d6aae69de4793bdfa5a7b51 Mon Sep 17 00:00:00 2001
From: mr
Date: Thu, 21 Apr 2011 13:27:53 +0200
Subject: subjectids for load_metadata in algorithm.rb and list_policies_uris
changes in A&A
---
lib/algorithm.rb | 12 ++++++------
lib/authorization.rb | 15 +++++++++++----
2 files changed, 17 insertions(+), 10 deletions(-)
(limited to 'lib')
diff --git a/lib/algorithm.rb b/lib/algorithm.rb
index 167c964..54ca064 100644
--- a/lib/algorithm.rb
+++ b/lib/algorithm.rb
@@ -52,9 +52,9 @@ module OpenTox
class BBRC
include Fminer
# Initialize bbrc algorithm
- def initialize
+ def initialize(subjectid=nil)
super File.join(CONFIG[:services]["opentox-algorithm"], "fminer/bbrc")
- load_metadata
+ load_metadata(subjectid)
end
end
@@ -62,9 +62,9 @@ module OpenTox
class LAST
include Fminer
# Initialize last algorithm
- def initialize
+ def initialize(subjectid=nil)
super File.join(CONFIG[:services]["opentox-algorithm"], "fminer/last")
- load_metadata
+ load_metadata(subjectid)
end
end
@@ -74,9 +74,9 @@ module OpenTox
class Lazar
include Algorithm
# Initialize lazar algorithm
- def initialize
+ def initialize(subjectid=nil)
super File.join(CONFIG[:services]["opentox-algorithm"], "lazar")
- load_metadata
+ load_metadata(subjectid)
end
end
diff --git a/lib/authorization.rb b/lib/authorization.rb
index eab20df..d9f900b 100644
--- a/lib/authorization.rb
+++ b/lib/authorization.rb
@@ -137,16 +137,23 @@ module OpenTox
# Lists policies alongside with affected uris
# @param [String] subjectid
# @return [Hash] keys: all policies of the subjectid owner, values: uris affected by those policies
- def self.list_policy_uris( subjectid )
+ def self.list_policies_uris( subjectid )
names = list_policies(subjectid)
policies = {}
names.each do |n|
- p = OpenTox::Policies.new
- p.load_xml( list_policy(n, subjectid) )
- policies[n] = p.uris
+ policies[n] = list_policy_uris( n, subjectid )
end
policies
end
+
+ # Lists policies alongside with affected uris
+ # @param [String] subjectid
+ # @return [Hash] keys: all policies of the subjectid owner, values: uris affected by those policies
+ def self.list_policy_uris( policy, subjectid )
+ p = OpenTox::Policies.new
+ p.load_xml( list_policy(policy, subjectid) )
+ p.uris
+ end
#Returns the owner (who created the first policy) of an URI
# @param [String, String]uri,subjectid
--
cgit v1.2.3
From 60d48b6a31fdc9aa80243d2e1e072f069bdc2799 Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Thu, 28 Apr 2011 03:55:53 -0700
Subject: Removed redis-server start call.
---
lib/environment.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/environment.rb b/lib/environment.rb
index 59578c1..ffc4f60 100644
--- a/lib/environment.rb
+++ b/lib/environment.rb
@@ -23,7 +23,7 @@ else
end
# database
-`redis-server /opt/redis/redis.conf` unless File.exists? "/var/run/redis.pid"
+#`redis-server /opt/redis/redis.conf` unless File.exists? "/var/run/redis.pid" # removed by AM
Ohm.connect :thread_safe => true
# load mail settings for error messages
--
cgit v1.2.3
From 8500b7de67afaa34675c006bff42768f1229e22e Mon Sep 17 00:00:00 2001
From: mr
Date: Mon, 2 May 2011 15:00:31 +0200
Subject: fix file type in helper
---
lib/helper.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/helper.rb b/lib/helper.rb
index 3031b74..7009082 100644
--- a/lib/helper.rb
+++ b/lib/helper.rb
@@ -90,7 +90,7 @@ before do
when "xls"
@accept = 'application/ms-excel'
else
- halt 404, "File format #{extension} not supported."
+ #halt 404, "File format #{extension} not supported."
end
end
--
cgit v1.2.3
From 612db56ce522a632414158917c2462fe40c242dc Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Wed, 4 May 2011 15:27:01 +0200
Subject: use task-status-code from task-service (to fix inconsistent task
status codes)
---
lib/overwrite.rb | 14 +++++++++-----
lib/task.rb | 2 ++
2 files changed, 11 insertions(+), 5 deletions(-)
(limited to 'lib')
diff --git a/lib/overwrite.rb b/lib/overwrite.rb
index fbe775d..fffcb14 100644
--- a/lib/overwrite.rb
+++ b/lib/overwrite.rb
@@ -39,20 +39,24 @@ end
class Sinatra::Base
def return_task( task )
- code = task.running? ? 202 : 200
+ raise "http_code == nil" unless task.http_code!=nil
case request.env['HTTP_ACCEPT']
when /rdf/
response['Content-Type'] = "application/rdf+xml"
- halt code,task.to_rdfxml
+ halt task.http_code,task.to_rdfxml
when /yaml/
response['Content-Type'] = "application/x-yaml"
- halt code,task.to_yaml # PENDING differs from task-webservice
+ halt task.http_code,task.to_yaml # PENDING differs from task-webservice
when /html/
response['Content-Type'] = "text/html"
- halt code,OpenTox.text_to_html(task.to_yaml, @subjectid)
+ halt task.http_code,OpenTox.text_to_html(task.to_yaml, @subjectid)
else # default /uri-list/
response['Content-Type'] = "text/uri-list"
- halt code,task.uri+"\n"
+ if task.completed?
+ halt task.http_code,task.resultURI+"\n"
+ else
+ halt task.http_code,task.uri+"\n"
+ end
end
end
end
diff --git a/lib/task.rb b/lib/task.rb
index 0ee3a11..19f42d6 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -8,6 +8,7 @@ module OpenTox
def initialize(uri=nil)
super uri
+ @http_code = 202
@metadata = {
DC.title => "",
DC.date => "",
@@ -154,6 +155,7 @@ module OpenTox
# not stored just for to_rdf
def add_error_report( error_report )
+ raise "not an error report: "+error_report.class.to_s unless error_report.is_a?(ErrorReport)
@error_report = error_report
end
--
cgit v1.2.3
From 435540f4be8787e0c34a64a2d2d7ed3118be9de9 Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Thu, 5 May 2011 07:17:04 +0200
Subject: Fixed activity output
---
lib/algorithm.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/algorithm.rb b/lib/algorithm.rb
index 54ca064..008e7fe 100644
--- a/lib/algorithm.rb
+++ b/lib/algorithm.rb
@@ -215,7 +215,7 @@ module OpenTox
LOGGER.debug "Predicting ..."
@r.eval "p<-predict(model,sims)[1,1]"
prediction = 10**(@r.p.to_f)
- LOGGER.debug "Prediction is: '" + @prediction.to_s + "'."
+ LOGGER.debug "Prediction is: '" + prediction.to_s + "'."
@r.quit # free R
end
confidence = conf/neighbors.size if neighbors.size > 0
--
cgit v1.2.3
From 4e01933dda7b56049f1c1216cb5895b10c10b4a4 Mon Sep 17 00:00:00 2001
From: root
Date: Fri, 6 May 2011 13:18:28 +0000
Subject: request features in YAML format first (Dataset.load_features), chomp
URIs in Dataset.all)
---
lib/dataset.rb | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
(limited to 'lib')
diff --git a/lib/dataset.rb b/lib/dataset.rb
index c61d86f..546eb2e 100644
--- a/lib/dataset.rb
+++ b/lib/dataset.rb
@@ -74,7 +74,7 @@ module OpenTox
# @param [optional,String] uri URI of the dataset service, defaults to service specified in configuration
# @return [Array] Array of dataset object without data (use one of the load_* methods to pull data from the server)
def self.all(uri=CONFIG[:services]["opentox-dataset"], subjectid=nil)
- RestClientWrapper.get(uri,{:accept => "text/uri-list",:subjectid => subjectid}).to_s.each_line.collect{|u| Dataset.new(u, subjectid)}
+ RestClientWrapper.get(uri,{:accept => "text/uri-list",:subjectid => subjectid}).to_s.each_line.collect{|u| Dataset.new(u.chomp, subjectid)}
end
# Load YAML representation into the dataset
@@ -158,8 +158,12 @@ module OpenTox
# Load and return only features from the dataset service
# @return [Hash] Features of the dataset
def load_features(subjectid=nil)
- parser = Parser::Owl::Dataset.new(@uri, subjectid)
- @features = parser.load_features(subjectid)
+ if (CONFIG[:yaml_hosts].include?(URI.parse(@uri).host))
+ @features = YAML.load(RestClientWrapper.get(File.join(@uri,"features"), {:accept => "application/x-yaml", :subjectid => subjectid}))
+ else
+ parser = Parser::Owl::Dataset.new(@uri, subjectid)
+ @features = parser.load_features(subjectid)
+ end
@features
end
--
cgit v1.2.3
From 0edca0616624ab9711b3791bbb7697a676e0b141 Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Fri, 6 May 2011 17:01:27 +0200
Subject: fix specificity (was 1-specificity) in cv-summary, (added
training-test-split to validation object)
---
lib/validation.rb | 46 +++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 45 insertions(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/validation.rb b/lib/validation.rb
index a47a554..8fa95bb 100644
--- a/lib/validation.rb
+++ b/lib/validation.rb
@@ -12,6 +12,29 @@ module OpenTox
val
end
+ # creates a training test split validation, waits until it finishes, may take some time
+ # @param [Hash] params (required:algorithm_uri,dataset_uri,prediction_feature, optional:algorithm_params,split_ratio(0.67),random_seed(1))
+ # @param [String,optional] subjectid
+ # @param [OpenTox::Task,optional] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
+ # @return [OpenTox::Validation]
+ def self.create_training_test_split( params, subjectid=nil, waiting_task=nil )
+ params[:subjectid] = subjectid if subjectid
+ uri = OpenTox::RestClientWrapper.post( File.join(CONFIG[:services]["opentox-validation"],"training_test_split"),
+ params,{:content_type => "text/uri-list"},waiting_task )
+ Validation.new(uri)
+ end
+
+ # looks for report for this validation, creates a report if no report is found
+ # @param [String,optional] subjectid
+ # @param [OpenTox::Task,optional] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
+ # @return [String] report uri
+ def find_or_create_report( subjectid=nil, waiting_task=nil )
+ @report = ValidationReport.find_for_validation(@uri, subjectid) unless @report
+ @report = ValidationReport.create(@uri, subjectid, waiting_task) unless @report
+ @report.uri
+ end
+
+
# creates a validation object from crossvaldiation statistics, raise error if not found
# (as crossvaldiation statistics are returned as an average valdidation over all folds)
# @param [String] crossvalidation uri
@@ -42,7 +65,7 @@ module OpenTox
res[:true_negatives] = s[OT.numTrueNegatives]
res[:false_negatives] = s[OT.numFalseNegatives]
res[:sensitivity] = s[OT.truePositiveRate]
- res[:specificity] = s[OT.falsePositiveRate]
+ res[:specificity] = s[OT.trueNegativeRate]
break
end
end
@@ -110,6 +133,16 @@ module OpenTox
class ValidationReport
include OpenTox
+ # finds ValidationReport via uri, raises error if not found
+ # @param [String] uri
+ # @param [String,optional] subjectid
+ # @return [OpenTox::ValidationReport]
+ def self.find( uri, subjectid=nil )
+ # PENDING load report data?
+ OpenTox::RestClientWrapper.get(uri,{:subjectid => subjectid})
+ ValidationReport.new(uri)
+ end
+
# finds ValidationReport for a particular validation
# @param [String] crossvalidation uri
# @param [String,optional] subjectid
@@ -120,6 +153,17 @@ module OpenTox
uris.size==0 ? nil : ValidationReport.new(uris[-1])
end
+ # creates a validation report via validation
+ # @param [String] validation uri
+ # @param [String,optional] subjectid
+ # @param [OpenTox::Task,optional] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
+ # @return [OpenTox::ValidationReport]
+ def self.create( validation_uri, subjectid=nil, waiting_task=nil )
+ uri = RestClientWrapper.post(File.join(CONFIG[:services]["opentox-validation"],"/report/validation"),
+ { :validation_uris => validation_uri, :subjectid => subjectid }, {}, waiting_task )
+ ValidationReport.new(uri)
+ end
+
end
class CrossvalidationReport
--
cgit v1.2.3
From b893941bc58260e2dd88d6d78433b65ba1dbe45b Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Fri, 6 May 2011 19:28:20 +0200
Subject: minor fixes: missing-values when splitting datasets, timeout handled
in rest-client-wrapper
---
lib/dataset.rb | 2 +-
lib/rest_client_wrapper.rb | 2 ++
2 files changed, 3 insertions(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/dataset.rb b/lib/dataset.rb
index 0a2f770..2b5759e 100644
--- a/lib/dataset.rb
+++ b/lib/dataset.rb
@@ -293,7 +293,7 @@ module OpenTox
else
compounds.each do |c|
features.each do |f|
- unless @data_entries[c][f]
+ if @data_entries[c]==nil or @data_entries[c][f]==nil
dataset.add(c,f,nil)
else
@data_entries[c][f].each do |v|
diff --git a/lib/rest_client_wrapper.rb b/lib/rest_client_wrapper.rb
index dac24dc..747a353 100644
--- a/lib/rest_client_wrapper.rb
+++ b/lib/rest_client_wrapper.rb
@@ -98,6 +98,8 @@ module OpenTox
rescue RestClient::RequestTimeout => ex
received_error ex.message, 408, nil, {:rest_uri => uri, :headers => headers, :payload => payload}
+ rescue Errno::ETIMEDOUT => ex
+ received_error ex.message, 408, nil, {:rest_uri => uri, :headers => headers, :payload => payload}
rescue Errno::ECONNREFUSED => ex
received_error ex.message, 500, nil, {:rest_uri => uri, :headers => headers, :payload => payload}
rescue RestClient::ExceptionWithResponse => ex
--
cgit v1.2.3
From 0f1e80c3dcbbbc0d8b2f916de68d6d0c86b53ec2 Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Fri, 6 May 2011 19:29:55 +0200
Subject: read acceptValue from ambit datasets, set acceptValue when create
dataset from csv/excel
---
lib/feature.rb | 13 -------------
lib/parser.rb | 40 ++++++++++++++++++++++++++++------------
2 files changed, 28 insertions(+), 25 deletions(-)
(limited to 'lib')
diff --git a/lib/feature.rb b/lib/feature.rb
index f6e2dfd..b631e46 100644
--- a/lib/feature.rb
+++ b/lib/feature.rb
@@ -16,19 +16,6 @@ module OpenTox
feature
end
- # provides domain (possible target values) of classification feature
- # @return [Array] list with possible target values
- def domain
- if metadata[OT.acceptValue]
- raise "accept value found, remove hack and implement correctly"
- else
- if @uri=~/feature\/26221/ || @uri=~/feature\/221726/
- return ["mutagen" , "nonmutagen"]
- end
- return [true, false]
- end
- end
-
# provides feature type, possible types are "regression" or "classification"
# @return [String] feature type, unknown if OT.isA property is unknown/ not set
def feature_type
diff --git a/lib/parser.rb b/lib/parser.rb
index db746c1..7bdee95 100644
--- a/lib/parser.rb
+++ b/lib/parser.rb
@@ -163,6 +163,7 @@ module OpenTox
data = {}
feature_values = {}
feature = {}
+ feature_accept_values = {}
other_statements = {}
`rapper -i rdfxml -o ntriples #{file.path} 2>/dev/null`.each_line do |line|
triple = line.chomp.split(' ',3)
@@ -182,6 +183,9 @@ module OpenTox
if triple[2]=~/#{OT.Compound}/i and !data[triple[0]]
data[triple[0]] = {:compound => triple[0], :values => []}
end
+ when /#{OT.acceptValue}/i # acceptValue in ambit datasets is only provided in dataset/ no in dataset//features
+ feature_accept_values[triple[0]] = [] unless feature_accept_values[triple[0]]
+ feature_accept_values[triple[0]] << triple[2]
else
end
end
@@ -192,20 +196,25 @@ module OpenTox
@dataset.add_compound(entry[:compound])
else
entry[:values].each do |value_id|
- split = feature_values[value_id].split(/\^\^/)
- case split[-1]
- when XSD.double, XSD.float
- value = split.first.to_f
- when XSD.boolean
- value = split.first=~/(?i)true/ ? true : false
- else
- value = split.first
+ if feature_values[value_id]
+ split = feature_values[value_id].split(/\^\^/)
+ case split[-1]
+ when XSD.double, XSD.float
+ value = split.first.to_f
+ when XSD.boolean
+ value = split.first=~/(?i)true/ ? true : false
+ else
+ value = split.first
+ end
end
@dataset.add entry[:compound],feature[value_id],value
end
end
end
load_features subjectid
+ feature_accept_values.each do |feature, values|
+ @dataset.features[feature][OT.acceptValue] = values
+ end
@dataset.metadata = load_metadata(subjectid)
@dataset
end
@@ -348,16 +357,23 @@ module OpenTox
when OT.NominalFeature
case value.to_s
when TRUE_REGEXP
- @dataset.add(compound.uri, feature, true )
+ val = true
when FALSE_REGEXP
- @dataset.add(compound.uri, feature, false )
+ val = false
end
when OT.NumericFeature
- @dataset.add compound.uri, feature, value.to_f
+ val = value.to_f
when OT.StringFeature
- @dataset.add compound.uri, feature, value.to_s
+ val = value.to_s
@activity_errors << smiles+", "+row.join(", ")
end
+ if val!=nil
+ @dataset.add(compound.uri, feature, val)
+ if type!=OT.NumericFeature
+ @dataset.features[feature][OT.acceptValue] = [] unless @dataset.features[feature][OT.acceptValue]
+ @dataset.features[feature][OT.acceptValue] << val.to_s unless @dataset.features[feature][OT.acceptValue].include?(val.to_s)
+ end
+ end
end
end
--
cgit v1.2.3
From 4d8ca4a4d057a197dbfe34e16950ea5433e9819a Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Mon, 9 May 2011 14:01:44 +0200
Subject: add list method to validation and crossvalidation objects
---
lib/validation.rb | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
(limited to 'lib')
diff --git a/lib/validation.rb b/lib/validation.rb
index 8fa95bb..08dc4ab 100644
--- a/lib/validation.rb
+++ b/lib/validation.rb
@@ -12,6 +12,18 @@ module OpenTox
val
end
+ # returns a filtered list of validation uris
+ # @param [Hash,optional] params, validation-params to filter the uris (could be model, training_dataset, ..)
+ # @return [Array]
+ def self.list( params={} )
+ filter_string = ""
+ params.each do |k,v|
+ filter_string = "?" if filter_string.length==0
+ filter_string += k.to_s+"="+v
+ end
+ (OpenTox::RestClientWrapper.get(CONFIG[:services]["opentox-validation"]+filter_string).split("\n"))
+ end
+
# creates a training test split validation, waits until it finishes, may take some time
# @param [Hash] params (required:algorithm_uri,dataset_uri,prediction_feature, optional:algorithm_params,split_ratio(0.67),random_seed(1))
# @param [String,optional] subjectid
@@ -95,6 +107,18 @@ module OpenTox
cv.load_metadata( subjectid )
cv
end
+
+ # returns a filtered list of crossvalidation uris
+ # @param [Hash,optional] params, crossvalidation-params to filter the uris (could be algorithm, dataset, ..)
+ # @return [Array]
+ def self.list( params={} )
+ filter_string = ""
+ params.each do |k,v|
+ filter_string = "?" if filter_string.length==0
+ filter_string += k.to_s+"="+v
+ end
+ (OpenTox::RestClientWrapper.get(File.join(CONFIG[:services]["opentox-validation"],"crossvalidation")+filter_string).split("\n"))
+ end
# creates a crossvalidations, waits until it finishes, may take some time
# @param [Hash] params (required:algorithm_uri,dataset_uri,prediction_feature, optional:algorithm_params,num_folds(10),random_seed(1),stratified(false))
--
cgit v1.2.3
From 41851663e591433fec1b021b88aa77a8fb0d37b0 Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Mon, 9 May 2011 05:53:09 -0700
Subject: Hotfix: Gaussian Decay for neighbors
---
lib/algorithm.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/algorithm.rb b/lib/algorithm.rb
index 167c964..21a5729 100644
--- a/lib/algorithm.rb
+++ b/lib/algorithm.rb
@@ -165,7 +165,7 @@ module OpenTox
# @param [Hash] params Keys `:similarity_algorithm,:p_values` are required
# @return [Hash] Hash with keys `:prediction, :confidence`
def self.local_svm_regression(neighbors,params )
- sims = neighbors.collect{ |n| n[:similarity] } # similarity values between query and neighbors
+ sims = neighbors.collect{ |n| Algorithm.gauss(n[:similarity]) } # similarity values between query and neighbors
conf = sims.inject{|sum,x| sum + x }
acts = neighbors.collect do |n|
act = n[:activity]
--
cgit v1.2.3
From 88af0ff8e54406f6bd4322a2d0ea93ade2c5bbbd Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Mon, 9 May 2011 05:53:45 -0700
Subject: Hotfix: Gaussian Decay for neighbors
---
lib/algorithm.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/algorithm.rb b/lib/algorithm.rb
index 008e7fe..abf10d4 100644
--- a/lib/algorithm.rb
+++ b/lib/algorithm.rb
@@ -165,7 +165,7 @@ module OpenTox
# @param [Hash] params Keys `:similarity_algorithm,:p_values` are required
# @return [Hash] Hash with keys `:prediction, :confidence`
def self.local_svm_regression(neighbors,params )
- sims = neighbors.collect{ |n| n[:similarity] } # similarity values between query and neighbors
+ sims = neighbors.collect{ |n| Algorithm.gauss(n[:similarity]) } # similarity values between query and neighbors
conf = sims.inject{|sum,x| sum + x }
acts = neighbors.collect do |n|
act = n[:activity]
--
cgit v1.2.3
From f999b42afbb4387d99b2c91a79f84654408cbab1 Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Tue, 10 May 2011 08:29:27 +0200
Subject: Added bal
---
lib/model.rb | 102 ++++++++++++++++++++++++++++++++++++++++++++++-------------
1 file changed, 80 insertions(+), 22 deletions(-)
(limited to 'lib')
diff --git a/lib/model.rb b/lib/model.rb
index 048de85..9442897 100644
--- a/lib/model.rb
+++ b/lib/model.rb
@@ -23,7 +23,7 @@ module OpenTox
# Generic OpenTox model class for all API compliant services
class Generic
include Model
-
+
# Find Generic Opentox Model via URI, and loads metadata, could raise NotFound/NotAuthorized error
# @param [String] uri Model URI
# @return [OpenTox::Model::Generic] Model instance
@@ -34,12 +34,12 @@ module OpenTox
raise "could not load model metadata '"+uri.to_s+"'" if model.metadata==nil or model.metadata.size==0
model
end
-
- # provides feature type, possible types are "regression" or "classification"
- # @return [String] feature type, "unknown" if type could not be estimated
+
+ # provides feature type, possible types are "regression" or "classification"
+ # @return [String] feature type, "unknown" if type could not be estimated
def feature_type(subjectid=nil)
return @feature_type if @feature_type
-
+
# dynamically perform restcalls if necessary
load_metadata(subjectid) if @metadata==nil or @metadata.size==0 or (@metadata.size==1 && @metadata.values[0]==@uri)
algorithm = OpenTox::Algorithm::Generic.find(@metadata[OT.algorithm], subjectid)
@@ -60,9 +60,9 @@ module OpenTox
raise "unknown model "+type_indicators.inspect unless @feature_type
@feature_type
end
-
+
end
-
+
# Lazy Structure Activity Relationship class
class Lazar
@@ -78,7 +78,7 @@ module OpenTox
else
super CONFIG[:services]["opentox-model"]
end
-
+
@metadata[OT.algorithm] = File.join(CONFIG[:services]["opentox-algorithm"],"lazar")
@features = []
@@ -178,8 +178,59 @@ module OpenTox
return @prediction_dataset if database_activity(subjectid)
- neighbors
- prediction = eval("#{@prediction_algorithm}(@neighbors,{:similarity_algorithm => @similarity_algorithm, :p_values => @p_values})")
+
+ # AM: Balancing, see http://www.maunz.de/wordpress/opentox/2011/balanced-lazar
+ l = Array.new # larger
+ s = Array.new # smaller fraction
+ if metadata[RDF.type] == [OTA.ClassificationLazySingleTarget]
+ @fingerprints.each do |training_compound,training_features|
+ @activities[training_compound].each do |act|
+ case act.to_s
+ when "false"
+ l << training_compound
+ when "true"
+ s << training_compound
+ else
+ LOGGER.warn "BLAZAR: Activity #{act.to_s} should not be reached."
+ end
+ end
+ end
+ if s.size > l.size then
+ l,s = s,l # happy swapping
+ LOGGER.info "BLAZAR: |s|=#{s.size}, |l|=#{l.size}."
+ end
+ # determine ratio
+ modulo = l.size.divmod(s.size)# modulo[0]=ratio, modulo[1]=rest
+ LOGGER.info "BLAZAR: Balance: #{modulo[0]}, rest #{modulo[1]}."
+ end
+
+ # AM: Balanced predictions
+ addon = (modulo[1].to_f/modulo[0]).ceil # what will be added in each round
+ slack = modulo[1].divmod(addon)[1] # what remains for the last round
+ position = 0
+ predictions = Array.new
+
+ @collect_neighbors = {}
+ predictions = []
+ for i in 1..modulo[0] do
+ (i == modulo[0]) && (slack>0) ? lr_size = s.size + slack : lr_size = s.size + addon # determine fraction
+ LOGGER.info "BLAZAR: Neighbors round #{i}: #{position} + #{lr_size}."
+ neighbors(s, l, position, lr_size) # get ratio fraction of larger part
+ predictions << eval("#{@prediction_algorithm}(@neighbors,{:similarity_algorithm => @similarity_algorithm, :p_values => @p_values})")
+ position = position + lr_size
+ end
+ @neighbors = @collect_neighbors.values # AM: get all neighbors
+
+ prediction={}
+ begin
+ p_sum=0.0
+ predictions.each do |p|
+ p[:prediction] == false ? p_sum = p_sum - p[:confidence].to_f : p_sum = p_sum + p[:confidence].to_f
+ end
+ prediction = { :prediction => (p_sum<0.0 ? false : true), :confidence => p_sum.abs/predictions.size } # AM: get mean
+ rescue Exception => e
+ LOGGER.error "BLAZAR failed in prediction: "+e.class.to_s+": "+e.message
+ end
prediction_feature_uri = File.join( @prediction_dataset.uri, "feature", "prediction", File.basename(@metadata[OT.dependentVariables]),@prediction_dataset.compounds.size.to_s)
# TODO: fix dependentVariable
@@ -269,23 +320,30 @@ module OpenTox
end
# Find neighbors and store them as object variable
- def neighbors
-
+ def neighbors(s=nil, l=nil, start=nil, offset=nil)
@compound_features = eval("#{@feature_calculation_algorithm}(@compound,@features)") if @feature_calculation_algorithm
@neighbors = []
- @fingerprints.each do |training_compound,training_features|
- sim = eval("#{@similarity_algorithm}(@compound_features,training_features,@p_values)")
- if sim > @min_sim
- @activities[training_compound].each do |act|
- @neighbors << {
- :compound => training_compound,
- :similarity => sim,
- :features => training_features,
- :activity => act
- }
+ begin
+ #@fingerprints.each do |training_compound,training_features| # AM: this is original by CH
+ [ l[start, offset ] , s ].flatten.each do |training_compound| # AM: access only a balanced subset
+ training_features = @fingerprints[training_compound]
+ sim = eval("#{@similarity_algorithm}(@compound_features,training_features,@p_values)")
+ if sim > @min_sim
+ @activities[training_compound].each do |act|
+ this_neighbor = {
+ :compound => training_compound,
+ :similarity => sim,
+ :features => training_features,
+ :activity => act
+ }
+ @neighbors << this_neighbor
+ @collect_neighbors[training_compound] = this_neighbor
+ end
end
end
+ rescue Exception => e
+ LOGGER.error "BLAZAR failed in neighbors: "+e.class.to_s+": "+e.message
end
end
--
cgit v1.2.3
From 1d8c7d6dfa513cd7c8ad642248db24e0d1e3a199 Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Tue, 10 May 2011 09:02:38 +0200
Subject: Using Best prediction only
---
lib/model.rb | 25 ++++++++++++-------------
1 file changed, 12 insertions(+), 13 deletions(-)
(limited to 'lib')
diff --git a/lib/model.rb b/lib/model.rb
index 9442897..a4d6d85 100644
--- a/lib/model.rb
+++ b/lib/model.rb
@@ -210,28 +210,28 @@ module OpenTox
position = 0
predictions = Array.new
- @collect_neighbors = {}
- predictions = []
+ prediction_best=nil
+ neighbors_best=nil
+
+ begin
for i in 1..modulo[0] do
(i == modulo[0]) && (slack>0) ? lr_size = s.size + slack : lr_size = s.size + addon # determine fraction
LOGGER.info "BLAZAR: Neighbors round #{i}: #{position} + #{lr_size}."
neighbors(s, l, position, lr_size) # get ratio fraction of larger part
- predictions << eval("#{@prediction_algorithm}(@neighbors,{:similarity_algorithm => @similarity_algorithm, :p_values => @p_values})")
+ prediction = eval("#{@prediction_algorithm}(@neighbors,{:similarity_algorithm => @similarity_algorithm, :p_values => @p_values})")
+ if prediction[:confidence].abs > prediction_best[:confidence].abs || prediction_best.nil?
+ prediction_best=prediction
+ neighbors_best=@neighbors
+ end
position = position + lr_size
end
- @neighbors = @collect_neighbors.values # AM: get all neighbors
-
- prediction={}
- begin
- p_sum=0.0
- predictions.each do |p|
- p[:prediction] == false ? p_sum = p_sum - p[:confidence].to_f : p_sum = p_sum + p[:confidence].to_f
- end
- prediction = { :prediction => (p_sum<0.0 ? false : true), :confidence => p_sum.abs/predictions.size } # AM: get mean
rescue Exception => e
LOGGER.error "BLAZAR failed in prediction: "+e.class.to_s+": "+e.message
end
+ prediction=prediction_best
+ @neighbors=neighbors_best
+
prediction_feature_uri = File.join( @prediction_dataset.uri, "feature", "prediction", File.basename(@metadata[OT.dependentVariables]),@prediction_dataset.compounds.size.to_s)
# TODO: fix dependentVariable
@prediction_dataset.metadata[OT.dependentVariables] = prediction_feature_uri
@@ -338,7 +338,6 @@ module OpenTox
:activity => act
}
@neighbors << this_neighbor
- @collect_neighbors[training_compound] = this_neighbor
end
end
end
--
cgit v1.2.3
From 2af934ddc033d7d8a737d88eb4ee175955ad4a0a Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Tue, 10 May 2011 11:11:34 +0200
Subject: Fixed first prediction case
---
lib/model.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/model.rb b/lib/model.rb
index a4d6d85..3d64f32 100644
--- a/lib/model.rb
+++ b/lib/model.rb
@@ -219,7 +219,7 @@ module OpenTox
LOGGER.info "BLAZAR: Neighbors round #{i}: #{position} + #{lr_size}."
neighbors(s, l, position, lr_size) # get ratio fraction of larger part
prediction = eval("#{@prediction_algorithm}(@neighbors,{:similarity_algorithm => @similarity_algorithm, :p_values => @p_values})")
- if prediction[:confidence].abs > prediction_best[:confidence].abs || prediction_best.nil?
+ if prediction_best.nil? || prediction[:confidence].abs > prediction_best[:confidence].abs
prediction_best=prediction
neighbors_best=@neighbors
end
--
cgit v1.2.3
From 51cb900375a575208cd210da5093773d9e10cfdd Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Tue, 10 May 2011 12:23:19 +0200
Subject: minor fix: load metadata when 'find'ing a report in validation.rb
---
lib/validation.rb | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
(limited to 'lib')
diff --git a/lib/validation.rb b/lib/validation.rb
index 08dc4ab..d58d36e 100644
--- a/lib/validation.rb
+++ b/lib/validation.rb
@@ -46,7 +46,6 @@ module OpenTox
@report.uri
end
-
# creates a validation object from crossvaldiation statistics, raise error if not found
# (as crossvaldiation statistics are returned as an average valdidation over all folds)
# @param [String] crossvalidation uri
@@ -162,9 +161,10 @@ module OpenTox
# @param [String,optional] subjectid
# @return [OpenTox::ValidationReport]
def self.find( uri, subjectid=nil )
- # PENDING load report data?
OpenTox::RestClientWrapper.get(uri,{:subjectid => subjectid})
- ValidationReport.new(uri)
+ rep = ValidationReport.new(uri)
+ rep.load_metadata( subjectid )
+ rep
end
# finds ValidationReport for a particular validation
@@ -200,7 +200,9 @@ module OpenTox
def self.find( uri, subjectid=nil )
# PENDING load report data?
OpenTox::RestClientWrapper.get(uri,{:subjectid => subjectid})
- CrossvalidationReport.new(uri)
+ rep = CrossvalidationReport.new(uri)
+ rep.load_metadata( subjectid )
+ rep
end
# finds CrossvalidationReport for a particular crossvalidation
--
cgit v1.2.3
From 305f3caa692dd977df07cbc5ec195521e2a135fa Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Tue, 10 May 2011 16:43:05 +0200
Subject: Added Gauss patch
---
lib/algorithm.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/algorithm.rb b/lib/algorithm.rb
index 008e7fe..abf10d4 100644
--- a/lib/algorithm.rb
+++ b/lib/algorithm.rb
@@ -165,7 +165,7 @@ module OpenTox
# @param [Hash] params Keys `:similarity_algorithm,:p_values` are required
# @return [Hash] Hash with keys `:prediction, :confidence`
def self.local_svm_regression(neighbors,params )
- sims = neighbors.collect{ |n| n[:similarity] } # similarity values between query and neighbors
+ sims = neighbors.collect{ |n| Algorithm.gauss(n[:similarity]) } # similarity values between query and neighbors
conf = sims.inject{|sum,x| sum + x }
acts = neighbors.collect do |n|
act = n[:activity]
--
cgit v1.2.3
From 524a68d8429b8adc16bd8073774f9305cb7138a0 Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Wed, 11 May 2011 12:13:37 +0200
Subject: Added balance patch
---
lib/parser.rb | 19 +++++++++++++++----
1 file changed, 15 insertions(+), 4 deletions(-)
(limited to 'lib')
diff --git a/lib/parser.rb b/lib/parser.rb
index db746c1..dc5f675 100644
--- a/lib/parser.rb
+++ b/lib/parser.rb
@@ -348,16 +348,27 @@ module OpenTox
when OT.NominalFeature
case value.to_s
when TRUE_REGEXP
- @dataset.add(compound.uri, feature, true )
+ #@dataset.add(compound.uri, feature, true )
+ val=true
when FALSE_REGEXP
- @dataset.add(compound.uri, feature, false )
+ #@dataset.add(compound.uri, feature, false )
+ val=false
end
when OT.NumericFeature
- @dataset.add compound.uri, feature, value.to_f
+ #@dataset.add compound.uri, feature, value.to_f
+ val = value.to_f
when OT.StringFeature
- @dataset.add compound.uri, feature, value.to_s
+ #@dataset.add compound.uri, feature, value.to_s
+ val = value.to_s
@activity_errors << smiles+", "+row.join(", ")
end
+ if val!=nil
+ @dataset.add(compound.uri, feature, val)
+ if type!=OT.NumericFeature
+ @dataset.features[feature][OT.acceptValue] = [] unless @dataset.features[feature][OT.acceptValue]
+ @dataset.features[feature][OT.acceptValue] << val.to_s unless @dataset.features[feature][OT.acceptValue].include?(val.to_s)
+ end
+ end
end
end
--
cgit v1.2.3
From 03a87a832162ccf17b6f0ebfda126e3622530ca3 Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Wed, 11 May 2011 15:56:55 +0200
Subject: Further Martin patch
---
lib/feature.rb | 9 +--------
1 file changed, 1 insertion(+), 8 deletions(-)
(limited to 'lib')
diff --git a/lib/feature.rb b/lib/feature.rb
index f6e2dfd..eb0b869 100644
--- a/lib/feature.rb
+++ b/lib/feature.rb
@@ -19,14 +19,7 @@ module OpenTox
# provides domain (possible target values) of classification feature
# @return [Array] list with possible target values
def domain
- if metadata[OT.acceptValue]
- raise "accept value found, remove hack and implement correctly"
- else
- if @uri=~/feature\/26221/ || @uri=~/feature\/221726/
- return ["mutagen" , "nonmutagen"]
- end
- return [true, false]
- end
+ return [true, false]
end
# provides feature type, possible types are "regression" or "classification"
--
cgit v1.2.3
From c6d34021f92610ff7dfcc72473c09ba08586687a Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Thu, 12 May 2011 12:39:47 +0200
Subject: set accept-header via html-param ?media=asdf (analogous to ambits
services)
---
lib/overwrite.rb | 1 +
1 file changed, 1 insertion(+)
(limited to 'lib')
diff --git a/lib/overwrite.rb b/lib/overwrite.rb
index fffcb14..df4e1b7 100644
--- a/lib/overwrite.rb
+++ b/lib/overwrite.rb
@@ -8,6 +8,7 @@ before {
$url_provider = self
# stupid internet explorer does not ask for text/html, add this manually
request.env['HTTP_ACCEPT'] += ";text/html" if request.env["HTTP_USER_AGENT"]=~/MSIE/
+ request.env['HTTP_ACCEPT']=request.params["media"] if request.params["media"]
}
# Error handling
--
cgit v1.2.3
From cb3c1dd486ba0a891c81886c1546553fc17f01b8 Mon Sep 17 00:00:00 2001
From: ch
Date: Thu, 12 May 2011 16:58:14 +0000
Subject: RDF serialization of metadata fixed for multiple RDF.types
---
lib/serializer.rb | 18 +++++++++++++++---
1 file changed, 15 insertions(+), 3 deletions(-)
(limited to 'lib')
diff --git a/lib/serializer.rb b/lib/serializer.rb
index 644a09f..e4cb541 100644
--- a/lib/serializer.rb
+++ b/lib/serializer.rb
@@ -26,6 +26,8 @@ module OpenTox
OT.Algorithm => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
OT.Parameter => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
OT.Task => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
+ OTA.PatternMiningSupervised => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
+
#classes for validation
OT.Validation => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
OT.ClassificationStatistics => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
@@ -40,10 +42,10 @@ module OpenTox
OT.compound => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
OT.feature => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
OT.dataEntry => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
- OT.acceptValue => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
OT.values => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
OT.algorithm => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
OT.parameters => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
+
#object props for validation#
OT.model => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
OT.trainingDataset => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
@@ -73,6 +75,8 @@ module OpenTox
OT.hasStatus => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
OT.resultURI => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
OT.percentageCompleted => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.acceptValue => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+
# annotation props for validation
OT.numUnpredicted => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
OT.crossvalidationFold => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
@@ -256,7 +260,8 @@ module OpenTox
def add_metadata(uri,metadata)
id = 0
metadata.each do |u,v|
- if v.is_a? Array and u == OT.parameters
+ #if v.is_a? Array and (u == OT.parameters or u == RDF.type)
+ if v.is_a? Array and u == OT.parameters#or u == RDF.type)
@object[uri][u] = [] unless @object[uri][u]
v.each do |value|
id+=1
@@ -267,7 +272,13 @@ module OpenTox
@object[genid][name] = [{"type" => type(entry), "value" => entry }]
end
end
- else # v.is_a? String
+ elsif v.is_a? Array and u == RDF.type
+ @object[uri] = {} unless @object[uri]
+ v.each do |value|
+ @object[uri][u] = [] unless @object[uri][u]
+ @object[uri][u] << {"type" => type(value), "value" => value }
+ end
+ elsif v.is_a? String
@object[uri] = {} unless @object[uri]
@object[uri][u] = [{"type" => type(v), "value" => v }]
end
@@ -309,6 +320,7 @@ module OpenTox
OT.value => v
}
@object[feature][RDF["type"]] << { "type" => "uri", "value" => featuretype(value) }
+ #@object[feature][RDF["type"]] = { "type" => "uri", "value" => featuretype(value) }
end
# Serializers
--
cgit v1.2.3
From 153a19bc26e1a9dac35d286b90037bfc9d0e9c6b Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Fri, 13 May 2011 11:46:08 +0200
Subject: catch nil error if delete with subjectid but without AA_SERVER is
called
---
lib/authorization.rb | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
(limited to 'lib')
diff --git a/lib/authorization.rb b/lib/authorization.rb
index d9f900b..b23b92f 100644
--- a/lib/authorization.rb
+++ b/lib/authorization.rb
@@ -286,10 +286,12 @@ module OpenTox
# @return [Boolean]
def self.delete_policies_from_uri(uri, subjectid)
policies = list_uri_policies(uri, subjectid)
- policies.each do |policy|
- ret = delete_policy(policy, subjectid)
- LOGGER.debug "OpenTox::Authorization delete policy: #{policy} - with result: #{ret}"
- end
+ if policies
+ policies.each do |policy|
+ ret = delete_policy(policy, subjectid)
+ LOGGER.debug "OpenTox::Authorization delete policy: #{policy} - with result: #{ret}"
+ end
+ end
return true
end
--
cgit v1.2.3
From 5acd3b8cd36a0f5017e4858df3d4516876858324 Mon Sep 17 00:00:00 2001
From: mr
Date: Mon, 16 May 2011 15:53:03 +0200
Subject: remove internal administrative LDAP groups
---
lib/authorization.rb | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/authorization.rb b/lib/authorization.rb
index b23b92f..288733a 100644
--- a/lib/authorization.rb
+++ b/lib/authorization.rb
@@ -227,7 +227,9 @@ module OpenTox
begin
resource = RestClient::Resource.new("#{AA_SERVER}/opensso/identity/search")
grps = resource.post(:admin => subjectid, :attributes_names => "objecttype", :attributes_values_objecttype => "group")
- grps.split("\n").collect{|x| x.sub("string=","")}
+ grps = grps.split("\n").collect{|x| x.sub("string=","")}
+ grps.delete_if{|g|g=="MemberManagement"||g=="Webmasters"}
+ grps
rescue
[]
end
--
cgit v1.2.3
From 778df38c0991aef8de53702e8c6229dd6f43d1a2 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Mon, 16 May 2011 14:44:30 +0000
Subject: uri_available? fixed in helper.rb
---
lib/helper.rb | 10 ++--------
1 file changed, 2 insertions(+), 8 deletions(-)
(limited to 'lib')
diff --git a/lib/helper.rb b/lib/helper.rb
index af92419..3a6126a 100644
--- a/lib/helper.rb
+++ b/lib/helper.rb
@@ -44,14 +44,8 @@ helpers do
def uri_available?(urlStr)
url = URI.parse(urlStr)
- unless @subjectid
- Net::HTTP.start(url.host, url.port) do |http|
- return http.head(url.request_uri).code == "200"
- end
- else
- Net::HTTP.start(url.host, url.port) do |http|
- return http.post(url.request_uri, "subjectid=#{@subjectid}").code == "202"
- end
+ Net::HTTP.start(url.host, url.port) do |http|
+ return http.head("#{url.request_uri}?subjectid=#{CGI.escape @subjectid}").code == "200"
end
end
--
cgit v1.2.3
From 5c6cb977db89b12ddeb822eb09370c9ad32ad84b Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Mon, 16 May 2011 16:50:13 +0200
Subject: Fixed log taking (for exclusively positive values only)
---
lib/algorithm.rb | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/algorithm.rb b/lib/algorithm.rb
index abf10d4..130d305 100644
--- a/lib/algorithm.rb
+++ b/lib/algorithm.rb
@@ -167,9 +167,17 @@ module OpenTox
def self.local_svm_regression(neighbors,params )
sims = neighbors.collect{ |n| Algorithm.gauss(n[:similarity]) } # similarity values between query and neighbors
conf = sims.inject{|sum,x| sum + x }
+
+ # AM: Control log taking
+ take_logs=true
+ neighbors.each do |n|
+ if (! n[:activity].nil?) && (n[:activity].to_f < 0.0)
+ take_logs = false
+ end
+ end
acts = neighbors.collect do |n|
act = n[:activity]
- Math.log10(act.to_f)
+ take_logs ? Math.log10(act.to_f) : act.to_f
end # activities of neighbors for supervised learning
neighbor_matches = neighbors.collect{ |n| n[:features] } # as in classification: URIs of matches
--
cgit v1.2.3
From b247527ced213486629add9d8b5b739620a8abff Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Mon, 16 May 2011 17:28:59 +0200
Subject: Fixed exp
---
lib/algorithm.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/algorithm.rb b/lib/algorithm.rb
index 130d305..7fbe0dc 100644
--- a/lib/algorithm.rb
+++ b/lib/algorithm.rb
@@ -222,7 +222,7 @@ module OpenTox
@r.eval "sims<-as.kernelMatrix(matrix(sims,1))"
LOGGER.debug "Predicting ..."
@r.eval "p<-predict(model,sims)[1,1]"
- prediction = 10**(@r.p.to_f)
+ prediction = 10**(@r.p.to_f) if take_logs
LOGGER.debug "Prediction is: '" + prediction.to_s + "'."
@r.quit # free R
end
--
cgit v1.2.3
From b944a21b557b9628b3b6f7be990534b2f86f0884 Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Tue, 17 May 2011 10:47:58 +0200
Subject: fix validation statistics: convert num predictions to integer
---
lib/validation.rb | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
(limited to 'lib')
diff --git a/lib/validation.rb b/lib/validation.rb
index d58d36e..1a2497b 100644
--- a/lib/validation.rb
+++ b/lib/validation.rb
@@ -65,7 +65,7 @@ module OpenTox
def summary
if @metadata[OT.classificationStatistics]
res = {
- :nr_predictions => @metadata[OT.numInstances] - @metadata[OT.numUnpredicted],
+ :nr_predictions => @metadata[OT.numInstances].to_i - @metadata[OT.numUnpredicted].to_i,
:correct_predictions => @metadata[OT.classificationStatistics][OT.percentCorrect],
:weighted_area_under_roc => @metadata[OT.classificationStatistics][OT.weightedAreaUnderRoc],
}
@@ -83,7 +83,7 @@ module OpenTox
res
elsif @metadata[OT.regressionStatistics]
{
- :nr_predictions => @metadata[OT.numInstances] - @metadata[OT.numUnpredicted],
+ :nr_predictions => @metadata[OT.numInstances].to_i - @metadata[OT.numUnpredicted].to_i,
:r_square => @metadata[OT.regressionStatistics][OT.rSquare],
:root_mean_squared_error => @metadata[OT.regressionStatistics][OT.rootMeanSquaredError],
:mean_absolute_error => @metadata[OT.regressionStatistics][OT.meanAbsoluteError],
--
cgit v1.2.3
From 37a066e4cfe102d2e4edfaf3b4b9787bcbb3206f Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Tue, 17 May 2011 16:08:25 +0200
Subject: Initial version
---
lib/algorithm.rb | 62 ++++++++++++++++++++++++++++++++++++++++++--------------
1 file changed, 47 insertions(+), 15 deletions(-)
(limited to 'lib')
diff --git a/lib/algorithm.rb b/lib/algorithm.rb
index 7fbe0dc..16372ea 100644
--- a/lib/algorithm.rb
+++ b/lib/algorithm.rb
@@ -164,11 +164,7 @@ module OpenTox
# @param [Array] neighbors, each neighbor is a hash with keys `:similarity, :activity, :features`
# @param [Hash] params Keys `:similarity_algorithm,:p_values` are required
# @return [Hash] Hash with keys `:prediction, :confidence`
- def self.local_svm_regression(neighbors,params )
- sims = neighbors.collect{ |n| Algorithm.gauss(n[:similarity]) } # similarity values between query and neighbors
- conf = sims.inject{|sum,x| sum + x }
-
- # AM: Control log taking
+ def self.local_svm_regression(neighbors, params)
take_logs=true
neighbors.each do |n|
if (! n[:activity].nil?) && (n[:activity].to_f < 0.0)
@@ -180,10 +176,51 @@ module OpenTox
take_logs ? Math.log10(act.to_f) : act.to_f
end # activities of neighbors for supervised learning
- neighbor_matches = neighbors.collect{ |n| n[:features] } # as in classification: URIs of matches
+ sims = neighbors.collect{ |n| Algorithm.gauss(n[:similarity]) } # similarity values btwn q and nbors
+ prediction = local_sv_machine (neighbors, acts, sims, "svr", params)
+ prediction = take_logs ? 10**(prediction.to_f) : prediction.to_f
+ LOGGER.debug "Prediction is: '" + prediction.to_s + "'."
+
+ conf = sims.inject{|sum,x| sum + x }
+ confidence = conf/neighbors.size if neighbors.size > 0
+ {:prediction => prediction, :confidence => confidence}
+
+ end
+
+ # Local support vector classification from neighbors
+ # @param [Array] neighbors, each neighbor is a hash with keys `:similarity, :activity, :features`
+ # @param [Hash] params Keys `:similarity_algorithm,:p_values` are required
+ # @return [Hash] Hash with keys `:prediction, :confidence`
+ def self.local_svm_classification(neighbors, params)
+ acts = neighbors.collect do |n|
+ act = n[:activity]
+ end # activities of neighbors for supervised learning
+
+ sims = neighbors.collect{ |n| Algorithm.gauss(n[:similarity]) } # similarity values btwn q and nbors
+ prediction = local_sv_machine (neighbors, acts, sims, "svc", params)
+ prediction = prediction.to_f
+ LOGGER.debug "Prediction is: '" + prediction.to_s + "'."
+
+ conf = sims.inject{|sum,x| sum + x }
+ confidence = conf/neighbors.size if neighbors.size > 0
+ {:prediction => prediction, :confidence => confidence}
+
+ end
+
+ end
+
+ # Local support vector prediction. Not to be called directly (use local_svm_regression or local_svm_classification.
+ # @param [Array] neighbors, each neighbor is a hash with keys `:similarity, :activity, :features`
+ # @param [Array] acts, activities for neighbors.
+ # @param [Array] sims, similarities for neighbors.
+ # @param [String] type, one of "svr" (regression) or "svc" (classification).
+ # @param [Hash] params Keys `:similarity_algorithm,:p_values` are required
+ # @return [Numeric] A prediction value.
+ def self.local_sv_machine(neighbors, acts, sims, type, params)
+ neighbor_matches = neighbors.collect{ |n| n[:features] } # URIs of matches
gram_matrix = [] # square matrix of similarities between neighbors; implements weighted tanimoto kernel
if neighbor_matches.size == 0
- raise "No neighbors found"
+ raise "No neighbors found."
else
# gram matrix
(0..(neighbor_matches.length-1)).each do |i|
@@ -216,21 +253,16 @@ module OpenTox
# model + support vectors
LOGGER.debug "Creating SVM model ..."
- @r.eval "model<-ksvm(gram_matrix, y, kernel=matrix, type=\"nu-svr\", nu=0.8)"
+ @r.eval "model<-ksvm(gram_matrix, y, kernel=matrix, type=\"nu-#{type}\", nu=0.5)"
@r.eval "sv<-as.vector(SVindex(model))"
@r.eval "sims<-sims[sv]"
@r.eval "sims<-as.kernelMatrix(matrix(sims,1))"
LOGGER.debug "Predicting ..."
@r.eval "p<-predict(model,sims)[1,1]"
- prediction = 10**(@r.p.to_f) if take_logs
- LOGGER.debug "Prediction is: '" + prediction.to_s + "'."
+ prediction = @r.p
@r.quit # free R
end
- confidence = conf/neighbors.size if neighbors.size > 0
- {:prediction => prediction, :confidence => confidence}
-
- end
-
+ prediction
end
module Substructure
--
cgit v1.2.3
From 0e49be4d0ed4752d5988ed651d813f001e42c05b Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Tue, 17 May 2011 16:35:20 +0200
Subject: Fixed method scope
---
lib/algorithm.rb | 110 ++++++++++++++++++++++++++++---------------------------
1 file changed, 56 insertions(+), 54 deletions(-)
(limited to 'lib')
diff --git a/lib/algorithm.rb b/lib/algorithm.rb
index 16372ea..0a5b09f 100644
--- a/lib/algorithm.rb
+++ b/lib/algorithm.rb
@@ -177,7 +177,7 @@ module OpenTox
end # activities of neighbors for supervised learning
sims = neighbors.collect{ |n| Algorithm.gauss(n[:similarity]) } # similarity values btwn q and nbors
- prediction = local_sv_machine (neighbors, acts, sims, "svr", params)
+ prediction = local_svm(neighbors, acts, sims, "svr", params)
prediction = take_logs ? 10**(prediction.to_f) : prediction.to_f
LOGGER.debug "Prediction is: '" + prediction.to_s + "'."
@@ -197,7 +197,7 @@ module OpenTox
end # activities of neighbors for supervised learning
sims = neighbors.collect{ |n| Algorithm.gauss(n[:similarity]) } # similarity values btwn q and nbors
- prediction = local_sv_machine (neighbors, acts, sims, "svc", params)
+ prediction = local_svm (neighbors, acts, sims, "svc", params)
prediction = prediction.to_f
LOGGER.debug "Prediction is: '" + prediction.to_s + "'."
@@ -207,62 +207,64 @@ module OpenTox
end
- end
- # Local support vector prediction. Not to be called directly (use local_svm_regression or local_svm_classification.
- # @param [Array] neighbors, each neighbor is a hash with keys `:similarity, :activity, :features`
- # @param [Array] acts, activities for neighbors.
- # @param [Array] sims, similarities for neighbors.
- # @param [String] type, one of "svr" (regression) or "svc" (classification).
- # @param [Hash] params Keys `:similarity_algorithm,:p_values` are required
- # @return [Numeric] A prediction value.
- def self.local_sv_machine(neighbors, acts, sims, type, params)
- neighbor_matches = neighbors.collect{ |n| n[:features] } # URIs of matches
- gram_matrix = [] # square matrix of similarities between neighbors; implements weighted tanimoto kernel
- if neighbor_matches.size == 0
- raise "No neighbors found."
- else
- # gram matrix
- (0..(neighbor_matches.length-1)).each do |i|
- gram_matrix[i] = [] unless gram_matrix[i]
- # upper triangle
- ((i+1)..(neighbor_matches.length-1)).each do |j|
- sim = eval("#{params[:similarity_algorithm]}(neighbor_matches[i], neighbor_matches[j], params[:p_values])")
- gram_matrix[i][j] = Algorithm.gauss(sim)
- gram_matrix[j] = [] unless gram_matrix[j]
- gram_matrix[j][i] = gram_matrix[i][j] # lower triangle
+ # Local support vector prediction from neighbors.
+ # Not to be called directly (use local_svm_regression or local_svm_classification.
+ # @param [Array] neighbors, each neighbor is a hash with keys `:similarity, :activity, :features`
+ # @param [Array] acts, activities for neighbors.
+ # @param [Array] sims, similarities for neighbors.
+ # @param [String] type, one of "svr" (regression) or "svc" (classification).
+ # @param [Hash] params Keys `:similarity_algorithm,:p_values` are required
+ # @return [Numeric] A prediction value.
+ def self.local_svm(neighbors, acts, sims, type, params)
+ neighbor_matches = neighbors.collect{ |n| n[:features] } # URIs of matches
+ gram_matrix = [] # square matrix of similarities between neighbors; implements weighted tanimoto kernel
+ if neighbor_matches.size == 0
+ raise "No neighbors found."
+ else
+ # gram matrix
+ (0..(neighbor_matches.length-1)).each do |i|
+ gram_matrix[i] = [] unless gram_matrix[i]
+ # upper triangle
+ ((i+1)..(neighbor_matches.length-1)).each do |j|
+ sim = eval("#{params[:similarity_algorithm]}(neighbor_matches[i], neighbor_matches[j], params[:p_values])")
+ gram_matrix[i][j] = Algorithm.gauss(sim)
+ gram_matrix[j] = [] unless gram_matrix[j]
+ gram_matrix[j][i] = gram_matrix[i][j] # lower triangle
+ end
+ gram_matrix[i][i] = 1.0
end
- gram_matrix[i][i] = 1.0
- end
- #LOGGER.debug gram_matrix.to_yaml
- @r = RinRuby.new(false,false) # global R instance leads to Socket errors after a large number of requests
- @r.eval "library('kernlab')" # this requires R package "kernlab" to be installed
- LOGGER.debug "Setting R data ..."
- # set data
- @r.gram_matrix = gram_matrix.flatten
- @r.n = neighbor_matches.size
- @r.y = acts
- @r.sims = sims
+ #LOGGER.debug gram_matrix.to_yaml
+ @r = RinRuby.new(false,false) # global R instance leads to Socket errors after a large number of requests
+ @r.eval "library('kernlab')" # this requires R package "kernlab" to be installed
+ LOGGER.debug "Setting R data ..."
+ # set data
+ @r.gram_matrix = gram_matrix.flatten
+ @r.n = neighbor_matches.size
+ @r.y = acts
+ @r.sims = sims
+
+ LOGGER.debug "Preparing R data ..."
+ # prepare data
+ @r.eval "y<-as.vector(y)"
+ @r.eval "gram_matrix<-as.kernelMatrix(matrix(gram_matrix,n,n))"
+ @r.eval "sims<-as.vector(sims)"
+
+ # model + support vectors
+ LOGGER.debug "Creating SVM model ..."
+ @r.eval "model<-ksvm(gram_matrix, y, kernel=matrix, type=\"nu-#{type}\", nu=0.5)"
+ @r.eval "sv<-as.vector(SVindex(model))"
+ @r.eval "sims<-sims[sv]"
+ @r.eval "sims<-as.kernelMatrix(matrix(sims,1))"
+ LOGGER.debug "Predicting ..."
+ @r.eval "p<-predict(model,sims)[1,1]"
+ prediction = @r.p
+ @r.quit # free R
+ end
+ prediction
+ end
- LOGGER.debug "Preparing R data ..."
- # prepare data
- @r.eval "y<-as.vector(y)"
- @r.eval "gram_matrix<-as.kernelMatrix(matrix(gram_matrix,n,n))"
- @r.eval "sims<-as.vector(sims)"
-
- # model + support vectors
- LOGGER.debug "Creating SVM model ..."
- @r.eval "model<-ksvm(gram_matrix, y, kernel=matrix, type=\"nu-#{type}\", nu=0.5)"
- @r.eval "sv<-as.vector(SVindex(model))"
- @r.eval "sims<-sims[sv]"
- @r.eval "sims<-as.kernelMatrix(matrix(sims,1))"
- LOGGER.debug "Predicting ..."
- @r.eval "p<-predict(model,sims)[1,1]"
- prediction = @r.p
- @r.quit # free R
- end
- prediction
end
module Substructure
--
cgit v1.2.3
From 4372e80a38c5228f3b7d0372f92195e62500b743 Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Tue, 17 May 2011 16:40:12 +0200
Subject: Add debug
---
lib/algorithm.rb | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/algorithm.rb b/lib/algorithm.rb
index 0a5b09f..ec5748d 100644
--- a/lib/algorithm.rb
+++ b/lib/algorithm.rb
@@ -178,7 +178,8 @@ module OpenTox
sims = neighbors.collect{ |n| Algorithm.gauss(n[:similarity]) } # similarity values btwn q and nbors
prediction = local_svm(neighbors, acts, sims, "svr", params)
- prediction = take_logs ? 10**(prediction.to_f) : prediction.to_f
+ LOGGER.debug "Prediction is: '" + prediction.to_s + "'."
+ prediction = (take_logs ? 10**(prediction.to_f) : prediction.to_f)
LOGGER.debug "Prediction is: '" + prediction.to_s + "'."
conf = sims.inject{|sum,x| sum + x }
--
cgit v1.2.3
From cf6d40be3f31d473f69216f1453e2ca0ddf82130 Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Tue, 17 May 2011 16:46:26 +0200
Subject: nu 0.8 again to pass tests
---
lib/algorithm.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/algorithm.rb b/lib/algorithm.rb
index ec5748d..4cb80e3 100644
--- a/lib/algorithm.rb
+++ b/lib/algorithm.rb
@@ -254,7 +254,7 @@ module OpenTox
# model + support vectors
LOGGER.debug "Creating SVM model ..."
- @r.eval "model<-ksvm(gram_matrix, y, kernel=matrix, type=\"nu-#{type}\", nu=0.5)"
+ @r.eval "model<-ksvm(gram_matrix, y, kernel=matrix, type=\"nu-#{type}\", nu=0.8)"
@r.eval "sv<-as.vector(SVindex(model))"
@r.eval "sims<-sims[sv]"
@r.eval "sims<-as.kernelMatrix(matrix(sims,1))"
--
cgit v1.2.3
From 4081ac06ddf8dafeebc93dfc28c4ef54f64a844d Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Wed, 18 May 2011 17:57:37 +0200
Subject: add opentox object for new algorithm comparison report
---
lib/validation.rb | 49 ++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 48 insertions(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/validation.rb b/lib/validation.rb
index 1a2497b..d7a337c 100644
--- a/lib/validation.rb
+++ b/lib/validation.rb
@@ -198,7 +198,6 @@ module OpenTox
# @param [String,optional] subjectid
# @return [OpenTox::CrossvalidationReport]
def self.find( uri, subjectid=nil )
- # PENDING load report data?
OpenTox::RestClientWrapper.get(uri,{:subjectid => subjectid})
rep = CrossvalidationReport.new(uri)
rep.load_metadata( subjectid )
@@ -227,6 +226,54 @@ module OpenTox
end
end
+
+ class AlgorithmComparisonReport
+ include OpenTox
+
+ # finds AlgorithmComparisonReport via uri, raises error if not found
+ # @param [String] uri
+ # @param [String,optional] subjectid
+ # @return [OpenTox::CrossvalidationReport]
+ def self.find( uri, subjectid=nil )
+ OpenTox::RestClientWrapper.get(uri,{:subjectid => subjectid})
+ rep = AlgorithmComparisonReport.new(uri)
+ rep.load_metadata( subjectid )
+ rep
+ end
+
+ # finds AlgorithmComparisonReport for a particular crossvalidation
+ # @param [String] crossvalidation uri
+ # @param [String,optional] subjectid
+ # @return [OpenTox::AlgorithmComparisonReport] nil if no report found
+ def self.find_for_crossvalidation( crossvalidation_uri, subjectid=nil )
+ uris = RestClientWrapper.get(File.join(CONFIG[:services]["opentox-validation"],
+ "/report/algorithm_comparison?crossvalidation="+crossvalidation_uri), {:subjectid => subjectid}).chomp.split("\n")
+ uris.size==0 ? nil : AlgorithmComparisonReport.new(uris[-1])
+ end
+
+ # creates a crossvalidation report via crossvalidation
+ # @param [Hash] crossvalidation uri_hash, see example
+ # @param [String,optional] subjectid
+ # @param [OpenTox::Task,optional] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
+ # @return [OpenTox::AlgorithmComparisonReport]
+ # example for hash:
+ # { :lazar-bbrc => [ http://host/validation/crossvalidation/x1, http://host/validation/crossvalidation/x2 ],
+ # :lazar-last => [ http://host/validation/crossvalidation/xy, http://host/validation/crossvalidation/xy ] }
+ def self.create( crossvalidation_uri_hash, subjectid=nil, waiting_task=nil )
+ identifier = []
+ validation_uris = []
+ crossvalidation_uri_hash.each do |id, uris|
+ uris.each do |uri|
+ identifier << id
+ validation_uris << uri
+ end
+ end
+ uri = RestClientWrapper.post(File.join(CONFIG[:services]["opentox-validation"],"/report/algorithm_comparison"),
+ { :validation_uris => validation_uris.join(","), :identifier => identifier.join(","), :subjectid => subjectid }, {}, waiting_task )
+ AlgorithmComparisonReport.new(uri)
+ end
+ end
+
class QMRFReport
include OpenTox
--
cgit v1.2.3
From cf0fd8003c373bd9216823ff2065231696ddfbcb Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Thu, 19 May 2011 10:08:17 +0200
Subject: Set nu to 0.5
---
lib/algorithm.rb | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
(limited to 'lib')
diff --git a/lib/algorithm.rb b/lib/algorithm.rb
index 4cb80e3..fb5fd7f 100644
--- a/lib/algorithm.rb
+++ b/lib/algorithm.rb
@@ -178,7 +178,6 @@ module OpenTox
sims = neighbors.collect{ |n| Algorithm.gauss(n[:similarity]) } # similarity values btwn q and nbors
prediction = local_svm(neighbors, acts, sims, "svr", params)
- LOGGER.debug "Prediction is: '" + prediction.to_s + "'."
prediction = (take_logs ? 10**(prediction.to_f) : prediction.to_f)
LOGGER.debug "Prediction is: '" + prediction.to_s + "'."
@@ -254,7 +253,7 @@ module OpenTox
# model + support vectors
LOGGER.debug "Creating SVM model ..."
- @r.eval "model<-ksvm(gram_matrix, y, kernel=matrix, type=\"nu-#{type}\", nu=0.8)"
+ @r.eval "model<-ksvm(gram_matrix, y, kernel=matrix, type=\"nu-#{type}\", nu=0.5)"
@r.eval "sv<-as.vector(SVindex(model))"
@r.eval "sims<-sims[sv]"
@r.eval "sims<-as.kernelMatrix(matrix(sims,1))"
--
cgit v1.2.3
From afefbdf05549c298387821c3a441d1de701291e0 Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Thu, 19 May 2011 12:12:23 +0200
Subject: Added SVM classification
---
lib/algorithm.rb | 61 +++++++++++++++++++++++++++++++++++++-------------------
1 file changed, 40 insertions(+), 21 deletions(-)
(limited to 'lib')
diff --git a/lib/algorithm.rb b/lib/algorithm.rb
index fb5fd7f..9402eab 100644
--- a/lib/algorithm.rb
+++ b/lib/algorithm.rb
@@ -177,7 +177,7 @@ module OpenTox
end # activities of neighbors for supervised learning
sims = neighbors.collect{ |n| Algorithm.gauss(n[:similarity]) } # similarity values btwn q and nbors
- prediction = local_svm(neighbors, acts, sims, "svr", params)
+ prediction = local_svm(neighbors, acts, sims, "nu-svr", params)
prediction = (take_logs ? 10**(prediction.to_f) : prediction.to_f)
LOGGER.debug "Prediction is: '" + prediction.to_s + "'."
@@ -197,9 +197,15 @@ module OpenTox
end # activities of neighbors for supervised learning
sims = neighbors.collect{ |n| Algorithm.gauss(n[:similarity]) } # similarity values btwn q and nbors
- prediction = local_svm (neighbors, acts, sims, "svc", params)
- prediction = prediction.to_f
- LOGGER.debug "Prediction is: '" + prediction.to_s + "'."
+
+
+ acts_f = acts.collect {|v| v == true ? 1.0 : 0.0}
+ begin
+ prediction = local_svm (neighbors, acts_f, sims, "C-bsvc", params)
+ LOGGER.debug "Prediction is: '" + prediction.to_s + "'."
+ rescue Exception => e
+ LOGGER.debug "Prediction failed."
+ end
conf = sims.inject{|sum,x| sum + x }
confidence = conf/neighbors.size if neighbors.size > 0
@@ -213,7 +219,7 @@ module OpenTox
# @param [Array] neighbors, each neighbor is a hash with keys `:similarity, :activity, :features`
# @param [Array] acts, activities for neighbors.
# @param [Array] sims, similarities for neighbors.
- # @param [String] type, one of "svr" (regression) or "svc" (classification).
+ # @param [String] type, one of "nu-svr" (regression) or "C-bsvc" (classification).
# @param [Hash] params Keys `:similarity_algorithm,:p_values` are required
# @return [Numeric] A prediction value.
def self.local_svm(neighbors, acts, sims, type, params)
@@ -245,22 +251,35 @@ module OpenTox
@r.y = acts
@r.sims = sims
- LOGGER.debug "Preparing R data ..."
- # prepare data
- @r.eval "y<-as.vector(y)"
- @r.eval "gram_matrix<-as.kernelMatrix(matrix(gram_matrix,n,n))"
- @r.eval "sims<-as.vector(sims)"
-
- # model + support vectors
- LOGGER.debug "Creating SVM model ..."
- @r.eval "model<-ksvm(gram_matrix, y, kernel=matrix, type=\"nu-#{type}\", nu=0.5)"
- @r.eval "sv<-as.vector(SVindex(model))"
- @r.eval "sims<-sims[sv]"
- @r.eval "sims<-as.kernelMatrix(matrix(sims,1))"
- LOGGER.debug "Predicting ..."
- @r.eval "p<-predict(model,sims)[1,1]"
- prediction = @r.p
- @r.quit # free R
+ begin
+ LOGGER.debug "Preparing R data ..."
+ # prepare data
+ @r.eval "y<-as.vector(y)"
+ @r.eval "gram_matrix<-as.kernelMatrix(matrix(gram_matrix,n,n))"
+ @r.eval "sims<-as.vector(sims)"
+
+ # model + support vectors
+ LOGGER.debug "Creating SVM model ..."
+ @r.eval "model<-ksvm(gram_matrix, y, kernel=matrix, type=\"#{type}\", nu=0.5)"
+ @r.eval "sv<-as.vector(SVindex(model))"
+ @r.eval "sims<-sims[sv]"
+ @r.eval "sims<-as.kernelMatrix(matrix(sims,1))"
+ LOGGER.debug "Predicting ..."
+ if type == "nu-svr"
+ @r.eval "p<-predict(model,sims)[1,1]"
+ elsif type == "C-bsvc"
+ @r.eval "p<-predict(model,sims)"
+ end
+ if type == "nu-svr"
+ prediction = @r.p
+ elsif type == "C-bsvc"
+ prediction = (@r.p.to_f == 1.0 ? true : false)
+ end
+ @r.quit # free R
+ rescue Exception => e
+ LOGGER.debug "#{e.class}: #{e.message} #{e.backtrace}"
+ end
+
end
prediction
end
--
cgit v1.2.3
From e34c80eadcd40482a765cda861b92ab5c1250049 Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Thu, 19 May 2011 13:08:28 +0200
Subject: Added Exception handling
---
lib/algorithm.rb | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
(limited to 'lib')
diff --git a/lib/algorithm.rb b/lib/algorithm.rb
index 9402eab..5b41cbf 100644
--- a/lib/algorithm.rb
+++ b/lib/algorithm.rb
@@ -177,9 +177,13 @@ module OpenTox
end # activities of neighbors for supervised learning
sims = neighbors.collect{ |n| Algorithm.gauss(n[:similarity]) } # similarity values btwn q and nbors
- prediction = local_svm(neighbors, acts, sims, "nu-svr", params)
- prediction = (take_logs ? 10**(prediction.to_f) : prediction.to_f)
- LOGGER.debug "Prediction is: '" + prediction.to_s + "'."
+ begin
+ prediction = local_svm(neighbors, acts, sims, "nu-svr", params)
+ prediction = (take_logs ? 10**(prediction.to_f) : prediction.to_f)
+ LOGGER.debug "Prediction is: '" + prediction.to_s + "'."
+ rescue Exception => e
+ LOGGER.debug "#{e.class}: #{e.message} #{e.backtrace}"
+ end
conf = sims.inject{|sum,x| sum + x }
confidence = conf/neighbors.size if neighbors.size > 0
@@ -195,16 +199,13 @@ module OpenTox
acts = neighbors.collect do |n|
act = n[:activity]
end # activities of neighbors for supervised learning
-
- sims = neighbors.collect{ |n| Algorithm.gauss(n[:similarity]) } # similarity values btwn q and nbors
-
-
acts_f = acts.collect {|v| v == true ? 1.0 : 0.0}
+ sims = neighbors.collect{ |n| Algorithm.gauss(n[:similarity]) } # similarity values btwn q and nbors
begin
prediction = local_svm (neighbors, acts_f, sims, "C-bsvc", params)
LOGGER.debug "Prediction is: '" + prediction.to_s + "'."
rescue Exception => e
- LOGGER.debug "Prediction failed."
+ LOGGER.debug "#{e.class}: #{e.message} #{e.backtrace}"
end
conf = sims.inject{|sum,x| sum + x }
--
cgit v1.2.3
From 30478c4dd18b56048b6e190027daef1fc6608230 Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Thu, 19 May 2011 16:55:34 +0200
Subject: Fixed digression class / regr
---
lib/model.rb | 83 ++++++++++++++++++++++++++++++++++++++++--------------------
1 file changed, 55 insertions(+), 28 deletions(-)
(limited to 'lib')
diff --git a/lib/model.rb b/lib/model.rb
index 3d64f32..7acd8f2 100644
--- a/lib/model.rb
+++ b/lib/model.rb
@@ -179,10 +179,10 @@ module OpenTox
return @prediction_dataset if database_activity(subjectid)
- # AM: Balancing, see http://www.maunz.de/wordpress/opentox/2011/balanced-lazar
- l = Array.new # larger
- s = Array.new # smaller fraction
- if metadata[RDF.type] == [OTA.ClassificationLazySingleTarget]
+ if metadata[RDF.type] == [OTA.ClassificationLazySingleTarget]
+ # AM: Balancing, see http://www.maunz.de/wordpress/opentox/2011/balanced-lazar
+ l = Array.new # larger
+ s = Array.new # smaller fraction
@fingerprints.each do |training_compound,training_features|
@activities[training_compound].each do |act|
case act.to_s
@@ -202,36 +202,41 @@ module OpenTox
# determine ratio
modulo = l.size.divmod(s.size)# modulo[0]=ratio, modulo[1]=rest
LOGGER.info "BLAZAR: Balance: #{modulo[0]}, rest #{modulo[1]}."
- end
- # AM: Balanced predictions
- addon = (modulo[1].to_f/modulo[0]).ceil # what will be added in each round
- slack = modulo[1].divmod(addon)[1] # what remains for the last round
- position = 0
- predictions = Array.new
+ # AM: Balanced predictions
+ addon = (modulo[1].to_f/modulo[0]).ceil # what will be added in each round
+ slack = modulo[1].divmod(addon)[1] # what remains for the last round
+ position = 0
+ predictions = Array.new
- prediction_best=nil
- neighbors_best=nil
+ prediction_best=nil
+ neighbors_best=nil
- begin
- for i in 1..modulo[0] do
- (i == modulo[0]) && (slack>0) ? lr_size = s.size + slack : lr_size = s.size + addon # determine fraction
- LOGGER.info "BLAZAR: Neighbors round #{i}: #{position} + #{lr_size}."
- neighbors(s, l, position, lr_size) # get ratio fraction of larger part
- prediction = eval("#{@prediction_algorithm}(@neighbors,{:similarity_algorithm => @similarity_algorithm, :p_values => @p_values})")
- if prediction_best.nil? || prediction[:confidence].abs > prediction_best[:confidence].abs
- prediction_best=prediction
- neighbors_best=@neighbors
+ begin
+ for i in 1..modulo[0] do
+ (i == modulo[0]) && (slack>0) ? lr_size = s.size + slack : lr_size = s.size + addon # determine fraction
+ LOGGER.info "BLAZAR: Neighbors round #{i}: #{position} + #{lr_size}."
+ neighbors(s, l, position, lr_size) # get ratio fraction of larger part
+ prediction = eval("#{@prediction_algorithm}(@neighbors,{:similarity_algorithm => @similarity_algorithm, :p_values => @p_values})")
+ if prediction_best.nil? || prediction[:confidence].abs > prediction_best[:confidence].abs
+ prediction_best=prediction
+ neighbors_best=@neighbors
+ end
+ position = position + lr_size
+ end
+ rescue Exception => e
+ LOGGER.error "BLAZAR failed in prediction: "+e.class.to_s+": "+e.message
end
- position = position + lr_size
- end
- rescue Exception => e
- LOGGER.error "BLAZAR failed in prediction: "+e.class.to_s+": "+e.message
- end
- prediction=prediction_best
- @neighbors=neighbors_best
+ prediction=prediction_best
+ @neighbors=neighbors_best
+ ### END AM balanced predictions
+ else # regression case: no balancing
+ neighbors
+ prediction = eval("#{@prediction_algorithm}(@neighbors,{:similarity_algorithm => @similarity_algorithm, :p_values => @p_values})")
+ end
+
prediction_feature_uri = File.join( @prediction_dataset.uri, "feature", "prediction", File.basename(@metadata[OT.dependentVariables]),@prediction_dataset.compounds.size.to_s)
# TODO: fix dependentVariable
@prediction_dataset.metadata[OT.dependentVariables] = prediction_feature_uri
@@ -347,6 +352,28 @@ module OpenTox
end
+
+ # Find neighbors and store them as object variable
+ def neighbors
+
+ @compound_features = eval("#{@feature_calculation_algorithm}(@compound,@features)") if @feature_calculation_algorithm
+
+ @neighbors = []
+ @fingerprints.each do |training_compound,training_features|
+ sim = eval("#{@similarity_algorithm}(@compound_features,training_features,@p_values)")
+ if sim > @min_sim
+ @activities[training_compound].each do |act|
+ @neighbors << {
+ :compound => training_compound,
+ :similarity => sim,
+ :features => training_features,
+ :activity => act
+ }
+ end
+ end
+ end
+ end
+
# Find database activities and store them in @prediction_dataset
# @return [Boolean] true if compound has databasse activities, false if not
def database_activity(subjectid)
--
cgit v1.2.3
From 32b7faa44ef70194e0ae1c5e43948eea785f9d04 Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Thu, 19 May 2011 17:03:50 +0200
Subject: Fixed neighbor selection
---
lib/model.rb | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
(limited to 'lib')
diff --git a/lib/model.rb b/lib/model.rb
index 7acd8f2..998d2dc 100644
--- a/lib/model.rb
+++ b/lib/model.rb
@@ -216,7 +216,7 @@ module OpenTox
for i in 1..modulo[0] do
(i == modulo[0]) && (slack>0) ? lr_size = s.size + slack : lr_size = s.size + addon # determine fraction
LOGGER.info "BLAZAR: Neighbors round #{i}: #{position} + #{lr_size}."
- neighbors(s, l, position, lr_size) # get ratio fraction of larger part
+ neighbors_balanced(s, l, position, lr_size) # get ratio fraction of larger part
prediction = eval("#{@prediction_algorithm}(@neighbors,{:similarity_algorithm => @similarity_algorithm, :p_values => @p_values})")
if prediction_best.nil? || prediction[:confidence].abs > prediction_best[:confidence].abs
prediction_best=prediction
@@ -325,7 +325,7 @@ module OpenTox
end
# Find neighbors and store them as object variable
- def neighbors(s=nil, l=nil, start=nil, offset=nil)
+ def neighbors_balanced(s, l, start, offset)
@compound_features = eval("#{@feature_calculation_algorithm}(@compound,@features)") if @feature_calculation_algorithm
@neighbors = []
--
cgit v1.2.3
From 8c78bf2358338cf5f795a65c9b1c21a48474169f Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Fri, 20 May 2011 10:52:32 +0200
Subject: change location of to-html-opentox-image to local validation service
---
lib/to-html.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/to-html.rb b/lib/to-html.rb
index 6785974..66a3e74 100644
--- a/lib/to-html.rb
+++ b/lib/to-html.rb
@@ -1,5 +1,5 @@
-OT_LOGO = "http://opentox.informatik.uni-freiburg.de/ot-logo.png"
+OT_LOGO = File.join(CONFIG[:services]["opentox-validation"],"resources/ot-logo.png")
class String
--
cgit v1.2.3
From 0b936c71d8a1d5effa6c29d5ee9c227fff18a070 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Mon, 23 May 2011 14:03:02 +0000
Subject: owl-dl fixed for model and prediction datasets
---
lib/dataset.rb | 7 ++-
lib/model.rb | 136 ++++++++++++++++++++++++++++++------------------------
lib/serializer.rb | 27 +++++++----
3 files changed, 95 insertions(+), 75 deletions(-)
(limited to 'lib')
diff --git a/lib/dataset.rb b/lib/dataset.rb
index 4005c1c..4dc4296 100644
--- a/lib/dataset.rb
+++ b/lib/dataset.rb
@@ -179,7 +179,6 @@ module OpenTox
end
end
-=begin
# Detect feature type(s) in the dataset
# @return [String] `classification", "regression", "mixed" or unknown`
def feature_type(subjectid=nil)
@@ -193,6 +192,7 @@ module OpenTox
"unknown"
end
end
+=begin
=end
# Get Spreadsheet representation
@@ -369,12 +369,11 @@ module OpenTox
end
def value(compound)
- @data_entries[compound.uri].collect{|f,v| v.first if f.match(/prediction/)}.compact.first
+ @data_entries[compound.uri].collect{|f,v| v.first if f.match(/value/)}.compact.first
end
def confidence(compound)
- feature_uri = @data_entries[compound.uri].collect{|f,v| f if f.match(/prediction/)}.compact.first
- @features[feature_uri][OT.confidence]
+ @data_entries[compound.uri].collect{|f,v| v.first if f.match(/confidence/)}.compact.first
end
def descriptors(compound)
diff --git a/lib/model.rb b/lib/model.rb
index 998d2dc..d46152d 100644
--- a/lib/model.rb
+++ b/lib/model.rb
@@ -164,8 +164,6 @@ module OpenTox
features = {}
unless @prediction_dataset
- #@prediction_dataset = cached_prediction
- #return @prediction_dataset if cached_prediction
@prediction_dataset = Dataset.create(CONFIG[:services]["opentox-dataset"], subjectid)
@prediction_dataset.add_metadata( {
OT.hasSource => @uri,
@@ -237,38 +235,90 @@ module OpenTox
prediction = eval("#{@prediction_algorithm}(@neighbors,{:similarity_algorithm => @similarity_algorithm, :p_values => @p_values})")
end
- prediction_feature_uri = File.join( @prediction_dataset.uri, "feature", "prediction", File.basename(@metadata[OT.dependentVariables]),@prediction_dataset.compounds.size.to_s)
- # TODO: fix dependentVariable
- @prediction_dataset.metadata[OT.dependentVariables] = prediction_feature_uri
+ # TODO: reasonable feature name
+ #prediction_feature_uri = File.join( @prediction_dataset.uri, "feature", "prediction", File.basename(@metadata[OT.dependentVariables]),@prediction_dataset.compounds.size.to_s)
+ value_feature_uri = File.join( @prediction_dataset.uri, "feature", "prediction", File.basename(@metadata[OT.dependentVariables]),"value")
+ confidence_feature_uri = File.join( @prediction_dataset.uri, "feature", "prediction", File.basename(@metadata[OT.dependentVariables]),"confidence")
+ prediction_feature_uris = {value_feature_uri => prediction[:prediction], confidence_feature_uri => prediction[:confidence]}
+ prediction_feature_uris[value_feature_uri] = "No similar compounds in training dataset." if @neighbors.size == 0 or prediction[:prediction].nil?
+
+
+ #@prediction_dataset.metadata[OT.dependentVariables] = prediction_feature_uri
+ @prediction_dataset.metadata[OT.dependentVariables] = @metadata[OT.dependentVariables]
+
+=begin
if @neighbors.size == 0
- @prediction_dataset.add_feature(prediction_feature_uri, {
- RDF.type => [OT.MeasuredFeature],
- OT.hasSource => @uri,
- DC.creator => @uri,
- DC.title => URI.decode(File.basename( @metadata[OT.dependentVariables] )),
- OT.error => "No similar compounds in training dataset.",
- OT.parameters => [{DC.title => "compound_uri", OT.paramValue => compound_uri}]
- })
- @prediction_dataset.add @compound.uri, prediction_feature_uri, prediction[:prediction]
+ prediction_feature_uris.each do |prediction_feature_uri,value|
+ @prediction_dataset.add_feature(prediction_feature_uri, {
+ RDF.type => [OT.MeasuredFeature],
+ OT.hasSource => @uri,
+ DC.creator => @uri,
+ DC.title => URI.decode(File.basename( @metadata[OT.dependentVariables] )),
+ OT.error => "No similar compounds in training dataset.",
+ #OT.parameters => [{DC.title => "compound_uri", OT.paramValue => compound_uri}]
+ })
+ @prediction_dataset.add @compound.uri, prediction_feature_uri, value
+ end
else
+=end
+ prediction_feature_uris.each do |prediction_feature_uri,value|
+ @prediction_dataset.metadata[OT.predictedVariables] = [] unless @prediction_dataset.metadata[OT.predictedVariables]
+ @prediction_dataset.metadata[OT.predictedVariables] << prediction_feature_uri
@prediction_dataset.add_feature(prediction_feature_uri, {
RDF.type => [OT.ModelPrediction],
OT.hasSource => @uri,
DC.creator => @uri,
DC.title => URI.decode(File.basename( @metadata[OT.dependentVariables] )),
- OT.prediction => prediction[:prediction],
- OT.confidence => prediction[:confidence],
- OT.parameters => [{DC.title => "compound_uri", OT.paramValue => compound_uri}]
+ # TODO: factor information to value
})
- @prediction_dataset.add @compound.uri, prediction_feature_uri, prediction[:prediction]
+ #OT.prediction => prediction[:prediction],
+ #OT.confidence => prediction[:confidence],
+ #OT.parameters => [{DC.title => "compound_uri", OT.paramValue => compound_uri}]
+ @prediction_dataset.add @compound.uri, prediction_feature_uri, value
+ end
- if verbose
- if @feature_calculation_algorithm == "Substructure.match"
- f = 0
- @compound_features.each do |feature|
- feature_uri = File.join( @prediction_dataset.uri, "feature", "descriptor", f.to_s)
+ if verbose
+ if @feature_calculation_algorithm == "Substructure.match"
+ f = 0
+ @compound_features.each do |feature|
+ feature_uri = File.join( @prediction_dataset.uri, "feature", "descriptor", f.to_s)
+ features[feature] = feature_uri
+ @prediction_dataset.add_feature(feature_uri, {
+ RDF.type => [OT.Substructure],
+ OT.smarts => feature,
+ OT.pValue => @p_values[feature],
+ OT.effect => @effects[feature]
+ })
+ @prediction_dataset.add @compound.uri, feature_uri, true
+ f+=1
+ end
+ else
+ @compound_features.each do |feature|
+ features[feature] = feature
+ @prediction_dataset.add @compound.uri, feature, true
+ end
+ end
+ n = 0
+ @neighbors.each do |neighbor|
+ neighbor_uri = File.join( @prediction_dataset.uri, "feature", "neighbor", n.to_s )
+ @prediction_dataset.add_feature(neighbor_uri, {
+ OT.compound => neighbor[:compound],
+ OT.similarity => neighbor[:similarity],
+ OT.measuredActivity => neighbor[:activity],
+ RDF.type => [OT.Neighbor]
+ })
+ @prediction_dataset.add @compound.uri, neighbor_uri, true
+ f = 0 unless f
+ neighbor[:features].each do |feature|
+ if @feature_calculation_algorithm == "Substructure.match"
+ feature_uri = File.join( @prediction_dataset.uri, "feature", "descriptor", f.to_s) unless feature_uri = features[feature]
+ else
+ feature_uri = feature
+ end
+ @prediction_dataset.add neighbor[:compound], feature_uri, true
+ unless features.has_key? feature
features[feature] = feature_uri
@prediction_dataset.add_feature(feature_uri, {
RDF.type => [OT.Substructure],
@@ -276,49 +326,13 @@ module OpenTox
OT.pValue => @p_values[feature],
OT.effect => @effects[feature]
})
- @prediction_dataset.add @compound.uri, feature_uri, true
f+=1
end
- else
- @compound_features.each do |feature|
- features[feature] = feature
- @prediction_dataset.add @compound.uri, feature, true
- end
- end
- n = 0
- @neighbors.each do |neighbor|
- neighbor_uri = File.join( @prediction_dataset.uri, "feature", "neighbor", n.to_s )
- @prediction_dataset.add_feature(neighbor_uri, {
- OT.compound => neighbor[:compound],
- OT.similarity => neighbor[:similarity],
- OT.measuredActivity => neighbor[:activity],
- RDF.type => [OT.Neighbor]
- })
- @prediction_dataset.add @compound.uri, neighbor_uri, true
- f = 0 unless f
- neighbor[:features].each do |feature|
- if @feature_calculation_algorithm == "Substructure.match"
- feature_uri = File.join( @prediction_dataset.uri, "feature", "descriptor", f.to_s) unless feature_uri = features[feature]
- else
- feature_uri = feature
- end
- @prediction_dataset.add neighbor[:compound], feature_uri, true
- unless features.has_key? feature
- features[feature] = feature_uri
- @prediction_dataset.add_feature(feature_uri, {
- RDF.type => [OT.Substructure],
- OT.smarts => feature,
- OT.pValue => @p_values[feature],
- OT.effect => @effects[feature]
- })
- f+=1
- end
- end
- n+=1
end
- # what happens with dataset predictions?
+ n+=1
end
end
+ #end
@prediction_dataset.save(subjectid)
@prediction_dataset
diff --git a/lib/serializer.rb b/lib/serializer.rb
index e4cb541..78e7709 100644
--- a/lib/serializer.rb
+++ b/lib/serializer.rb
@@ -17,6 +17,7 @@ module OpenTox
# this should come from opentox.owl
OT.Compound => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
OT.Feature => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
+ OT.Model => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
OT.NominalFeature => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
OT.NumericFeature => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
OT.StringFeature => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
@@ -27,6 +28,8 @@ module OpenTox
OT.Parameter => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
OT.Task => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
OTA.PatternMiningSupervised => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
+ OTA.ClassificationLazySingleTarget => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
+ OTA.RegressionLazySingleTarget => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
#classes for validation
OT.Validation => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
@@ -45,6 +48,9 @@ module OpenTox
OT.values => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
OT.algorithm => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
OT.parameters => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
+ OT.featureDataset => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
+ OT.dependentVariables => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
+ OT.paramValue => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
#object props for validation#
OT.model => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
@@ -126,7 +132,7 @@ module OpenTox
OT.hasSource => { RDF["type"] => [{ "type" => "uri", "value" => OWL.DatatypeProperty }] } ,
OT.value => { RDF["type"] => [{ "type" => "uri", "value" => OWL.DatatypeProperty }] } ,
OT.paramScope => { RDF["type"] => [{ "type" => "uri", "value" => OWL.DatatypeProperty }] } ,
- OT.paramValue => { RDF["type"] => [{ "type" => "uri", "value" => OWL.DatatypeProperty }] } ,
+ #OT.paramValue => { RDF["type"] => [{ "type" => "uri", "value" => OWL.DatatypeProperty }] } ,
}
@data_entries = {}
@@ -157,23 +163,16 @@ module OpenTox
# Add a dataset
# @param [String] uri Dataset URI
def add_dataset(dataset)
-
@dataset = dataset.uri
-
@object[dataset.uri] = { RDF["type"] => [{ "type" => "uri", "value" => OT.Dataset }] }
-
add_metadata dataset.uri, dataset.metadata
-
dataset.compounds.each { |compound| add_compound compound }
-
dataset.features.each { |feature,metadata| add_feature feature,metadata }
-
dataset.data_entries.each do |compound,entry|
entry.each do |feature,values|
values.each { |value| add_data_entry compound,feature,value }
end
end
-
end
# Add a algorithm
@@ -188,6 +187,13 @@ module OpenTox
def add_model(uri,metadata)
@object[uri] = { RDF["type"] => [{ "type" => "uri", "value" => OT.Model }] }
add_metadata uri, metadata
+ @object[metadata[OT.featureDataset]] = { RDF["type"] => [{ "type" => "uri", "value" => OT.Dataset }] }
+ @object[metadata[OT.trainingDataset]] = { RDF["type"] => [{ "type" => "uri", "value" => OT.Dataset }] }
+ @object[metadata[OT.dependentVariables]] = { RDF["type"] => [{ "type" => "uri", "value" => OT.Feature }] }
+ # TODO: add algorithms from parameters
+ @object["http://ot-dev.in-silico.ch/algorithm/fminer/bbrc"] = { RDF["type"] => [{ "type" => "uri", "value" => OT.Algorithm }] }
+ @object["http://ot-dev.in-silico.ch/algorithm/fminer/last"] = { RDF["type"] => [{ "type" => "uri", "value" => OT.Algorithm }] }
+ @object["http://ot-dev.in-silico.ch/algorithm/lazar"] = { RDF["type"] => [{ "type" => "uri", "value" => OT.Algorithm }] }
end
# Add a task
@@ -272,7 +278,7 @@ module OpenTox
@object[genid][name] = [{"type" => type(entry), "value" => entry }]
end
end
- elsif v.is_a? Array and u == RDF.type
+ elsif v.is_a? Array #and u == RDF.type
@object[uri] = {} unless @object[uri]
v.each do |value|
@object[uri][u] = [] unless @object[uri][u]
@@ -354,7 +360,8 @@ module OpenTox
# @return [text/plain] Object OWL-DL in RDF/XML format
def to_rdfxml
Tempfile.open("owl-serializer"){|f| f.write(self.to_ntriples); @path = f.path}
- `rapper -i ntriples -f 'xmlns:ot="#{OT.uri}"' -f 'xmlns:dc="#{DC.uri}"' -f 'xmlns:rdf="#{RDF.uri}"' -f 'xmlns:owl="#{OWL.uri}"' -o rdfxml #{@path} 2>/dev/null`
+ # TODO: add base uri for ist services
+ `rapper -i ntriples -f 'xmlns:ot="#{OT.uri}"' -f 'xmlns:ota="#{OTA.uri}"' -f 'xmlns:dc="#{DC.uri}"' -f 'xmlns:rdf="#{RDF.uri}"' -f 'xmlns:owl="#{OWL.uri}"' -o rdfxml #{@path} 2>/dev/null`
end
# Convert to JSON as specified in http://n2.talis.com/wiki/RDF_JSON_Specification
--
cgit v1.2.3
From 87eb7cc1e079821c2f7c5e101e7e392e9bd10f00 Mon Sep 17 00:00:00 2001
From: davor
Date: Tue, 24 May 2011 09:35:11 +0200
Subject: Fixing regression detection
---
lib/parser.rb | 66 +++++++++++++++++++++++++++++++++++++++++++++--------------
1 file changed, 51 insertions(+), 15 deletions(-)
(limited to 'lib')
diff --git a/lib/parser.rb b/lib/parser.rb
index 7bdee95..8deaa91 100644
--- a/lib/parser.rb
+++ b/lib/parser.rb
@@ -277,7 +277,23 @@ module OpenTox
def load_spreadsheet(book)
book.default_sheet = 0
add_features book.row(1)
- 2.upto(book.last_row) { |i| add_values book.row(i) }
+
+ # AM: fix mixed read in
+ regression_features=false
+ 2.upto(book.last_row) { |i|
+ row = book.row(i)
+ smiles = row.shift
+ row.each_index do |i|
+ value = row[i]
+ type = feature_type(value)
+ if type == OT.NumericFeature
+ regression_features=true
+ break
+ end
+ end
+ }
+
+ 2.upto(book.last_row) { |i| add_values book.row(i),regression_features }
warnings
@dataset
end
@@ -289,7 +305,23 @@ module OpenTox
row = 0
input = csv.split("\n")
add_features split_row(input.shift)
- input.each { |row| add_values split_row(row) }
+
+
+ # AM: fix mixed read in
+ regression_features=false
+ input.each { |row|
+ row = split_row(row)
+ smiles = row.shift
+ row.each_index do |i|
+ value = row[i]
+ type = feature_type(value)
+ if type == OT.NumericFeature
+ regression_features=true
+ break
+ end
+ end
+ }
+ input.each { |row| add_values split_row(row),regression_features }
warnings
@dataset
end
@@ -335,7 +367,7 @@ module OpenTox
end
end
- def add_values(row)
+ def add_values(row, regression_features=false)
smiles = row.shift
compound = Compound.from_smiles(smiles)
@@ -353,19 +385,23 @@ module OpenTox
@feature_types[feature] << type
- case type
- when OT.NominalFeature
- case value.to_s
- when TRUE_REGEXP
- val = true
- when FALSE_REGEXP
- val = false
- end
- when OT.NumericFeature
+ if (regression_features)
val = value.to_f
- when OT.StringFeature
- val = value.to_s
- @activity_errors << smiles+", "+row.join(", ")
+ else
+ case type
+ when OT.NominalFeature
+ case value.to_s
+ when TRUE_REGEXP
+ val = true
+ when FALSE_REGEXP
+ val = false
+ end
+ when OT.NumericFeature
+ val = value.to_f
+ when OT.StringFeature
+ val = value.to_s
+ @activity_errors << smiles+", "+row.join(", ")
+ end
end
if val!=nil
@dataset.add(compound.uri, feature, val)
--
cgit v1.2.3
From 4a7ba2adb0743cd225ad5c2cf9f71c896d87b157 Mon Sep 17 00:00:00 2001
From: davor
Date: Tue, 24 May 2011 10:45:53 +0200
Subject: Created dedicated function for value sweeping
---
lib/parser.rb | 35 +++++++++++++++++------------------
1 file changed, 17 insertions(+), 18 deletions(-)
(limited to 'lib')
diff --git a/lib/parser.rb b/lib/parser.rb
index 8deaa91..4984292 100644
--- a/lib/parser.rb
+++ b/lib/parser.rb
@@ -282,15 +282,8 @@ module OpenTox
regression_features=false
2.upto(book.last_row) { |i|
row = book.row(i)
- smiles = row.shift
- row.each_index do |i|
- value = row[i]
- type = feature_type(value)
- if type == OT.NumericFeature
- regression_features=true
- break
- end
- end
+ regression_features = detect_regression_features row
+ break if regression_features=true
}
2.upto(book.last_row) { |i| add_values book.row(i),regression_features }
@@ -311,21 +304,15 @@ module OpenTox
regression_features=false
input.each { |row|
row = split_row(row)
- smiles = row.shift
- row.each_index do |i|
- value = row[i]
- type = feature_type(value)
- if type == OT.NumericFeature
- regression_features=true
- break
- end
- end
+ regression_features = detect_regression_features row
+ break if regression_features=true
}
input.each { |row| add_values split_row(row),regression_features }
warnings
@dataset
end
+
private
def warnings
@@ -367,6 +354,18 @@ module OpenTox
end
end
+ def detect_regression_features row
+ regression_features=false
+ row.each_index do |i|
+ value = row[i]
+ type = feature_type(value)
+ if type == OT.NumericFeature
+ regression_features=true
+ end
+ end
+ regression_features
+ end
+
def add_values(row, regression_features=false)
smiles = row.shift
--
cgit v1.2.3
From 8a20cf940c346fd04649d3c3c8f7ad4c1fcb20cb Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Tue, 24 May 2011 14:00:16 +0200
Subject: Fix: break was too early
---
lib/parser.rb | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
(limited to 'lib')
diff --git a/lib/parser.rb b/lib/parser.rb
index 4984292..5f847c3 100644
--- a/lib/parser.rb
+++ b/lib/parser.rb
@@ -283,7 +283,7 @@ module OpenTox
2.upto(book.last_row) { |i|
row = book.row(i)
regression_features = detect_regression_features row
- break if regression_features=true
+ break if regression_features==true
}
2.upto(book.last_row) { |i| add_values book.row(i),regression_features }
@@ -305,7 +305,7 @@ module OpenTox
input.each { |row|
row = split_row(row)
regression_features = detect_regression_features row
- break if regression_features=true
+ break if regression_features==true
}
input.each { |row| add_values split_row(row),regression_features }
warnings
@@ -355,6 +355,7 @@ module OpenTox
end
def detect_regression_features row
+ row.shift
regression_features=false
row.each_index do |i|
value = row[i]
--
cgit v1.2.3
From d0006c50909a7f134df4e246f747831e3a5547ed Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Tue, 24 May 2011 15:11:12 +0200
Subject: Fixing regression detection
---
lib/parser.rb | 66 +++++++++++++++++++++++++++++++++++++++++++++--------------
1 file changed, 51 insertions(+), 15 deletions(-)
(limited to 'lib')
diff --git a/lib/parser.rb b/lib/parser.rb
index 7bdee95..5f847c3 100644
--- a/lib/parser.rb
+++ b/lib/parser.rb
@@ -277,7 +277,16 @@ module OpenTox
def load_spreadsheet(book)
book.default_sheet = 0
add_features book.row(1)
- 2.upto(book.last_row) { |i| add_values book.row(i) }
+
+ # AM: fix mixed read in
+ regression_features=false
+ 2.upto(book.last_row) { |i|
+ row = book.row(i)
+ regression_features = detect_regression_features row
+ break if regression_features==true
+ }
+
+ 2.upto(book.last_row) { |i| add_values book.row(i),regression_features }
warnings
@dataset
end
@@ -289,11 +298,21 @@ module OpenTox
row = 0
input = csv.split("\n")
add_features split_row(input.shift)
- input.each { |row| add_values split_row(row) }
+
+
+ # AM: fix mixed read in
+ regression_features=false
+ input.each { |row|
+ row = split_row(row)
+ regression_features = detect_regression_features row
+ break if regression_features==true
+ }
+ input.each { |row| add_values split_row(row),regression_features }
warnings
@dataset
end
+
private
def warnings
@@ -335,7 +354,20 @@ module OpenTox
end
end
- def add_values(row)
+ def detect_regression_features row
+ row.shift
+ regression_features=false
+ row.each_index do |i|
+ value = row[i]
+ type = feature_type(value)
+ if type == OT.NumericFeature
+ regression_features=true
+ end
+ end
+ regression_features
+ end
+
+ def add_values(row, regression_features=false)
smiles = row.shift
compound = Compound.from_smiles(smiles)
@@ -353,19 +385,23 @@ module OpenTox
@feature_types[feature] << type
- case type
- when OT.NominalFeature
- case value.to_s
- when TRUE_REGEXP
- val = true
- when FALSE_REGEXP
- val = false
- end
- when OT.NumericFeature
+ if (regression_features)
val = value.to_f
- when OT.StringFeature
- val = value.to_s
- @activity_errors << smiles+", "+row.join(", ")
+ else
+ case type
+ when OT.NominalFeature
+ case value.to_s
+ when TRUE_REGEXP
+ val = true
+ when FALSE_REGEXP
+ val = false
+ end
+ when OT.NumericFeature
+ val = value.to_f
+ when OT.StringFeature
+ val = value.to_s
+ @activity_errors << smiles+", "+row.join(", ")
+ end
end
if val!=nil
@dataset.add(compound.uri, feature, val)
--
cgit v1.2.3
From 0d87789eec37f7ae09d01937dbfc72af1ef17252 Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Tue, 24 May 2011 16:06:05 +0200
Subject: fix small errors in to-html method
---
lib/to-html.rb | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
(limited to 'lib')
diff --git a/lib/to-html.rb b/lib/to-html.rb
index 66a3e74..51602d7 100644
--- a/lib/to-html.rb
+++ b/lib/to-html.rb
@@ -6,7 +6,7 @@ class String
# encloses URI in text with with link tag
# @return [String] new text with marked links
def link_urls
- self.gsub(/(?i)http(s?):\/\/[^\r\n\s']*/, '\0')
+ self.gsub(/(?i)http(s?):\/\/[^\r\n\s']*/, '\0')
end
end
@@ -30,7 +30,7 @@ module OpenTox
title = nil #$sinatra.url_for($sinatra.request.env['PATH_INFO'], :full) if $sinatra
html = ""
html += ""+title+"" if title
- html += ""
+ html += "<\/img>"
if AA_SERVER
user = OpenTox::Authorization.get_user(subjectid) if subjectid
@@ -63,7 +63,7 @@ module OpenTox
html += "
Content
" if description || related_links
html += "
"
html += text.link_urls
- html += "
"
+ html += ""
html
end
@@ -78,7 +78,7 @@ module OpenTox
"
password:
"+
#""+
"
"
- html += ""
+ html += ""
html
end
end
--
cgit v1.2.3
From 524bda5ac60e07aa0805bfb215da718157849672 Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Tue, 24 May 2011 16:08:22 +0200
Subject: fix lazar-non-predictions: replace "No similar compounds in training
dataset." with nil
---
lib/model.rb | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
(limited to 'lib')
diff --git a/lib/model.rb b/lib/model.rb
index d46152d..139aed8 100644
--- a/lib/model.rb
+++ b/lib/model.rb
@@ -241,8 +241,8 @@ module OpenTox
confidence_feature_uri = File.join( @prediction_dataset.uri, "feature", "prediction", File.basename(@metadata[OT.dependentVariables]),"confidence")
prediction_feature_uris = {value_feature_uri => prediction[:prediction], confidence_feature_uri => prediction[:confidence]}
- prediction_feature_uris[value_feature_uri] = "No similar compounds in training dataset." if @neighbors.size == 0 or prediction[:prediction].nil?
-
+ #prediction_feature_uris[value_feature_uri] = "No similar compounds in training dataset." if @neighbors.size == 0 or prediction[:prediction].nil?
+ prediction_feature_uris[value_feature_uri] = nil if @neighbors.size == 0 or prediction[:prediction].nil?
#@prediction_dataset.metadata[OT.dependentVariables] = prediction_feature_uri
@prediction_dataset.metadata[OT.dependentVariables] = @metadata[OT.dependentVariables]
--
cgit v1.2.3
From fe85fafc4b24cc8275ad67536d25d660249bb792 Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Tue, 24 May 2011 16:10:10 +0200
Subject: adjust dataset-parser: predictedVariables may be array, do not
request id/features from ambit services as not supported
---
lib/parser.rb | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
(limited to 'lib')
diff --git a/lib/parser.rb b/lib/parser.rb
index 5f847c3..a6878a2 100644
--- a/lib/parser.rb
+++ b/lib/parser.rb
@@ -56,7 +56,7 @@ module OpenTox
`rapper -i rdfxml -o ntriples #{file.path} 2>/dev/null`.each_line do |line|
triple = line.to_triple
if triple[0] == @uri
- if triple[1] == RDF.type # allow multiple types
+ if triple[1] == RDF.type || triple[1]==OT.predictedVariables # allow multiple types
@metadata[triple[1]] = [] unless @metadata[triple[1]]
@metadata[triple[1]] << triple[2].split('^^').first
else
@@ -228,7 +228,11 @@ module OpenTox
file = Tempfile.new("ot-rdfxml")
# do not concat /features to uri string, this would not work for dataset/R401577?max=3
uri = URI::parse(@uri)
- uri.path = File.join(uri.path,"features")
+ # PENDING
+ # ambit models return http://host/dataset/id?feature_uris[]=sth but
+ # amibt dataset services does not support http://host/dataset/id/features?feature_uris[]=sth
+ # -> load features from complete dataset
+ uri.path = File.join(uri.path,"features") unless @uri=~/\?feature_uris\[\]/
uri = uri.to_s
file.puts OpenTox::RestClientWrapper.get uri,{:subjectid => subjectid,:accept => "application/rdf+xml"},nil,false
file.close
--
cgit v1.2.3
From aaff8d61a7b3bb96e79fbf575718764a071ced9a Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Tue, 24 May 2011 18:04:59 +0200
Subject: added missing prop to serializer
---
lib/serializer.rb | 1 +
1 file changed, 1 insertion(+)
(limited to 'lib')
diff --git a/lib/serializer.rb b/lib/serializer.rb
index 78e7709..62c1159 100644
--- a/lib/serializer.rb
+++ b/lib/serializer.rb
@@ -109,6 +109,7 @@ module OpenTox
OT.precision => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
OT.areaUnderRoc => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
OT.weightedAreaUnderRoc => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
+ OT.weightedAccuracy => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
OT.fMeasure => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
OT.percentIncorrect => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
OT.validationType => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
--
cgit v1.2.3
From 43572f94815a5ec4ca5b922dad3a1c1a140b7348 Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Tue, 24 May 2011 19:44:53 +0200
Subject: remove empty space that produced a warning
---
lib/algorithm.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/algorithm.rb b/lib/algorithm.rb
index 5b41cbf..96b9df1 100644
--- a/lib/algorithm.rb
+++ b/lib/algorithm.rb
@@ -202,7 +202,7 @@ module OpenTox
acts_f = acts.collect {|v| v == true ? 1.0 : 0.0}
sims = neighbors.collect{ |n| Algorithm.gauss(n[:similarity]) } # similarity values btwn q and nbors
begin
- prediction = local_svm (neighbors, acts_f, sims, "C-bsvc", params)
+ prediction = local_svm(neighbors, acts_f, sims, "C-bsvc", params)
LOGGER.debug "Prediction is: '" + prediction.to_s + "'."
rescue Exception => e
LOGGER.debug "#{e.class}: #{e.message} #{e.backtrace}"
--
cgit v1.2.3
From b7a03a18ce90d664d89d6a414512aa03a6dddcc4 Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Wed, 25 May 2011 08:51:56 +0200
Subject: Add_neighbor function
---
lib/model.rb | 59 ++++++++++++++++++++++-------------------------------------
1 file changed, 22 insertions(+), 37 deletions(-)
(limited to 'lib')
diff --git a/lib/model.rb b/lib/model.rb
index 139aed8..f5e0410 100644
--- a/lib/model.rb
+++ b/lib/model.rb
@@ -338,54 +338,39 @@ module OpenTox
@prediction_dataset
end
- # Find neighbors and store them as object variable
+ # Find neighbors and store them as object variable, access only a subset of compounds for that.
def neighbors_balanced(s, l, start, offset)
@compound_features = eval("#{@feature_calculation_algorithm}(@compound,@features)") if @feature_calculation_algorithm
-
@neighbors = []
- begin
- #@fingerprints.each do |training_compound,training_features| # AM: this is original by CH
[ l[start, offset ] , s ].flatten.each do |training_compound| # AM: access only a balanced subset
training_features = @fingerprints[training_compound]
- sim = eval("#{@similarity_algorithm}(@compound_features,training_features,@p_values)")
- if sim > @min_sim
- @activities[training_compound].each do |act|
- this_neighbor = {
- :compound => training_compound,
- :similarity => sim,
- :features => training_features,
- :activity => act
- }
- @neighbors << this_neighbor
- end
- end
- end
- rescue Exception => e
- LOGGER.error "BLAZAR failed in neighbors: "+e.class.to_s+": "+e.message
+ add_neighbor training_features
end
end
-
- # Find neighbors and store them as object variable
+ # Find neighbors and store them as object variable.
def neighbors
-
- @compound_features = eval("#{@feature_calculation_algorithm}(@compound,@features)") if @feature_calculation_algorithm
-
- @neighbors = []
- @fingerprints.each do |training_compound,training_features|
- sim = eval("#{@similarity_algorithm}(@compound_features,training_features,@p_values)")
- if sim > @min_sim
- @activities[training_compound].each do |act|
- @neighbors << {
- :compound => training_compound,
- :similarity => sim,
- :features => training_features,
- :activity => act
- }
- end
+ @compound_features = eval("#{@feature_calculation_algorithm}(@compound,@features)") if @feature_calculation_algorithm
+ @neighbors = []
+ @fingerprints.each do |training_compound,training_features| # AM: access all compounds
+ add_neighbor training_features
+ end
+ end
+
+ # Adds a neighbor to @neighbors if it passes the similarity threshold.
+ def add_neighbor(training_features)
+ sim = eval("#{@similarity_algorithm}(@compound_features,training_features,@p_values)")
+ if sim > @min_sim
+ @activities[training_compound].each do |act|
+ @neighbors << {
+ :compound => training_compound,
+ :similarity => sim,
+ :features => training_features,
+ :activity => act
+ }
end
- end
+ end
end
# Find database activities and store them in @prediction_dataset
--
cgit v1.2.3
From baca9424a84b6a21363cac891cdef72f44c116b1 Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Wed, 25 May 2011 10:08:04 +0200
Subject: remove duplicate debug msg
---
lib/rest_client_wrapper.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/rest_client_wrapper.rb b/lib/rest_client_wrapper.rb
index 747a353..53887a2 100644
--- a/lib/rest_client_wrapper.rb
+++ b/lib/rest_client_wrapper.rb
@@ -131,7 +131,7 @@ module OpenTox
raise "unknown content-type for task : '"+res.content_type.to_s+"'"+" base-uri: "+base_uri.to_s+" content: "+res[0..200].to_s
end
- LOGGER.debug "result is a task '"+task.uri.to_s+"', wait for completion"
+ #LOGGER.debug "result is a task '"+task.uri.to_s+"', wait for completion"
task.wait_for_completion waiting_task
unless task.completed? # maybe task was cancelled / error
if task.errorReport
--
cgit v1.2.3
From baffedfc7543cfc8a90fc185fc91f2748ce94528 Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Wed, 25 May 2011 10:24:13 +0200
Subject: Fixed add_neighbor
---
lib/model.rb | 25 +++++++++++++++++++++----
1 file changed, 21 insertions(+), 4 deletions(-)
(limited to 'lib')
diff --git a/lib/model.rb b/lib/model.rb
index f5e0410..3d27706 100644
--- a/lib/model.rb
+++ b/lib/model.rb
@@ -338,28 +338,45 @@ module OpenTox
@prediction_dataset
end
+ # Calculate the propositionalization matrix aka instantiation matrix (0/1 entries for features)
+# def get_prop_matrix
+# matrix = Array.new
+# begin
+# @neighbors.each do |n|
+# row = []
+# @features.each do |f|
+# row << @fingerprints[n].include?(f) ? 0.0 : @p_values[f]
+# end
+# matrix << row
+# end
+# rescue Exception => e
+# LOGGER.debug "get_prop_matrix failed with '" + $! + "'"
+# end
+# matrix
+# end
+
# Find neighbors and store them as object variable, access only a subset of compounds for that.
def neighbors_balanced(s, l, start, offset)
@compound_features = eval("#{@feature_calculation_algorithm}(@compound,@features)") if @feature_calculation_algorithm
@neighbors = []
[ l[start, offset ] , s ].flatten.each do |training_compound| # AM: access only a balanced subset
training_features = @fingerprints[training_compound]
- add_neighbor training_features
+ add_neighbor training_features, training_compound
end
end
- # Find neighbors and store them as object variable.
+ # Find neighbors and store them as object variable, access all compounds for that.
def neighbors
@compound_features = eval("#{@feature_calculation_algorithm}(@compound,@features)") if @feature_calculation_algorithm
@neighbors = []
@fingerprints.each do |training_compound,training_features| # AM: access all compounds
- add_neighbor training_features
+ add_neighbor training_features, training_compound
end
end
# Adds a neighbor to @neighbors if it passes the similarity threshold.
- def add_neighbor(training_features)
+ def add_neighbor(training_features, training_compound)
sim = eval("#{@similarity_algorithm}(@compound_features,training_features,@p_values)")
if sim > @min_sim
@activities[training_compound].each do |act|
--
cgit v1.2.3
From 52e73a3da8e99da9a0a973b6ef9934297bc6511e Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Wed, 25 May 2011 11:55:41 +0200
Subject: remove check for task status when code is 201 (after discussion with
nina and fabian)
---
lib/task.rb | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/task.rb b/lib/task.rb
index 42d3d17..146a756 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -288,7 +288,8 @@ module OpenTox
if @http_code == 202
raise "#{@uri}: illegal task state, code is 202, but hasStatus is not Running: '"+@metadata[OT.hasStatus]+"'" unless running?
elsif @http_code == 201
- raise "#{@uri}: illegal task state, code is 201, but hasStatus is not Completed: '"+@metadata[OT.hasStatus]+"'" unless completed?
+ # ignore hasStatus
+ # raise "#{@uri}: illegal task state, code is 201, but hasStatus is not Completed: '"+@metadata[OT.hasStatus]+"'" unless completed?
raise "#{@uri}: illegal task state, code is 201, resultURI is no task-URI: '"+@metadata[OT.resultURI].to_s+
"'" unless @metadata[OT.resultURI] and @metadata[OT.resultURI].to_s.uri?
end
--
cgit v1.2.3
From b6ba84a077db9f6c708807f059e501333f7303b1 Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Wed, 25 May 2011 12:18:08 +0200
Subject: 1st v
---
lib/model.rb | 39 +++++++++++++++++++++++----------------
1 file changed, 23 insertions(+), 16 deletions(-)
(limited to 'lib')
diff --git a/lib/model.rb b/lib/model.rb
index 3d27706..bebf5d3 100644
--- a/lib/model.rb
+++ b/lib/model.rb
@@ -215,6 +215,7 @@ module OpenTox
(i == modulo[0]) && (slack>0) ? lr_size = s.size + slack : lr_size = s.size + addon # determine fraction
LOGGER.info "BLAZAR: Neighbors round #{i}: #{position} + #{lr_size}."
neighbors_balanced(s, l, position, lr_size) # get ratio fraction of larger part
+ prop_matrix = get_prop_matrix
prediction = eval("#{@prediction_algorithm}(@neighbors,{:similarity_algorithm => @similarity_algorithm, :p_values => @p_values})")
if prediction_best.nil? || prediction[:confidence].abs > prediction_best[:confidence].abs
prediction_best=prediction
@@ -228,10 +229,11 @@ module OpenTox
prediction=prediction_best
@neighbors=neighbors_best
- ### END AM balanced predictions
+ ### END AM balanced predictions
else # regression case: no balancing
neighbors
+ prop_matrix = get_prop_matrix
prediction = eval("#{@prediction_algorithm}(@neighbors,{:similarity_algorithm => @similarity_algorithm, :p_values => @p_values})")
end
@@ -339,21 +341,26 @@ module OpenTox
end
# Calculate the propositionalization matrix aka instantiation matrix (0/1 entries for features)
-# def get_prop_matrix
-# matrix = Array.new
-# begin
-# @neighbors.each do |n|
-# row = []
-# @features.each do |f|
-# row << @fingerprints[n].include?(f) ? 0.0 : @p_values[f]
-# end
-# matrix << row
-# end
-# rescue Exception => e
-# LOGGER.debug "get_prop_matrix failed with '" + $! + "'"
-# end
-# matrix
-# end
+ def get_prop_matrix
+ matrix = Array.new
+ begin
+ @neighbors.each do |n|
+ n = n[:compound]
+ row = []
+ @features.each do |f|
+ if ! @fingerprints[n].nil?
+ row << (@fingerprints[n].include?(f) ? 0.0 : @p_values[f])
+ else
+ row << 0.0
+ end
+ end
+ matrix << row
+ end
+ rescue Exception => e
+ LOGGER.debug "get_prop_matrix failed with '" + $! + "'"
+ end
+ matrix
+ end
# Find neighbors and store them as object variable, access only a subset of compounds for that.
def neighbors_balanced(s, l, start, offset)
--
cgit v1.2.3
From d012b9e8da641c342c455a1384ddf3b14f5b5c35 Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Wed, 25 May 2011 12:38:04 +0200
Subject: 2nd v
---
lib/model.rb | 87 ++++++++++++++++++++++++++++++++----------------------------
1 file changed, 46 insertions(+), 41 deletions(-)
(limited to 'lib')
diff --git a/lib/model.rb b/lib/model.rb
index bebf5d3..f4df8ea 100644
--- a/lib/model.rb
+++ b/lib/model.rb
@@ -177,7 +177,7 @@ module OpenTox
return @prediction_dataset if database_activity(subjectid)
- if metadata[RDF.type] == [OTA.ClassificationLazySingleTarget]
+ if metadata[RDF.type] == [OTA.ClassificationLazySingleTarget]
# AM: Balancing, see http://www.maunz.de/wordpress/opentox/2011/balanced-lazar
l = Array.new # larger
s = Array.new # smaller fraction
@@ -211,33 +211,33 @@ module OpenTox
neighbors_best=nil
begin
- for i in 1..modulo[0] do
- (i == modulo[0]) && (slack>0) ? lr_size = s.size + slack : lr_size = s.size + addon # determine fraction
- LOGGER.info "BLAZAR: Neighbors round #{i}: #{position} + #{lr_size}."
- neighbors_balanced(s, l, position, lr_size) # get ratio fraction of larger part
- prop_matrix = get_prop_matrix
- prediction = eval("#{@prediction_algorithm}(@neighbors,{:similarity_algorithm => @similarity_algorithm, :p_values => @p_values})")
- if prediction_best.nil? || prediction[:confidence].abs > prediction_best[:confidence].abs
- prediction_best=prediction
- neighbors_best=@neighbors
+ for i in 1..modulo[0] do
+ (i == modulo[0]) && (slack>0) ? lr_size = s.size + slack : lr_size = s.size + addon # determine fraction
+ LOGGER.info "BLAZAR: Neighbors round #{i}: #{position} + #{lr_size}."
+ neighbors_balanced(s, l, position, lr_size) # get ratio fraction of larger part
+ props = get_props
+ prediction = eval("#{@prediction_algorithm}(@neighbors,{:similarity_algorithm => @similarity_algorithm, :p_values => @p_values})")
+ if prediction_best.nil? || prediction[:confidence].abs > prediction_best[:confidence].abs
+ prediction_best=prediction
+ neighbors_best=@neighbors
+ end
+ position = position + lr_size
end
- position = position + lr_size
- end
rescue Exception => e
LOGGER.error "BLAZAR failed in prediction: "+e.class.to_s+": "+e.message
end
prediction=prediction_best
@neighbors=neighbors_best
- ### END AM balanced predictions
+ ### END AM balanced predictions
else # regression case: no balancing
neighbors
- prop_matrix = get_prop_matrix
+ props = get_props
prediction = eval("#{@prediction_algorithm}(@neighbors,{:similarity_algorithm => @similarity_algorithm, :p_values => @p_values})")
end
-
- # TODO: reasonable feature name
+
+ # TODO: reasonable feature name
#prediction_feature_uri = File.join( @prediction_dataset.uri, "feature", "prediction", File.basename(@metadata[OT.dependentVariables]),@prediction_dataset.compounds.size.to_s)
value_feature_uri = File.join( @prediction_dataset.uri, "feature", "prediction", File.basename(@metadata[OT.dependentVariables]),"value")
confidence_feature_uri = File.join( @prediction_dataset.uri, "feature", "prediction", File.basename(@metadata[OT.dependentVariables]),"confidence")
@@ -245,7 +245,7 @@ module OpenTox
prediction_feature_uris = {value_feature_uri => prediction[:prediction], confidence_feature_uri => prediction[:confidence]}
#prediction_feature_uris[value_feature_uri] = "No similar compounds in training dataset." if @neighbors.size == 0 or prediction[:prediction].nil?
prediction_feature_uris[value_feature_uri] = nil if @neighbors.size == 0 or prediction[:prediction].nil?
-
+
#@prediction_dataset.metadata[OT.dependentVariables] = prediction_feature_uri
@prediction_dataset.metadata[OT.dependentVariables] = @metadata[OT.dependentVariables]
@@ -275,10 +275,10 @@ module OpenTox
DC.title => URI.decode(File.basename( @metadata[OT.dependentVariables] )),
# TODO: factor information to value
})
- #OT.prediction => prediction[:prediction],
- #OT.confidence => prediction[:confidence],
- #OT.parameters => [{DC.title => "compound_uri", OT.paramValue => compound_uri}]
- @prediction_dataset.add @compound.uri, prediction_feature_uri, value
+ #OT.prediction => prediction[:prediction],
+ #OT.confidence => prediction[:confidence],
+ #OT.parameters => [{DC.title => "compound_uri", OT.paramValue => compound_uri}]
+ @prediction_dataset.add @compound.uri, prediction_feature_uri, value
end
if verbose
@@ -341,34 +341,39 @@ module OpenTox
end
# Calculate the propositionalization matrix aka instantiation matrix (0/1 entries for features)
- def get_prop_matrix
+ # Same for the vector describing the query compound
+ def get_props
matrix = Array.new
begin
- @neighbors.each do |n|
- n = n[:compound]
+ @neighbors.each do |n|
+ n = n[:compound]
+ row = []
+ @features.each do |f|
+ if ! @fingerprints[n].nil?
+ row << (@fingerprints[n].include?(f) ? 0.0 : @p_values[f])
+ else
+ row << 0.0
+ end
+ end
+ matrix << row
+ end
row = []
@features.each do |f|
- if ! @fingerprints[n].nil?
- row << (@fingerprints[n].include?(f) ? 0.0 : @p_values[f])
- else
- row << 0.0
- end
+ row << (@compound.match([f]).size == 0 ? 0.0 : @p_values[f])
end
- matrix << row
- end
rescue Exception => e
- LOGGER.debug "get_prop_matrix failed with '" + $! + "'"
+ LOGGER.debug "get_props failed with '" + $! + "'"
end
- matrix
+ [ matrix, row ]
end
# Find neighbors and store them as object variable, access only a subset of compounds for that.
def neighbors_balanced(s, l, start, offset)
@compound_features = eval("#{@feature_calculation_algorithm}(@compound,@features)") if @feature_calculation_algorithm
@neighbors = []
- [ l[start, offset ] , s ].flatten.each do |training_compound| # AM: access only a balanced subset
- training_features = @fingerprints[training_compound]
- add_neighbor training_features, training_compound
+ [ l[start, offset ] , s ].flatten.each do |training_compound| # AM: access only a balanced subset
+ training_features = @fingerprints[training_compound]
+ add_neighbor training_features, training_compound
end
end
@@ -378,7 +383,7 @@ module OpenTox
@compound_features = eval("#{@feature_calculation_algorithm}(@compound,@features)") if @feature_calculation_algorithm
@neighbors = []
@fingerprints.each do |training_compound,training_features| # AM: access all compounds
- add_neighbor training_features, training_compound
+ add_neighbor training_features, training_compound
end
end
@@ -388,10 +393,10 @@ module OpenTox
if sim > @min_sim
@activities[training_compound].each do |act|
@neighbors << {
- :compound => training_compound,
- :similarity => sim,
- :features => training_features,
- :activity => act
+ :compound => training_compound,
+ :similarity => sim,
+ :features => training_features,
+ :activity => act
}
end
end
--
cgit v1.2.3
From 153c740268c1bf6255f14f80550f690179a72fd9 Mon Sep 17 00:00:00 2001
From: mr
Date: Wed, 25 May 2011 13:35:42 +0200
Subject: fix if subjectid is nil
---
lib/helper.rb | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/helper.rb b/lib/helper.rb
index 3a6126a..995f3e9 100644
--- a/lib/helper.rb
+++ b/lib/helper.rb
@@ -44,8 +44,9 @@ helpers do
def uri_available?(urlStr)
url = URI.parse(urlStr)
+ subjectidstr = @subjectid ? "?subjectid=#{CGI.escape @subjectid}" : ""
Net::HTTP.start(url.host, url.port) do |http|
- return http.head("#{url.request_uri}?subjectid=#{CGI.escape @subjectid}").code == "200"
+ return http.head("#{url.request_uri}#{subjectidstr}").code == "200"
end
end
--
cgit v1.2.3
From a76a0c8d8ee259f1818a5fa2b5c4986fa460d888 Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Wed, 25 May 2011 13:59:53 +0200
Subject: re-enabled cookie-authentication for html-access to webservices,
replaced login/logout with sign in/out to avoid name clash with toxcreate
---
lib/to-html.rb | 32 +++++++++++++++-----------------
1 file changed, 15 insertions(+), 17 deletions(-)
(limited to 'lib')
diff --git a/lib/to-html.rb b/lib/to-html.rb
index 51602d7..2c29f7d 100644
--- a/lib/to-html.rb
+++ b/lib/to-html.rb
@@ -36,11 +36,11 @@ module OpenTox
user = OpenTox::Authorization.get_user(subjectid) if subjectid
html += "
"
unless user
- html += "You are currently not logged in to "+$url_provider.url_for("",:full)+
- ", login"
+ html += "You are currently not signed in to "+$url_provider.url_for("",:full)+
+ ", sign in"
else
- html += "You are logged in as '#{user}' to "+$url_provider.url_for("",:full)+
- ", logout"
+ html += "You are signed in as '#{user}' to "+$url_provider.url_for("",:full)+
+ ", sign out"
end
html += "
"
end
@@ -67,46 +67,44 @@ module OpenTox
html
end
- def self.login( msg=nil )
+ def self.sign_in( msg=nil )
html = "Login"
- html += ""
html
end
end
-=begin
-get '/logout/?' do
+get '/sign_out/?' do
response.set_cookie("subjectid",{:value=>nil})
content_type "text/html"
- content = "Sucessfully logged out from "+$url_provider.url_for("",:full)
+ content = "Sucessfully signed out from "+$url_provider.url_for("",:full)
OpenTox.text_to_html(content)
end
-get '/login/?' do
+get '/sign_in/?' do
content_type "text/html"
- OpenTox.login
+ OpenTox.sign_in
end
-post '/login/?' do
+post '/sign_in/?' do
subjectid = OpenTox::Authorization.authenticate(params[:user], params[:password])
if (subjectid)
response.set_cookie("subjectid",{:value=>subjectid})
content_type "text/html"
- content = "Sucessfully logged in as '"+params[:user]+"' to "+$url_provider.url_for("",:full)
+ content = "Sucessfully signed in as '"+params[:user]+"' to "+$url_provider.url_for("",:full)
OpenTox.text_to_html(content,subjectid)
else
content_type "text/html"
- OpenTox.login("Login failed, please try again")
+ OpenTox.sign_in("Login failed, please try again")
end
end
-=end
--
cgit v1.2.3
From 3f209f75a2abe2b8a89df3afcb3f54ec8329a5e1 Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Wed, 25 May 2011 14:16:34 +0200
Subject: 3rd v
---
lib/algorithm.rb | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 80 insertions(+), 5 deletions(-)
(limited to 'lib')
diff --git a/lib/algorithm.rb b/lib/algorithm.rb
index 96b9df1..280ed82 100644
--- a/lib/algorithm.rb
+++ b/lib/algorithm.rb
@@ -178,7 +178,7 @@ module OpenTox
sims = neighbors.collect{ |n| Algorithm.gauss(n[:similarity]) } # similarity values btwn q and nbors
begin
- prediction = local_svm(neighbors, acts, sims, "nu-svr", params)
+ prediction = (props.nil? ? local_svm(neighbors, acts, sims, "nu-svr", params) : local_svm_prop(neighbors, acts, sims, "nu-svr", params, props))
prediction = (take_logs ? 10**(prediction.to_f) : prediction.to_f)
LOGGER.debug "Prediction is: '" + prediction.to_s + "'."
rescue Exception => e
@@ -194,15 +194,16 @@ module OpenTox
# Local support vector classification from neighbors
# @param [Array] neighbors, each neighbor is a hash with keys `:similarity, :activity, :features`
# @param [Hash] params Keys `:similarity_algorithm,:p_values` are required
+ # @param [Array] props, propositionalization of neighbors and query structure e.g. [ Array_for_q, two-nested-Arrays_for_n ]
# @return [Hash] Hash with keys `:prediction, :confidence`
- def self.local_svm_classification(neighbors, params)
+ def self.local_svm_classification(neighbors, params, props=nil)
acts = neighbors.collect do |n|
act = n[:activity]
end # activities of neighbors for supervised learning
acts_f = acts.collect {|v| v == true ? 1.0 : 0.0}
sims = neighbors.collect{ |n| Algorithm.gauss(n[:similarity]) } # similarity values btwn q and nbors
begin
- prediction = local_svm(neighbors, acts_f, sims, "C-bsvc", params)
+ prediction = (props.nil? ? local_svm(neighbors, acts_f, sims, "C-bsvc", params) : local_svm_prop(neighbors, acts_f, sims, "C-bsvc", params, props))
LOGGER.debug "Prediction is: '" + prediction.to_s + "'."
rescue Exception => e
LOGGER.debug "#{e.class}: #{e.message} #{e.backtrace}"
@@ -216,14 +217,16 @@ module OpenTox
# Local support vector prediction from neighbors.
- # Not to be called directly (use local_svm_regression or local_svm_classification.
+ # Uses pre-defined Kernel Matrix.
+ # Not to be called directly (use local_svm_regression or local_svm_classification).
# @param [Array] neighbors, each neighbor is a hash with keys `:similarity, :activity, :features`
# @param [Array] acts, activities for neighbors.
# @param [Array] sims, similarities for neighbors.
# @param [String] type, one of "nu-svr" (regression) or "C-bsvc" (classification).
# @param [Hash] params Keys `:similarity_algorithm,:p_values` are required
+ # @param [Array] props, propositionalization of neighbors and query structure e.g. [ Array_for_q, two-nested-Arrays_for_n ]
# @return [Numeric] A prediction value.
- def self.local_svm(neighbors, acts, sims, type, params)
+ def self.local_svm(neighbors, acts, sims, type, params, props=nil)
neighbor_matches = neighbors.collect{ |n| n[:features] } # URIs of matches
gram_matrix = [] # square matrix of similarities between neighbors; implements weighted tanimoto kernel
if neighbor_matches.size == 0
@@ -285,6 +288,78 @@ module OpenTox
prediction
end
+ # Local support vector prediction from neighbors.
+ # Uses propositionalized setting.
+ # Not to be called directly (use local_svm_regression or local_svm_classification).
+ # @param [Array] neighbors, each neighbor is a hash with keys `:similarity, :activity, :features`
+ # @param [Array] acts, activities for neighbors.
+ # @param [Array] props, propositionalization of neighbors and query structure e.g. [ Array_for_q, two-nested-Arrays_for_n ]
+ # @param [String] type, one of "nu-svr" (regression) or "C-bsvc" (classification).
+ # @param [Hash] params Keys `:similarity_algorithm,:p_values` are required
+ # @return [Numeric] A prediction value.
+ def self.local_svm_prop(props, acts, type, params)
+
+ n_prop = props[0] # is a matrix, i.e. two nested Arrays.
+ q_prop = props[1] # is an Array.
+
+ #neighbor_matches = neighbors.collect{ |n| n[:features] } # URIs of matches
+ #gram_matrix = [] # square matrix of similarities between neighbors; implements weighted tanimoto kernel
+ if n_prop.size == 0
+ raise "No neighbors found."
+ else
+ # gram matrix
+ #(0..(neighbor_matches.length-1)).each do |i|
+ # gram_matrix[i] = [] unless gram_matrix[i]
+ # # upper triangle
+ # ((i+1)..(neighbor_matches.length-1)).each do |j|
+ # sim = eval("#{params[:similarity_algorithm]}(neighbor_matches[i], neighbor_matches[j], params[:p_values])")
+ # gram_matrix[i][j] = Algorithm.gauss(sim)
+ # gram_matrix[j] = [] unless gram_matrix[j]
+ # gram_matrix[j][i] = gram_matrix[i][j] # lower triangle
+ # end
+ # gram_matrix[i][i] = 1.0
+ #end
+
+ #LOGGER.debug gram_matrix.to_yaml
+ @r = RinRuby.new(false,false) # global R instance leads to Socket errors after a large number of requests
+ @r.eval "library('kernlab')" # this requires R package "kernlab" to be installed
+ LOGGER.debug "Setting R data ..."
+ # set data
+ @r.n_prop = n_prop.flatten
+ @r.n = n_prop.size
+ @r.y = acts
+ @r.q_prop = q_prop
+
+ begin
+ LOGGER.debug "Preparing R data ..."
+ # prepare data
+ @r.eval "y<-as.vector(y)"
+ @r.eval "prop_matrix<-matrix(n_prop,n,n)"
+ @r.eval "q_prop<-as.vector(q_prop)"
+
+ # model + support vectors
+ LOGGER.debug "Creating SVM model ..."
+ @r.eval "model<-ksvm(prop_matrix, y, type=\"#{type}\", nu=0.5)"
+ LOGGER.debug "Predicting ..."
+ if type == "nu-svr"
+ @r.eval "p<-predict(model,q_prop)[1,1]"
+ elsif type == "C-bsvc"
+ @r.eval "p<-predict(model,q_prop)"
+ end
+ if type == "nu-svr"
+ prediction = @r.p
+ elsif type == "C-bsvc"
+ prediction = (@r.p.to_f == 1.0 ? true : false)
+ end
+ @r.quit # free R
+ rescue Exception => e
+ LOGGER.debug "#{e.class}: #{e.message} #{e.backtrace}"
+ end
+ end
+ prediction
+ end
+
+
end
module Substructure
--
cgit v1.2.3
From ca6dd87b7c80611c4f4e4716f68fe6633ce1066b Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Wed, 25 May 2011 15:04:50 +0200
Subject: 4th v
---
lib/algorithm.rb | 4 ++--
lib/model.rb | 5 ++---
2 files changed, 4 insertions(+), 5 deletions(-)
(limited to 'lib')
diff --git a/lib/algorithm.rb b/lib/algorithm.rb
index 280ed82..2f722c1 100644
--- a/lib/algorithm.rb
+++ b/lib/algorithm.rb
@@ -178,7 +178,7 @@ module OpenTox
sims = neighbors.collect{ |n| Algorithm.gauss(n[:similarity]) } # similarity values btwn q and nbors
begin
- prediction = (props.nil? ? local_svm(neighbors, acts, sims, "nu-svr", params) : local_svm_prop(neighbors, acts, sims, "nu-svr", params, props))
+ prediction = (props.nil? ? local_svm(neighbors, acts, sims, "nu-svr", params) : local_svm_prop(props, acts, sims, "nu-svr", params))
prediction = (take_logs ? 10**(prediction.to_f) : prediction.to_f)
LOGGER.debug "Prediction is: '" + prediction.to_s + "'."
rescue Exception => e
@@ -203,7 +203,7 @@ module OpenTox
acts_f = acts.collect {|v| v == true ? 1.0 : 0.0}
sims = neighbors.collect{ |n| Algorithm.gauss(n[:similarity]) } # similarity values btwn q and nbors
begin
- prediction = (props.nil? ? local_svm(neighbors, acts_f, sims, "C-bsvc", params) : local_svm_prop(neighbors, acts_f, sims, "C-bsvc", params, props))
+ prediction = (props.nil? ? local_svm(neighbors, acts_f, sims, "C-bsvc", params) : local_svm_prop(props, acts_f, sims, "C-bsvc", params))
LOGGER.debug "Prediction is: '" + prediction.to_s + "'."
rescue Exception => e
LOGGER.debug "#{e.class}: #{e.message} #{e.backtrace}"
diff --git a/lib/model.rb b/lib/model.rb
index f4df8ea..6a4602f 100644
--- a/lib/model.rb
+++ b/lib/model.rb
@@ -176,8 +176,7 @@ module OpenTox
return @prediction_dataset if database_activity(subjectid)
-
- if metadata[RDF.type] == [OTA.ClassificationLazySingleTarget]
+ if metadata[RDF.type].include?([OTA.ClassificationLazySingleTarget][0]) # AM: searching in metadata for classification
# AM: Balancing, see http://www.maunz.de/wordpress/opentox/2011/balanced-lazar
l = Array.new # larger
s = Array.new # smaller fraction
@@ -231,7 +230,7 @@ module OpenTox
@neighbors=neighbors_best
### END AM balanced predictions
- else # regression case: no balancing
+ else # no balancing as before
neighbors
props = get_props
prediction = eval("#{@prediction_algorithm}(@neighbors,{:similarity_algorithm => @similarity_algorithm, :p_values => @p_values})")
--
cgit v1.2.3
From 2b12d07bec101df8c10b7ab5aff1491b0997a6c7 Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Wed, 25 May 2011 17:10:14 +0200
Subject: 6th v
---
lib/algorithm.rb | 17 +++++++++--------
lib/model.rb | 4 ++--
2 files changed, 11 insertions(+), 10 deletions(-)
(limited to 'lib')
diff --git a/lib/algorithm.rb b/lib/algorithm.rb
index 2f722c1..e089184 100644
--- a/lib/algorithm.rb
+++ b/lib/algorithm.rb
@@ -138,7 +138,7 @@ module OpenTox
# @param [Array] neighbors, each neighbor is a hash with keys `:similarity, :activity`
# @param [optional] params Ignored (only for compatibility with local_svm_regression)
# @return [Hash] Hash with keys `:prediction, :confidence`
- def self.weighted_majority_vote(neighbors,params={})
+ def self.weighted_majority_vote(neighbors,params={}, props=nil)
conf = 0.0
confidence = 0.0
neighbors.each do |neighbor|
@@ -178,7 +178,7 @@ module OpenTox
sims = neighbors.collect{ |n| Algorithm.gauss(n[:similarity]) } # similarity values btwn q and nbors
begin
- prediction = (props.nil? ? local_svm(neighbors, acts, sims, "nu-svr", params) : local_svm_prop(props, acts, sims, "nu-svr", params))
+ prediction = (props.nil? ? local_svm(neighbors, acts, sims, "nu-svr", params) : local_svm_prop(props, acts, "nu-svr", params))
prediction = (take_logs ? 10**(prediction.to_f) : prediction.to_f)
LOGGER.debug "Prediction is: '" + prediction.to_s + "'."
rescue Exception => e
@@ -203,7 +203,7 @@ module OpenTox
acts_f = acts.collect {|v| v == true ? 1.0 : 0.0}
sims = neighbors.collect{ |n| Algorithm.gauss(n[:similarity]) } # similarity values btwn q and nbors
begin
- prediction = (props.nil? ? local_svm(neighbors, acts_f, sims, "C-bsvc", params) : local_svm_prop(props, acts_f, sims, "C-bsvc", params))
+ prediction = (props.nil? ? local_svm(neighbors, acts_f, sims, "C-bsvc", params) : local_svm_prop(props, acts_f, "C-bsvc", params))
LOGGER.debug "Prediction is: '" + prediction.to_s + "'."
rescue Exception => e
LOGGER.debug "#{e.class}: #{e.message} #{e.backtrace}"
@@ -226,7 +226,7 @@ module OpenTox
# @param [Hash] params Keys `:similarity_algorithm,:p_values` are required
# @param [Array] props, propositionalization of neighbors and query structure e.g. [ Array_for_q, two-nested-Arrays_for_n ]
# @return [Numeric] A prediction value.
- def self.local_svm(neighbors, acts, sims, type, params, props=nil)
+ def self.local_svm(neighbors, acts, sims, type, params)
neighbor_matches = neighbors.collect{ |n| n[:features] } # URIs of matches
gram_matrix = [] # square matrix of similarities between neighbors; implements weighted tanimoto kernel
if neighbor_matches.size == 0
@@ -326,16 +326,17 @@ module OpenTox
LOGGER.debug "Setting R data ..."
# set data
@r.n_prop = n_prop.flatten
- @r.n = n_prop.size
+ @r.n_prop_x_size = n_prop.size
+ @r.n_prop_y_size = n_prop[0].size
@r.y = acts
@r.q_prop = q_prop
begin
LOGGER.debug "Preparing R data ..."
# prepare data
- @r.eval "y<-as.vector(y)"
- @r.eval "prop_matrix<-matrix(n_prop,n,n)"
- @r.eval "q_prop<-as.vector(q_prop)"
+ @r.eval "y<-matrix(y)"
+ @r.eval "prop_matrix<-matrix(n_prop, n_prop_x_size, n_prop_y_size, byrow=TRUE)"
+ @r.eval "q_prop<-matrix(q_prop, 1, n_prop_y_size, byrow=TRUE)"
# model + support vectors
LOGGER.debug "Creating SVM model ..."
diff --git a/lib/model.rb b/lib/model.rb
index 6a4602f..1a5aa37 100644
--- a/lib/model.rb
+++ b/lib/model.rb
@@ -215,7 +215,7 @@ module OpenTox
LOGGER.info "BLAZAR: Neighbors round #{i}: #{position} + #{lr_size}."
neighbors_balanced(s, l, position, lr_size) # get ratio fraction of larger part
props = get_props
- prediction = eval("#{@prediction_algorithm}(@neighbors,{:similarity_algorithm => @similarity_algorithm, :p_values => @p_values})")
+ prediction = eval("#{@prediction_algorithm}(@neighbors,{:similarity_algorithm => @similarity_algorithm, :p_values => @p_values}, props)")
if prediction_best.nil? || prediction[:confidence].abs > prediction_best[:confidence].abs
prediction_best=prediction
neighbors_best=@neighbors
@@ -233,7 +233,7 @@ module OpenTox
else # no balancing as before
neighbors
props = get_props
- prediction = eval("#{@prediction_algorithm}(@neighbors,{:similarity_algorithm => @similarity_algorithm, :p_values => @p_values})")
+ prediction = eval("#{@prediction_algorithm}(@neighbors,{:similarity_algorithm => @similarity_algorithm, :p_values => @p_values}, props)")
end
# TODO: reasonable feature name
--
cgit v1.2.3
From 77c885b7394aa11ba5e59eb60884205332efa31a Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Thu, 26 May 2011 08:38:21 +0200
Subject: 7th v
---
lib/algorithm.rb | 2 ++
lib/model.rb | 4 ++--
2 files changed, 4 insertions(+), 2 deletions(-)
(limited to 'lib')
diff --git a/lib/algorithm.rb b/lib/algorithm.rb
index e089184..91e075a 100644
--- a/lib/algorithm.rb
+++ b/lib/algorithm.rb
@@ -227,6 +227,7 @@ module OpenTox
# @param [Array] props, propositionalization of neighbors and query structure e.g. [ Array_for_q, two-nested-Arrays_for_n ]
# @return [Numeric] A prediction value.
def self.local_svm(neighbors, acts, sims, type, params)
+ LOGGER.debug "Local SVM (Weighted Tanimoto Kernel)."
neighbor_matches = neighbors.collect{ |n| n[:features] } # URIs of matches
gram_matrix = [] # square matrix of similarities between neighbors; implements weighted tanimoto kernel
if neighbor_matches.size == 0
@@ -299,6 +300,7 @@ module OpenTox
# @return [Numeric] A prediction value.
def self.local_svm_prop(props, acts, type, params)
+ LOGGER.debug "Local SVM (Propositionalization / Kernlab Kernel)."
n_prop = props[0] # is a matrix, i.e. two nested Arrays.
q_prop = props[1] # is an Array.
diff --git a/lib/model.rb b/lib/model.rb
index 1a5aa37..921335c 100644
--- a/lib/model.rb
+++ b/lib/model.rb
@@ -214,7 +214,7 @@ module OpenTox
(i == modulo[0]) && (slack>0) ? lr_size = s.size + slack : lr_size = s.size + addon # determine fraction
LOGGER.info "BLAZAR: Neighbors round #{i}: #{position} + #{lr_size}."
neighbors_balanced(s, l, position, lr_size) # get ratio fraction of larger part
- props = get_props
+ (@prediction_algorithm.include? "svm" and params[:prop_kernel] == "true") ? props = get_props : props = nil
prediction = eval("#{@prediction_algorithm}(@neighbors,{:similarity_algorithm => @similarity_algorithm, :p_values => @p_values}, props)")
if prediction_best.nil? || prediction[:confidence].abs > prediction_best[:confidence].abs
prediction_best=prediction
@@ -232,7 +232,7 @@ module OpenTox
else # no balancing as before
neighbors
- props = get_props
+ (@prediction_algorithm.include? "svm" and params[:prop_kernel] == "true") ? props = get_props : props = nil
prediction = eval("#{@prediction_algorithm}(@neighbors,{:similarity_algorithm => @similarity_algorithm, :p_values => @p_values}, props)")
end
--
cgit v1.2.3
From f13763a8505ad997739b65d7cfcd804411ff9c77 Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Thu, 26 May 2011 10:56:31 +0200
Subject: unify access to classification feature domain, replace methode
feature_values with accept_values
---
lib/dataset.rb | 17 +++++++----------
1 file changed, 7 insertions(+), 10 deletions(-)
(limited to 'lib')
diff --git a/lib/dataset.rb b/lib/dataset.rb
index 4dc4296..fc7c263 100644
--- a/lib/dataset.rb
+++ b/lib/dataset.rb
@@ -167,16 +167,13 @@ module OpenTox
@features
end
- def feature_classes(feature, subjectid=nil)
- if Feature.find(feature, subjectid).feature_type == "classification"
- classes = []
- @data_entries.each do |c,e|
- e[feature].each { |v| classes << v.to_s }
- end
- classes.uniq.sort
- else
- nil
- end
+ # returns the accept_values of a feature, i.e. the classification domain / all possible feature values
+ # @param [String] feature the URI of the feature
+ # @return [Array] return array with strings, nil if value is not set (e.g. when feature is numeric)
+ def accept_values(feature)
+ accept_values = features[feature][OT.acceptValue]
+ accept_values.sort if accept_values
+ accept_values
end
# Detect feature type(s) in the dataset
--
cgit v1.2.3
From 065fdeb351f68d0445b66516ccf8e7cfcc7e2a1f Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Thu, 26 May 2011 12:22:07 +0200
Subject: Fixed prediction type switching
---
lib/model.rb | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/model.rb b/lib/model.rb
index 921335c..d63eef2 100644
--- a/lib/model.rb
+++ b/lib/model.rb
@@ -176,7 +176,10 @@ module OpenTox
return @prediction_dataset if database_activity(subjectid)
- if metadata[RDF.type].include?([OTA.ClassificationLazySingleTarget][0]) # AM: searching in metadata for classification
+ load_metadata(subjectid)
+ case OpenTox::Feature.find(metadata[OT.dependentVariables]).feature_type
+ when "classification"
+
# AM: Balancing, see http://www.maunz.de/wordpress/opentox/2011/balanced-lazar
l = Array.new # larger
s = Array.new # smaller fraction
@@ -231,6 +234,7 @@ module OpenTox
### END AM balanced predictions
else # no balancing as before
+ LOGGER.info "LAZAR: Unbalanced."
neighbors
(@prediction_algorithm.include? "svm" and params[:prop_kernel] == "true") ? props = get_props : props = nil
prediction = eval("#{@prediction_algorithm}(@neighbors,{:similarity_algorithm => @similarity_algorithm, :p_values => @p_values}, props)")
--
cgit v1.2.3
From f507227fd4efff3c8b32b2a8c8f2860af2546e3b Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Thu, 26 May 2011 13:11:32 +0200
Subject: Hotfix: Switch to balanced mode.
---
lib/model.rb | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
(limited to 'lib')
diff --git a/lib/model.rb b/lib/model.rb
index 139aed8..14471cc 100644
--- a/lib/model.rb
+++ b/lib/model.rb
@@ -176,11 +176,15 @@ module OpenTox
return @prediction_dataset if database_activity(subjectid)
-
- if metadata[RDF.type] == [OTA.ClassificationLazySingleTarget]
+ load_metadata(subjectid)
+ case OpenTox::Feature.find(metadata[OT.dependentVariables]).feature_type
+ when "classification"
# AM: Balancing, see http://www.maunz.de/wordpress/opentox/2011/balanced-lazar
l = Array.new # larger
s = Array.new # smaller fraction
+
+ raise "no fingerprints in model" if @fingerprints.size==0
+
@fingerprints.each do |training_compound,training_features|
@activities[training_compound].each do |act|
case act.to_s
@@ -231,6 +235,7 @@ module OpenTox
### END AM balanced predictions
else # regression case: no balancing
+ LOGGER.info "LAZAR: Unbalanced."
neighbors
prediction = eval("#{@prediction_algorithm}(@neighbors,{:similarity_algorithm => @similarity_algorithm, :p_values => @p_values})")
end
--
cgit v1.2.3
From 3922c8e5fcb9fbe6ddedab9f70e114717ff33a60 Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Thu, 26 May 2011 14:28:19 +0200
Subject: 8th v
---
lib/algorithm.rb | 2 +-
lib/model.rb | 17 +++++++++++++----
2 files changed, 14 insertions(+), 5 deletions(-)
(limited to 'lib')
diff --git a/lib/algorithm.rb b/lib/algorithm.rb
index 91e075a..2652695 100644
--- a/lib/algorithm.rb
+++ b/lib/algorithm.rb
@@ -164,7 +164,7 @@ module OpenTox
# @param [Array] neighbors, each neighbor is a hash with keys `:similarity, :activity, :features`
# @param [Hash] params Keys `:similarity_algorithm,:p_values` are required
# @return [Hash] Hash with keys `:prediction, :confidence`
- def self.local_svm_regression(neighbors, params)
+ def self.local_svm_regression(neighbors, params, props=nil)
take_logs=true
neighbors.each do |n|
if (! n[:activity].nil?) && (n[:activity].to_f < 0.0)
diff --git a/lib/model.rb b/lib/model.rb
index 7c2ef58..28c05a9 100644
--- a/lib/model.rb
+++ b/lib/model.rb
@@ -69,7 +69,7 @@ module OpenTox
include Model
include Algorithm
- attr_accessor :compound, :prediction_dataset, :features, :effects, :activities, :p_values, :fingerprints, :feature_calculation_algorithm, :similarity_algorithm, :prediction_algorithm, :min_sim, :subjectid
+ attr_accessor :compound, :prediction_dataset, :features, :effects, :activities, :p_values, :fingerprints, :feature_calculation_algorithm, :similarity_algorithm, :prediction_algorithm, :min_sim, :subjectid, :prop_kernel
def initialize(uri=nil)
@@ -92,6 +92,7 @@ module OpenTox
@prediction_algorithm = "Neighbors.weighted_majority_vote"
@min_sim = 0.3
+ @prop_kernel = false
end
@@ -219,7 +220,11 @@ module OpenTox
(i == modulo[0]) && (slack>0) ? lr_size = s.size + slack : lr_size = s.size + addon # determine fraction
LOGGER.info "BLAZAR: Neighbors round #{i}: #{position} + #{lr_size}."
neighbors_balanced(s, l, position, lr_size) # get ratio fraction of larger part
- (@prediction_algorithm.include? "svm" and params[:prop_kernel] == "true") ? props = get_props : props = nil
+ if @prop_kernel && @prediction_algorithm.include?("svm")
+ props = get_props
+ else
+ props = nil
+ end
prediction = eval("#{@prediction_algorithm}(@neighbors,{:similarity_algorithm => @similarity_algorithm, :p_values => @p_values}, props)")
if prediction_best.nil? || prediction[:confidence].abs > prediction_best[:confidence].abs
prediction_best=prediction
@@ -235,10 +240,14 @@ module OpenTox
@neighbors=neighbors_best
### END AM balanced predictions
- else # regression case: no balancing
+ else # AM: no balancing
LOGGER.info "LAZAR: Unbalanced."
neighbors
- (@prediction_algorithm.include? "svm" and params[:prop_kernel] == "true") ? props = get_props : props = nil
+ if @prop_kernel && @prediction_algorithm.include?("svm")
+ props = get_props
+ else
+ props = nil
+ end
prediction = eval("#{@prediction_algorithm}(@neighbors,{:similarity_algorithm => @similarity_algorithm, :p_values => @p_values}, props)")
end
--
cgit v1.2.3
From a1135de5d9911838f4c020d73be9c462cba709d1 Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Thu, 26 May 2011 15:46:15 +0200
Subject: fix blazar nil error
---
lib/model.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/model.rb b/lib/model.rb
index 14471cc..edaa696 100644
--- a/lib/model.rb
+++ b/lib/model.rb
@@ -207,7 +207,7 @@ module OpenTox
# AM: Balanced predictions
addon = (modulo[1].to_f/modulo[0]).ceil # what will be added in each round
- slack = modulo[1].divmod(addon)[1] # what remains for the last round
+ slack = (addon!=0 ? modulo[1].divmod(addon)[1] : 0) # what remains for the last round
position = 0
predictions = Array.new
--
cgit v1.2.3
From 1ddea6e712319b7f21a6acf24739a2ef54c41042 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Thu, 26 May 2011 20:52:10 +0000
Subject: predicted/value and predicted/confidence stored as separate features
in model
---
lib/model.rb | 67 ++++++++++++++++++++++++++-----------------------------
lib/serializer.rb | 2 ++
2 files changed, 34 insertions(+), 35 deletions(-)
(limited to 'lib')
diff --git a/lib/model.rb b/lib/model.rb
index 139aed8..31a513e 100644
--- a/lib/model.rb
+++ b/lib/model.rb
@@ -168,7 +168,6 @@ module OpenTox
@prediction_dataset.add_metadata( {
OT.hasSource => @uri,
DC.creator => @uri,
- # TODO: fix dependentVariable
DC.title => URI.decode(File.basename( @metadata[OT.dependentVariables] )),
OT.parameters => [{DC.title => "compound_uri", OT.paramValue => compound_uri}]
} )
@@ -235,47 +234,16 @@ module OpenTox
prediction = eval("#{@prediction_algorithm}(@neighbors,{:similarity_algorithm => @similarity_algorithm, :p_values => @p_values})")
end
- # TODO: reasonable feature name
- #prediction_feature_uri = File.join( @prediction_dataset.uri, "feature", "prediction", File.basename(@metadata[OT.dependentVariables]),@prediction_dataset.compounds.size.to_s)
- value_feature_uri = File.join( @prediction_dataset.uri, "feature", "prediction", File.basename(@metadata[OT.dependentVariables]),"value")
- confidence_feature_uri = File.join( @prediction_dataset.uri, "feature", "prediction", File.basename(@metadata[OT.dependentVariables]),"confidence")
+ value_feature_uri = File.join( @uri, "predicted", "value")
+ confidence_feature_uri = File.join( @uri, "predicted", "confidence")
prediction_feature_uris = {value_feature_uri => prediction[:prediction], confidence_feature_uri => prediction[:confidence]}
- #prediction_feature_uris[value_feature_uri] = "No similar compounds in training dataset." if @neighbors.size == 0 or prediction[:prediction].nil?
prediction_feature_uris[value_feature_uri] = nil if @neighbors.size == 0 or prediction[:prediction].nil?
- #@prediction_dataset.metadata[OT.dependentVariables] = prediction_feature_uri
@prediction_dataset.metadata[OT.dependentVariables] = @metadata[OT.dependentVariables]
+ @prediction_dataset.metadata[OT.predictedVariables] = [value_feature_uri, confidence_feature_uri]
-=begin
- if @neighbors.size == 0
- prediction_feature_uris.each do |prediction_feature_uri,value|
- @prediction_dataset.add_feature(prediction_feature_uri, {
- RDF.type => [OT.MeasuredFeature],
- OT.hasSource => @uri,
- DC.creator => @uri,
- DC.title => URI.decode(File.basename( @metadata[OT.dependentVariables] )),
- OT.error => "No similar compounds in training dataset.",
- #OT.parameters => [{DC.title => "compound_uri", OT.paramValue => compound_uri}]
- })
- @prediction_dataset.add @compound.uri, prediction_feature_uri, value
- end
-
- else
-=end
prediction_feature_uris.each do |prediction_feature_uri,value|
- @prediction_dataset.metadata[OT.predictedVariables] = [] unless @prediction_dataset.metadata[OT.predictedVariables]
- @prediction_dataset.metadata[OT.predictedVariables] << prediction_feature_uri
- @prediction_dataset.add_feature(prediction_feature_uri, {
- RDF.type => [OT.ModelPrediction],
- OT.hasSource => @uri,
- DC.creator => @uri,
- DC.title => URI.decode(File.basename( @metadata[OT.dependentVariables] )),
- # TODO: factor information to value
- })
- #OT.prediction => prediction[:prediction],
- #OT.confidence => prediction[:confidence],
- #OT.parameters => [{DC.title => "compound_uri", OT.paramValue => compound_uri}]
@prediction_dataset.add @compound.uri, prediction_feature_uri, value
end
@@ -401,6 +369,35 @@ module OpenTox
end
end
+ def prediction_features
+ [prediction_value_feature,prediction_confidence_feature]
+ end
+
+ def prediction_value_feature
+ dependent_uri = @metadata[OT.dependentVariables].first
+ feature = OpenTox::Feature.new File.join( @uri, "predicted", "value")
+ feature.add_metadata( {
+ RDF.type => [OT.ModelPrediction],
+ OT.hasSource => @uri,
+ DC.creator => @uri,
+ DC.title => URI.decode(File.basename( dependent_uri )),
+ OWL.sameAs => dependent_uri
+ })
+ feature
+ end
+
+ def prediction_confidence_feature
+ dependent_uri = @metadata[OT.dependentVariables].first
+ feature = OpenTox::Feature.new File.join( @uri, "predicted", "confidence")
+ feature.add_metadata( {
+ RDF.type => [OT.ModelPrediction],
+ OT.hasSource => @uri,
+ DC.creator => @uri,
+ DC.title => "#{URI.decode(File.basename( dependent_uri ))} confidence"
+ })
+ feature
+ end
+
# Save model at model service
def save(subjectid)
self.uri = RestClientWrapper.post(@uri,self.to_yaml,{:content_type => "application/x-yaml", :subjectid => subjectid})
diff --git a/lib/serializer.rb b/lib/serializer.rb
index 62c1159..5a9fd0a 100644
--- a/lib/serializer.rb
+++ b/lib/serializer.rb
@@ -50,6 +50,7 @@ module OpenTox
OT.parameters => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
OT.featureDataset => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
OT.dependentVariables => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
+ OT.predictedVariables => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
OT.paramValue => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
#object props for validation#
@@ -191,6 +192,7 @@ module OpenTox
@object[metadata[OT.featureDataset]] = { RDF["type"] => [{ "type" => "uri", "value" => OT.Dataset }] }
@object[metadata[OT.trainingDataset]] = { RDF["type"] => [{ "type" => "uri", "value" => OT.Dataset }] }
@object[metadata[OT.dependentVariables]] = { RDF["type"] => [{ "type" => "uri", "value" => OT.Feature }] }
+ metadata[OT.predictedVariables].each{|feature| @object[feature] = { RDF["type"] => [{ "type" => "uri", "value" => OT.Feature }] }}
# TODO: add algorithms from parameters
@object["http://ot-dev.in-silico.ch/algorithm/fminer/bbrc"] = { RDF["type"] => [{ "type" => "uri", "value" => OT.Algorithm }] }
@object["http://ot-dev.in-silico.ch/algorithm/fminer/last"] = { RDF["type"] => [{ "type" => "uri", "value" => OT.Algorithm }] }
--
cgit v1.2.3
From af426336f15e1f4b58c87bf09571721bb42a388f Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Fri, 27 May 2011 10:06:12 +0200
Subject: predicted variable and confidence can now be derieved from model,
adjust feature_type accordingly
---
lib/feature.rb | 26 ++++++++++++-------------
lib/model.rb | 60 +++++++++++++++++++++++++++++++++++++++-------------------
2 files changed, 54 insertions(+), 32 deletions(-)
(limited to 'lib')
diff --git a/lib/feature.rb b/lib/feature.rb
index 2f1ab6c..f3bec5c 100644
--- a/lib/feature.rb
+++ b/lib/feature.rb
@@ -2,6 +2,8 @@ module OpenTox
class Feature
include OpenTox
+ attr_accessor :subjectid
+
# Find a feature
# @param [String] uri Feature URI
# @return [OpenTox::Task] Feature object
@@ -13,9 +15,9 @@ module OpenTox
else
feature.add_metadata Parser::Owl::Dataset.new(uri).load_metadata
end
+ feature.subjectid = subjectid
feature
end
-
# provides feature type, possible types are "regression" or "classification"
# @return [String] feature type, unknown if OT.isA property is unknown/ not set
@@ -24,21 +26,19 @@ module OpenTox
"classification"
elsif metadata[RDF.type].flatten.include?(OT.NumericFeature)
"regression"
- else
- #"unknown"
- metadata[RDF.type].inspect
- end
-=begin
- case metadata[RDF.type]
- when /NominalFeature/
- "classification"
- when /NumericFeature/
- "regression"
+ elsif metadata[OWL.sameAs]
+ metadata[OWL.sameAs].each do |f|
+ begin
+ type = Feature.find(f, subjectid).feature_type
+ return type unless type=="unknown"
+ rescue => ex
+ LOGGER.warn "could not load same-as-feature '"+f.to_s+"' for feature '"+uri.to_s+"' : "+ex.message.to_s
+ end
+ end
+ "unknown"
else
"unknown"
end
-=end
end
-
end
end
diff --git a/lib/model.rb b/lib/model.rb
index baf01a6..f0fd46b 100644
--- a/lib/model.rb
+++ b/lib/model.rb
@@ -38,29 +38,51 @@ module OpenTox
# provides feature type, possible types are "regression" or "classification"
# @return [String] feature type, "unknown" if type could not be estimated
def feature_type(subjectid=nil)
- return @feature_type if @feature_type
-
- # dynamically perform restcalls if necessary
- load_metadata(subjectid) if @metadata==nil or @metadata.size==0 or (@metadata.size==1 && @metadata.values[0]==@uri)
- algorithm = OpenTox::Algorithm::Generic.find(@metadata[OT.algorithm], subjectid)
- algorithm_title = algorithm ? algorithm.metadata[DC.title] : nil
- algorithm_type = algorithm ? algorithm.metadata[RDF.type] : nil
- dependent_variable = OpenTox::Feature.find( @metadata[OT.dependentVariables],subjectid )
- dependent_variable_type = dependent_variable ? dependent_variable.feature_type : nil
- type_indicators = [dependent_variable_type, @metadata[RDF.type], @metadata[DC.title], @uri, algorithm_type, algorithm_title].flatten
- type_indicators.each do |type|
- case type
- when /(?i)classification/
- @feature_type = "classification"
- break
- when /(?i)regression/
- @feature_type = "regression"
- end
+ unless @feature_type
+ load_predicted_variables( subjectid ) unless @predicted_variable
+ @feature_type = OpenTox::Feature.find( @predicted_variable, subjectid ).feature_type
end
- raise "unknown model "+type_indicators.inspect unless @feature_type
@feature_type
end
+
+ def predicted_variable( subjectid )
+ load_predicted_variables( subjectid ) unless @predicted_variable
+ @predicted_variable
+ end
+ def predicted_confidence( subjectid )
+ load_predicted_variables( subjectid ) unless @predicted_confidence
+ @predicted_confidence
+ end
+
+ private
+ def load_predicted_variables( subjectid=nil )
+ load_metadata(subjectid) if @metadata==nil or @metadata.size==0 or (@metadata.size==1 && @metadata.values[0]==@uri)
+ if @metadata[OT.predictedVariables]
+ predictedVariables = @metadata[OT.predictedVariables]
+ if predictedVariables.is_a?(Array)
+ if (predictedVariables.size==1)
+ @predicted_variable = predictedVariables[0]
+ elsif (predictedVariables.size==2)
+ # PENDING identify confidence
+ conf_index = -1
+ predictedVariables.size.times do |i|
+ f = OpenTox::Feature.find(predictedVariables[i])
+ conf_index = i if f.metadata[DC.title]=~/(?i)confidence/
+ end
+ raise "could not estimate predicted variable from model: '"+uri.to_s+
+ "', number of predicted-variables==2, but no confidence found" if conf_index==-1
+ @predicted_variable = predictedVariables[1-conf_index]
+ @predicted_confidence = predictedVariables[conf_index]
+ else
+ raise "could not estimate predicted variable from model: '"+uri.to_s+"', number of predicted-variables > 2"
+ end
+ else
+ raise "could not estimate predicted variable from model: '"+uri.to_s+"', predicted-variables is no array"
+ end
+ end
+ raise "could not estimate predicted variable from model: '"+uri.to_s+"'" unless @predicted_variable
+ end
end
# Lazy Structure Activity Relationship class
--
cgit v1.2.3
From 1dbf257583fb68658f4ba4ecde3602ebef07e540 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Mon, 30 May 2011 08:17:43 +0000
Subject: mail exceptions disabled
---
lib/config/config_ru.rb | 2 ++
lib/environment.rb | 2 +-
2 files changed, 3 insertions(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/config/config_ru.rb b/lib/config/config_ru.rb
index 93df867..dc04263 100644
--- a/lib/config/config_ru.rb
+++ b/lib/config/config_ru.rb
@@ -19,6 +19,7 @@ set :lock, true
end
use Rack::ShowExceptions
+=begin
if defined?(MAIL)
# monkeypatch with the original method
@@ -50,3 +51,4 @@ if defined?(MAIL)
mail.smtp MAIL
end
end
+=end
diff --git a/lib/environment.rb b/lib/environment.rb
index ffc4f60..28a9a66 100644
--- a/lib/environment.rb
+++ b/lib/environment.rb
@@ -27,7 +27,7 @@ end
Ohm.connect :thread_safe => true
# load mail settings for error messages
-load File.join config_dir,"mail.rb" if File.exists?(File.join config_dir,"mail.rb")
+#load File.join config_dir,"mail.rb" if File.exists?(File.join config_dir,"mail.rb")
logfile = "#{LOG_DIR}/#{ENV["RACK_ENV"]}.log"
#LOGGER = OTLogger.new(logfile,'daily') # daily rotation
--
cgit v1.2.3
From a5945d10144e49ff983dd02b0860aeb4e4e8ab1c Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Tue, 31 May 2011 08:59:18 +0000
Subject: keep classes from external datasets
---
lib/model.rb | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)
(limited to 'lib')
diff --git a/lib/model.rb b/lib/model.rb
index 4321646..02fabfa 100644
--- a/lib/model.rb
+++ b/lib/model.rb
@@ -91,7 +91,7 @@ module OpenTox
include Model
include Algorithm
- attr_accessor :compound, :prediction_dataset, :features, :effects, :activities, :p_values, :fingerprints, :feature_calculation_algorithm, :similarity_algorithm, :prediction_algorithm, :min_sim, :subjectid, :prop_kernel
+ attr_accessor :compound, :prediction_dataset, :features, :effects, :activities, :p_values, :fingerprints, :feature_calculation_algorithm, :similarity_algorithm, :prediction_algorithm, :min_sim, :subjectid, :prop_kernel, :value_map
def initialize(uri=nil)
@@ -108,6 +108,7 @@ module OpenTox
@activities = {}
@p_values = {}
@fingerprints = {}
+ @value_map = {}
@feature_calculation_algorithm = "Substructure.match"
@similarity_algorithm = "Similarity.tanimoto"
@@ -275,15 +276,21 @@ module OpenTox
value_feature_uri = File.join( @uri, "predicted", "value")
confidence_feature_uri = File.join( @uri, "predicted", "confidence")
- prediction_feature_uris = {value_feature_uri => prediction[:prediction], confidence_feature_uri => prediction[:confidence]}
- prediction_feature_uris[value_feature_uri] = nil if @neighbors.size == 0 or prediction[:prediction].nil?
+ #prediction_feature_uris = {value_feature_uri => prediction[:prediction], confidence_feature_uri => prediction[:confidence]}
+ #prediction_feature_uris[value_feature_uri] = nil if @neighbors.size == 0 or prediction[:prediction].nil?
@prediction_dataset.metadata[OT.dependentVariables] = @metadata[OT.dependentVariables]
@prediction_dataset.metadata[OT.predictedVariables] = [value_feature_uri, confidence_feature_uri]
- prediction_feature_uris.each do |prediction_feature_uri,value|
- @prediction_dataset.add @compound.uri, prediction_feature_uri, value
+ if OpenTox::Feature.find(metadata[OT.dependentVariables]).feature_type == "classification"
+ @prediction_dataset.add @compound.uri, value_feature_uri, @value_map[prediction[:prediction]]
+ else
+ @prediction_dataset.add @compound.uri, value_feature_uri, prediction[:prediction]
end
+ @prediction_dataset.add @compound.uri, confidence_feature_uri, prediction[:confidence]
+ #prediction_feature_uris.each do |prediction_feature_uri,value|
+ #@prediction_dataset.add @compound.uri, prediction_feature_uri, @value_map[value]
+ #end
if verbose
if @feature_calculation_algorithm == "Substructure.match"
--
cgit v1.2.3
From b98bc374b119e5a21f43d4f45048376aeeeead09 Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Tue, 31 May 2011 13:51:09 +0200
Subject: fix set acceptValues when splitting dataset for validation
---
lib/dataset.rb | 6 ++++++
1 file changed, 6 insertions(+)
(limited to 'lib')
diff --git a/lib/dataset.rb b/lib/dataset.rb
index fc7c263..5e6a29b 100644
--- a/lib/dataset.rb
+++ b/lib/dataset.rb
@@ -304,6 +304,12 @@ module OpenTox
end
end
end
+ # set feature metadata in new dataset accordingly (including accept values)
+ features.each do |f|
+ self.features[f].each do |k,v|
+ dataset.features[f][k] = v
+ end
+ end
dataset.add_metadata(metadata)
dataset.save(subjectid)
dataset
--
cgit v1.2.3
From 64354959e04fcac11bcf70e75099691b74573033 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Tue, 16 Aug 2011 14:46:31 +0200
Subject: initial minimal version
---
lib/algorithm.rb | 15 +++--
lib/authorization.rb | 4 +-
lib/compound.rb | 21 +++----
lib/dataset.rb | 164 +++++++++++++++++++++------------------------------
lib/environment.rb | 12 ++--
lib/error.rb | 1 -
lib/feature.rb | 6 +-
lib/helper.rb | 3 +-
lib/model.rb | 66 +++++++++++++--------
lib/opentox-ruby.rb | 17 +++---
lib/opentox.rb | 16 +++--
lib/overwrite.rb | 4 ++
lib/to-html.rb | 1 -
13 files changed, 161 insertions(+), 169 deletions(-)
(limited to 'lib')
diff --git a/lib/algorithm.rb b/lib/algorithm.rb
index 2652695..4c50d32 100644
--- a/lib/algorithm.rb
+++ b/lib/algorithm.rb
@@ -1,8 +1,8 @@
# R integration
# workaround to initialize R non-interactively (former rinruby versions did this by default)
# avoids compiling R with X
-R = nil
-require "rinruby"
+#R = nil
+#require "rinruby"
module OpenTox
@@ -16,6 +16,7 @@ module OpenTox
# @param [optional,OpenTox::Task] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
# @return [String] URI of new resource (dataset, model, ...)
def run(params=nil, waiting_task=nil)
+ #puts @uri
RestClientWrapper.post(@uri, params, {:accept => 'text/uri-list'}, waiting_task).to_s
end
@@ -37,7 +38,7 @@ module OpenTox
def self.find(uri, subjectid=nil)
return nil unless uri
alg = Generic.new(uri)
- alg.load_metadata( subjectid )
+ alg.load_metadata
raise "cannot load algorithm metadata" if alg.metadata==nil or alg.metadata.size==0
alg
end
@@ -54,7 +55,7 @@ module OpenTox
# Initialize bbrc algorithm
def initialize(subjectid=nil)
super File.join(CONFIG[:services]["opentox-algorithm"], "fminer/bbrc")
- load_metadata(subjectid)
+ load_metadata
end
end
@@ -64,7 +65,7 @@ module OpenTox
# Initialize last algorithm
def initialize(subjectid=nil)
super File.join(CONFIG[:services]["opentox-algorithm"], "fminer/last")
- load_metadata(subjectid)
+ load_metadata
end
end
@@ -76,10 +77,11 @@ module OpenTox
# Initialize lazar algorithm
def initialize(subjectid=nil)
super File.join(CONFIG[:services]["opentox-algorithm"], "lazar")
- load_metadata(subjectid)
+ load_metadata
end
end
+=begin
# Utility methods without dedicated webservices
# Similarity calculations
@@ -399,6 +401,7 @@ module OpenTox
m_pos = array.size / 2
return array.size % 2 == 1 ? array[m_pos] : (array[m_pos-1] + array[m_pos])/2
end
+=end
end
end
diff --git a/lib/authorization.rb b/lib/authorization.rb
index 288733a..27ae734 100644
--- a/lib/authorization.rb
+++ b/lib/authorization.rb
@@ -2,7 +2,7 @@ module OpenTox
#Module for Authorization and Authentication
#@example Authentication
- # require "opentox-ruby-api-wrapper"
+ # require "opentox-ruby"
# OpenTox::Authorization::AA_SERVER = "https://opensso.in-silico.ch" #if not set in .opentox/conf/[environment].yaml
# token = OpenTox::Authorization.authenticate("benutzer", "passwort")
#@see http://www.opentox.org/dev/apis/api-1.2/AA OpenTox A&A API 1.2 specification
@@ -389,4 +389,4 @@ module OpenTox
end
end
-end
\ No newline at end of file
+end
diff --git a/lib/compound.rb b/lib/compound.rb
index a85507b..189db7b 100644
--- a/lib/compound.rb
+++ b/lib/compound.rb
@@ -29,30 +29,21 @@ module OpenTox
# @param [String] smiles Smiles string
# @return [OpenTox::Compound] Compound
def self.from_smiles(smiles)
- c = Compound.new
- c.inchi = Compound.smiles2inchi(smiles)
- c.uri = File.join(CONFIG[:services]["opentox-compound"],URI.escape(c.inchi))
- c
+ Compound.new RestClientWrapper.post(CONFIG[:services]["opentox-compound"], smiles, :content_type => 'chemical/x-daylight-smiles').to_s.chomp
end
# Create a compound from inchi string
# @param [String] smiles InChI string
# @return [OpenTox::Compound] Compound
def self.from_inchi(inchi)
- c = Compound.new
- c.inchi = inchi
- c.uri = File.join(CONFIG[:services]["opentox-compound"],URI.escape(c.inchi))
- c
+ Compound.new RestClientWrapper.post(CONFIG[:services]["opentox-compound"], inchi, :content_type => 'chemical/x-inchi').to_s.chomp
end
# Create a compound from sdf string
# @param [String] smiles SDF string
# @return [OpenTox::Compound] Compound
def self.from_sdf(sdf)
- c = Compound.new
- c.inchi = Compound.sdf2inchi(sdf)
- c.uri = File.join(CONFIG[:services]["opentox-compound"],URI.escape(c.inchi))
- c
+ Compound.new RestClientWrapper.post(CONFIG[:services]["opentox-compound"], sdf, :content_type => 'chemical/x-mdl-sdfile').to_s.chomp
end
# Create a compound from name. Relies on an external service for name lookups.
@@ -77,13 +68,13 @@ module OpenTox
# Get (canonical) smiles
# @return [String] Smiles string
def to_smiles
- Compound.obconversion(@inchi,'inchi','can')
+ RestClientWrapper.get(@uri, :accept => 'chemical/x-daylight-smiles').chomp
end
# Get sdf
# @return [String] SDF string
def to_sdf
- Compound.obconversion(@inchi,'inchi','sdf')
+ RestClientWrapper.get(@uri, :accept => 'chemical/x-mdl-sdfile').chomp
end
# Get gif image
@@ -118,6 +109,7 @@ module OpenTox
end
end
+=begin
# Match a smarts string
# @example
# compound = OpenTox::Compound.from_name("Benzene")
@@ -195,5 +187,6 @@ module OpenTox
obconversion.write_string(obmol)
end
end
+=end
end
end
diff --git a/lib/dataset.rb b/lib/dataset.rb
index 5e6a29b..84dce65 100644
--- a/lib/dataset.rb
+++ b/lib/dataset.rb
@@ -1,6 +1,7 @@
module OpenTox
# Ruby wrapper for OpenTox Dataset Webservices (http://opentox.org/dev/apis/api-1.2/dataset).
+ # TODO: fix API Doc
class Dataset
include OpenTox
@@ -15,7 +16,7 @@ module OpenTox
# @param [optional, String] uri Dataset URI
# @return [OpenTox::Dataset] Dataset object
def initialize(uri=nil,subjectid=nil)
- super uri
+ super uri, subjectid
@features = {}
@compounds = []
@data_entries = {}
@@ -28,7 +29,17 @@ module OpenTox
# @return [OpenTox::Dataset] Dataset object
def self.create(uri=CONFIG[:services]["opentox-dataset"], subjectid=nil)
dataset = Dataset.new(nil,subjectid)
- dataset.save(subjectid)
+ dataset.save
+ dataset
+ end
+
+ # Find a dataset and load all data. This can be time consuming, use Dataset.new together with one of the load_* methods for a fine grained control over data loading.
+ # @param [String] uri Dataset URI
+ # @return [OpenTox::Dataset] Dataset object with all data
+ def self.find(uri, subjectid=nil)
+ return nil unless uri
+ dataset = Dataset.new(uri, subjectid)
+ dataset.load_metadata
dataset
end
@@ -40,20 +51,9 @@ module OpenTox
# @return [OpenTox::Dataset] Dataset object with CSV data
def self.create_from_csv_file(file, subjectid=nil)
dataset = Dataset.create(CONFIG[:services]["opentox-dataset"], subjectid)
- parser = Parser::Spreadsheets.new
- parser.dataset = dataset
- parser.load_csv(File.open(file).read)
- dataset.save(subjectid)
- dataset
- end
-
- # Find a dataset and load all data. This can be time consuming, use Dataset.new together with one of the load_* methods for a fine grained control over data loading.
- # @param [String] uri Dataset URI
- # @return [OpenTox::Dataset] Dataset object with all data
- def self.find(uri, subjectid=nil)
- return nil unless uri
- dataset = Dataset.new(uri, subjectid)
- dataset.load_all(subjectid)
+ #RestClientWrapper.post(dataset.uri,File.read(file), {:content_type => "text/csv", :subjectid => @subjectid})
+ RestClientWrapper.post(dataset.uri,{:file => File.new(file)},{:accept => "text/uri-list", :subjectid => subjectid})#, {:content_type => "text/csv", :subjectid => @subjectid})
+ dataset.load_metadata
dataset
end
@@ -64,7 +64,7 @@ module OpenTox
return false unless uri
dataset = Dataset.new(uri, subjectid)
begin
- dataset.load_metadata( subjectid ).size > 0
+ dataset.load_metadata.size > 0
rescue
false
end
@@ -80,26 +80,20 @@ module OpenTox
# Load YAML representation into the dataset
# @param [String] yaml YAML representation of the dataset
# @return [OpenTox::Dataset] Dataset object with YAML data
- def load_yaml(yaml)
- copy YAML.load(yaml)
+ def store_yaml(yaml)
+ RestClientWrapper.post(@uri,yaml, {:content_type => "application/x-yaml", :subjectid => @subjectid})
end
- def load_rdfxml(rdfxml)
- raise "rdfxml data is empty" if rdfxml.to_s.size==0
- file = Tempfile.new("ot-rdfxml")
- file.puts rdfxml
- file.close
- load_rdfxml_file file
- file.delete
+ def store_rdfxml(rdfxml)
+ RestClientWrapper.post(@uri, rdfxml, {:content_type => "application/rdf+xml", :subjectid => @subjectid})
end
# Load RDF/XML representation from a file
# @param [String] file File with RDF/XML representation of the dataset
# @return [OpenTox::Dataset] Dataset object with RDF/XML data
- def load_rdfxml_file(file, subjectid=nil)
- parser = Parser::Owl::Dataset.new @uri, subjectid
- parser.uri = file.path
- copy parser.load_uri(subjectid)
+ def store_rdfxml_file(file)
+ #RestClientWrapper.post(@uri, :file => File.new(file))#, {:content_type => "application/rdf+xml", :subjectid => @subjectid})
+ RestClientWrapper.post(@uri, File.read(file), {:content_type => "application/rdf+xml", :subjectid => @subjectid})
end
# Load CSV string (format specification: http://toxcreate.org/help)
@@ -108,11 +102,8 @@ module OpenTox
# - you will have to set remaining metadata manually
# @param [String] csv CSV representation of the dataset
# @return [OpenTox::Dataset] Dataset object with CSV data
- def load_csv(csv, subjectid=nil)
- save(subjectid) unless @uri # get a uri for creating features
- parser = Parser::Spreadsheets.new
- parser.dataset = self
- parser.load_csv(csv)
+ def store_csv(csv)
+ RestClientWrapper.post(@uri, csv, {:content_type => "text/csv", :subjectid => @subjectid})
end
# Load Spreadsheet book (created with roo gem http://roo.rubyforge.org/, excel format specification: http://toxcreate.org/help)
@@ -121,35 +112,36 @@ module OpenTox
# - you will have to set remaining metadata manually
# @param [Excel] book Excel workbook object (created with roo gem)
# @return [OpenTox::Dataset] Dataset object with Excel data
- def load_spreadsheet(book, subjectid=nil)
- save(subjectid) unless @uri # get a uri for creating features
- parser = Parser::Spreadsheets.new
- parser.dataset = self
- parser.load_spreadsheet(book)
+ def store_spreadsheet_file(file)
+ RestClientWrapper.post(@uri, :file => File.new(file))#, {:content_type => "application/vnd.ms-excel", :subjectid => @subjectid})
end
# Load and return only metadata of a Dataset object
# @return [Hash] Metadata of the dataset
- def load_metadata(subjectid=nil)
- add_metadata Parser::Owl::Dataset.new(@uri, subjectid).load_metadata(subjectid)
+ def load_metadata
+ if (CONFIG[:yaml_hosts].include?(URI.parse(@uri).host))
+ @metadata = YAML.load(RestClientWrapper.get(File.join(@uri,"metadata"), {:accept => "application/x-yaml", :subjectid => @subjectid}))
+ else
+ add_metadata Parser::Owl::Dataset.new(@uri, @subjectid).load_metadata
+ end
self.uri = @uri if @uri # keep uri
@metadata
end
# Load all data (metadata, data_entries, compounds and features) from URI
- def load_all(subjectid=nil)
+ def load_all
if (CONFIG[:yaml_hosts].include?(URI.parse(@uri).host))
- copy YAML.load(RestClientWrapper.get(@uri, {:accept => "application/x-yaml", :subjectid => subjectid}))
+ copy YAML.load(RestClientWrapper.get(@uri, {:accept => "application/x-yaml", :subjectid => @subjectid}))
else
- parser = Parser::Owl::Dataset.new(@uri, subjectid)
- copy parser.load_uri(subjectid)
+ parser = Parser::Owl::Dataset.new(@uri, @subjectid)
+ copy parser.load_uri
end
end
# Load and return only compound URIs from the dataset service
# @return [Array] Compound URIs in the dataset
- def load_compounds(subjectid=nil)
- RestClientWrapper.get(File.join(uri,"compounds"),{:accept=> "text/uri-list", :subjectid => subjectid}).to_s.each_line do |compound_uri|
+ def load_compounds
+ RestClientWrapper.get(File.join(uri,"compounds"),{:accept=> "text/uri-list", :subjectid => @subjectid}).to_s.each_line do |compound_uri|
@compounds << compound_uri.chomp
end
@compounds.uniq!
@@ -157,12 +149,12 @@ module OpenTox
# Load and return only features from the dataset service
# @return [Hash] Features of the dataset
- def load_features(subjectid=nil)
+ def load_features
if (CONFIG[:yaml_hosts].include?(URI.parse(@uri).host))
- @features = YAML.load(RestClientWrapper.get(File.join(@uri,"features"), {:accept => "application/x-yaml", :subjectid => subjectid}))
+ @features = YAML.load(RestClientWrapper.get(File.join(@uri,"features"), {:accept => "application/x-yaml", :subjectid => @subjectid}))
else
- parser = Parser::Owl::Dataset.new(@uri, subjectid)
- @features = parser.load_features(subjectid)
+ parser = Parser::Owl::Dataset.new(@uri, @subjectid)
+ @features = parser.load_features
end
@features
end
@@ -171,6 +163,7 @@ module OpenTox
# @param [String] feature the URI of the feature
# @return [Array] return array with strings, nil if value is not set (e.g. when feature is numeric)
def accept_values(feature)
+ load_features
accept_values = features[feature][OT.acceptValue]
accept_values.sort if accept_values
accept_values
@@ -178,8 +171,8 @@ module OpenTox
# Detect feature type(s) in the dataset
# @return [String] `classification", "regression", "mixed" or unknown`
- def feature_type(subjectid=nil)
- load_features(subjectid)
+ def feature_type
+ load_features
feature_types = @features.collect{|f,metadata| metadata[RDF.type]}.flatten.uniq
if feature_types.include?(OT.NominalFeature)
"classification"
@@ -189,13 +182,11 @@ module OpenTox
"unknown"
end
end
-=begin
-=end
# Get Spreadsheet representation
# @return [Spreadsheet::Workbook] Workbook which can be written with the spreadsheet gem (data_entries only, metadata will will be discarded))
def to_spreadsheet
- Serializer::Spreadsheets.new(self).to_spreadsheet
+ Spreadsheet::Workbook.new(RestClientWrapper.get(@uri, {:accept => "application/vnd.ms-excel", :subjectid => @subjectid}))
end
# Get Excel representation (alias for to_spreadsheet)
@@ -207,33 +198,31 @@ module OpenTox
# Get CSV string representation (data_entries only, metadata will be discarded)
# @return [String] CSV representation
def to_csv
- Serializer::Spreadsheets.new(self).to_csv
+ RestClientWrapper.get(@uri, {:accept => "text/csv", :subjectid => @subjectid})
end
# Get OWL-DL in ntriples format
# @return [String] N-Triples representation
def to_ntriples
- s = Serializer::Owl.new
- s.add_dataset(self)
- s.to_ntriples
+ RestClientWrapper.get(@uri, {:accept => "application/rdf+xml", :subjectid => @subjectid})
end
# Get OWL-DL in RDF/XML format
# @return [String] RDF/XML representation
def to_rdfxml
- s = Serializer::Owl.new
- s.add_dataset(self)
- s.to_rdfxml
+ RestClientWrapper.get(@uri, {:accept => "application/rdf+xml", :subjectid => @subjectid})
end
# Get name (DC.title) of a feature
# @param [String] feature Feature URI
# @return [String] Feture title
def feature_name(feature)
+ load_features
@features[feature][DC.title]
end
def title
+ load_metadata
@metadata[DC.title]
end
@@ -251,14 +240,6 @@ module OpenTox
@data_entries[compound][feature] << value if value!=nil
end
- # Add/modify metadata, existing entries will be overwritten
- # @example
- # dataset.add_metadata({DC.title => "any_title", DC.creator => "my_email"})
- # @param [Hash] metadata Hash mapping predicate_uris to values
- def add_metadata(metadata)
- metadata.each { |k,v| @metadata[k] = v }
- end
-
# Add a feature
# @param [String] feature Feature URI
# @param [Hash] metadata Hash with feature metadata
@@ -285,10 +266,10 @@ module OpenTox
# @param [Hash] metadata Hash containing the metadata for the new dataset
# @param [String] subjectid
# @return [OpenTox::Dataset] newly created dataset, already saved
- def split( compounds, features, metadata, subjectid=nil)
+ def split( compounds, features, metadata)
LOGGER.debug "split dataset using "+compounds.size.to_s+"/"+@compounds.size.to_s+" compounds"
raise "no new compounds selected" unless compounds and compounds.size>0
- dataset = OpenTox::Dataset.create(CONFIG[:services]["opentox-dataset"],subjectid)
+ dataset = OpenTox::Dataset.create(CONFIG[:services]["opentox-dataset"],@subjectid)
if features.size==0
compounds.each{ |c| dataset.add_compound(c) }
else
@@ -311,7 +292,7 @@ module OpenTox
end
end
dataset.add_metadata(metadata)
- dataset.save(subjectid)
+ dataset.save
dataset
end
@@ -319,29 +300,23 @@ module OpenTox
# - creates a new dataset if uri is not set
# - overwrites dataset if uri exists
# @return [String] Dataset URI
- def save(subjectid=nil)
- # TODO: rewrite feature URI's ??
+ def save
@compounds.uniq!
- if @uri
- if (CONFIG[:yaml_hosts].include?(URI.parse(@uri).host))
- RestClientWrapper.post(@uri,self.to_yaml,{:content_type => "application/x-yaml", :subjectid => subjectid})
- else
- File.open("ot-post-file.rdf","w+") { |f| f.write(self.to_rdfxml); @path = f.path }
- task_uri = RestClient.post(@uri, {:file => File.new(@path)},{:accept => "text/uri-list" , :subjectid => subjectid}).to_s.chomp
- #task_uri = `curl -X POST -H "Accept:text/uri-list" -F "file=@#{@path};type=application/rdf+xml" http://apps.ideaconsult.net:8080/ambit2/dataset`
- Task.find(task_uri).wait_for_completion
- self.uri = RestClientWrapper.get(task_uri,{:accept => 'text/uri-list', :subjectid => subjectid})
- end
+ # create dataset if uri is empty
+ self.uri = RestClientWrapper.post(CONFIG[:services]["opentox-dataset"],{:subjectid => @subjectid}).to_s.chomp unless @uri
+ if (CONFIG[:yaml_hosts].include?(URI.parse(@uri).host))
+ RestClientWrapper.post(@uri,self.to_yaml,{:content_type => "application/x-yaml", :subjectid => @subjectid})
else
- # create dataset if uri is empty
- self.uri = RestClientWrapper.post(CONFIG[:services]["opentox-dataset"],{:subjectid => subjectid}).to_s.chomp
+ s = Serializer::Owl.new
+ s.add_dataset(self)
+ RestClientWrapper.post(@uri, s.to_rdfxml,{:content_type => "application/rdf+xml" , :subjectid => @subjectid})
end
@uri
end
# Delete dataset at the dataset service
- def delete(subjectid=nil)
- RestClientWrapper.delete(@uri, :subjectid => subjectid)
+ def delete
+ RestClientWrapper.delete(@uri, :subjectid => @subjectid)
end
private
@@ -367,7 +342,7 @@ module OpenTox
# @return [OpenTox::Dataset] Prediction dataset object with all data
def self.find(uri, subjectid=nil)
prediction = LazarPrediction.new(uri, subjectid)
- prediction.load_all(subjectid)
+ prediction.load_all
prediction
end
@@ -392,10 +367,5 @@ module OpenTox
@data_entries[compound.uri].collect{|f,v| @features[f] if f.match(/neighbor/)}.compact
end
-# def errors(compound)
-# features = @data_entries[compound.uri].keys
-# features.collect{|f| @features[f][OT.error]}.join(" ") if features
-# end
-
end
end
diff --git a/lib/environment.rb b/lib/environment.rb
index 28a9a66..cae743c 100644
--- a/lib/environment.rb
+++ b/lib/environment.rb
@@ -24,7 +24,7 @@ end
# database
#`redis-server /opt/redis/redis.conf` unless File.exists? "/var/run/redis.pid" # removed by AM
-Ohm.connect :thread_safe => true
+# Ohm.connect :thread_safe => true
# load mail settings for error messages
#load File.join config_dir,"mail.rb" if File.exists?(File.join config_dir,"mail.rb")
@@ -69,11 +69,6 @@ class OwlNamespace
end
-AA_SERVER = CONFIG[:authorization] ? (CONFIG[:authorization][:server] ? CONFIG[:authorization][:server] : nil) : nil
-CONFIG[:authorization][:authenticate_request] = [""] unless CONFIG[:authorization][:authenticate_request]
-CONFIG[:authorization][:authorize_request] = [""] unless CONFIG[:authorization][:authorize_request]
-CONFIG[:authorization][:free_request] = [""] unless CONFIG[:authorization][:free_request]
-
RDF = OwlNamespace.new 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'
OWL = OwlNamespace.new 'http://www.w3.org/2002/07/owl#'
DC = OwlNamespace.new 'http://purl.org/dc/elements/1.1/'
@@ -81,3 +76,8 @@ OT = OwlNamespace.new 'http://www.opentox.org/api/1.1#'
OTA = OwlNamespace.new 'http://www.opentox.org/algorithmTypes.owl#'
XSD = OwlNamespace.new 'http://www.w3.org/2001/XMLSchema#'
+AA_SERVER = CONFIG[:authorization] ? (CONFIG[:authorization][:server] ? CONFIG[:authorization][:server] : nil) : nil
+CONFIG[:authorization][:authenticate_request] = [""] unless CONFIG[:authorization][:authenticate_request]
+CONFIG[:authorization][:authorize_request] = [""] unless CONFIG[:authorization][:authorize_request]
+CONFIG[:authorization][:free_request] = [""] unless CONFIG[:authorization][:free_request]
+
diff --git a/lib/error.rb b/lib/error.rb
index b92f2a4..45b7545 100644
--- a/lib/error.rb
+++ b/lib/error.rb
@@ -1,4 +1,3 @@
-
# adding additional fields to Exception class to format errors according to OT-API
class Exception
attr_accessor :errorCause
diff --git a/lib/feature.rb b/lib/feature.rb
index f3bec5c..84a85b9 100644
--- a/lib/feature.rb
+++ b/lib/feature.rb
@@ -6,12 +6,12 @@ module OpenTox
# Find a feature
# @param [String] uri Feature URI
- # @return [OpenTox::Task] Feature object
+ # @return [OpenTox::Feature] Feature object
def self.find(uri, subjectid=nil)
return nil unless uri
- feature = Feature.new uri
+ feature = Feature.new uri, subjectid
if (CONFIG[:yaml_hosts].include?(URI.parse(uri).host))
- feature.add_metadata YAML.load(RestClientWrapper.get(uri,{:accept => "application/x-yaml", :subjectid => subjectid}))
+ feature.add_metadata YAML.load(RestClientWrapper.get(uri,{:accept => "application/x-yaml", :subjectid => @subjectid}))
else
feature.add_metadata Parser::Owl::Dataset.new(uri).load_metadata
end
diff --git a/lib/helper.rb b/lib/helper.rb
index 995f3e9..04300e0 100644
--- a/lib/helper.rb
+++ b/lib/helper.rb
@@ -1,3 +1,4 @@
+=begin
helpers do
# Authentification
@@ -94,4 +95,4 @@ before do
protected!(@subjectid)
end
end
-
+=end
diff --git a/lib/model.rb b/lib/model.rb
index 02fabfa..a806b74 100644
--- a/lib/model.rb
+++ b/lib/model.rb
@@ -4,6 +4,24 @@ module OpenTox
include OpenTox
+ # Find a lazar model
+ # @param [String] uri Model URI
+ # @return [OpenTox::Model::Lazar] lazar model
+ def self.find(uri, subjectid=nil)
+ if CONFIG[:yaml_hosts].include?(URI.parse(uri).host)
+ YAML.load RestClientWrapper.get(uri,{:accept => 'application/x-yaml', :subjectid => subjectid})
+ else
+ parser = Parser::Owl::Feature.new(uri, @subjectid)
+ @metadata = parser.load_uri.metadata
+ end
+ end
+
+ # Get URIs of all models
+ # @return [Array] List of lazar model URIs
+ def self.all(subjectid=nil)
+ RestClientWrapper.get(CONFIG[:services]["opentox-model"], :subjectid => subjectid).to_s.split("\n")
+ end
+
# Run a model with parameters
# @param [Hash] params Parameters for OpenTox model
# @param [optional,OpenTox::Task] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
@@ -29,35 +47,35 @@ module OpenTox
# @return [OpenTox::Model::Generic] Model instance
def self.find(uri,subjectid=nil)
return nil unless uri
- model = Generic.new(uri)
- model.load_metadata(subjectid)
+ model = Generic.new(uri,subjectid)
+ model.load_metadata
raise "could not load model metadata '"+uri.to_s+"'" if model.metadata==nil or model.metadata.size==0
model
end
# provides feature type, possible types are "regression" or "classification"
# @return [String] feature type, "unknown" if type could not be estimated
- def feature_type(subjectid=nil)
+ def feature_type
unless @feature_type
- load_predicted_variables( subjectid ) unless @predicted_variable
- @feature_type = OpenTox::Feature.find( @predicted_variable, subjectid ).feature_type
+ load_predicted_variables unless @predicted_variable
+ @feature_type = OpenTox::Feature.find( @predicted_variable, @subjectid ).feature_type
end
@feature_type
end
- def predicted_variable( subjectid )
- load_predicted_variables( subjectid ) unless @predicted_variable
+ def predicted_variable
+ load_predicted_variables unless @predicted_variable
@predicted_variable
end
- def predicted_confidence( subjectid )
- load_predicted_variables( subjectid ) unless @predicted_confidence
+ def predicted_confidence
+ load_predicted_variables unless @predicted_confidence
@predicted_confidence
end
private
- def load_predicted_variables( subjectid=nil )
- load_metadata(subjectid) if @metadata==nil or @metadata.size==0 or (@metadata.size==1 && @metadata.values[0]==@uri)
+ def load_predicted_variables
+ load_metadata if @metadata==nil or @metadata.size==0 or (@metadata.size==1 && @metadata.values[0]==@uri)
if @metadata[OT.predictedVariables]
predictedVariables = @metadata[OT.predictedVariables]
if predictedVariables.is_a?(Array)
@@ -86,14 +104,14 @@ module OpenTox
end
# Lazy Structure Activity Relationship class
- class Lazar
+ class Lazar < Generic
- include Model
+ #include Model
include Algorithm
attr_accessor :compound, :prediction_dataset, :features, :effects, :activities, :p_values, :fingerprints, :feature_calculation_algorithm, :similarity_algorithm, :prediction_algorithm, :min_sim, :subjectid, :prop_kernel, :value_map
- def initialize(uri=nil)
+ def initialize(uri=nil,subjectid=nil)
if uri
super uri
@@ -119,17 +137,15 @@ module OpenTox
end
- # Get URIs of all lazar models
- # @return [Array] List of lazar model URIs
- def self.all(subjectid=nil)
- RestClientWrapper.get(CONFIG[:services]["opentox-model"], :subjectid => subjectid).to_s.split("\n")
- end
-
- # Find a lazar model
+ # Find a lazar model via URI, and loads metadata, could raise NotFound/NotAuthorized error
# @param [String] uri Model URI
- # @return [OpenTox::Model::Lazar] lazar model
- def self.find(uri, subjectid=nil)
- YAML.load RestClientWrapper.get(uri,{:accept => 'application/x-yaml', :subjectid => subjectid})
+ # @return [OpenTox::Model::Generic] Model instance
+ def self.find(uri,subjectid=nil)
+ return nil unless uri
+ model = Lazar.new(uri,subjectid)
+ model.load_metadata
+ raise "could not load model metadata '"+uri.to_s+"'" if model.metadata==nil or model.metadata.size==0
+ model
end
# Create a new lazar model
@@ -142,6 +158,7 @@ module OpenTox
OpenTox::Model::Lazar.find(model_uri, subjectid)
end
+=begin
# Get a parameter value
# @param [String] param Parameter name
# @return [String] Parameter value
@@ -465,6 +482,7 @@ module OpenTox
RestClientWrapper.delete(@uri, :subjectid => subjectid) unless @uri == CONFIG[:services]["opentox-model"]
end
+=end
end
end
end
diff --git a/lib/opentox-ruby.rb b/lib/opentox-ruby.rb
index ae05cb2..16abee9 100644
--- a/lib/opentox-ruby.rb
+++ b/lib/opentox-ruby.rb
@@ -1,14 +1,15 @@
-['rubygems', 'sinatra', 'sinatra/url_for', 'ohm', 'rest_client', 'yaml', 'cgi', 'spork', 'error', 'overwrite', 'environment'].each do |lib|
+#['rubygems', 'sinatra', 'sinatra/url_for', 'ohm', 'rest_client', 'yaml', 'cgi', 'spork', 'error', 'overwrite', 'environment'].each do |lib|
+['rubygems', 'rest_client', 'yaml', 'cgi', 'spork', 'error', 'overwrite', 'environment'].each do |lib|
require lib
end
-begin
- require 'openbabel'
-rescue LoadError
- puts "Please install Openbabel with 'rake openbabel:install' in the compound component"
-end
+#begin
+ #require 'openbabel'
+#rescue LoadError
+ #puts "Please install Openbabel with 'rake openbabel:install' in the compound component"
+#end
-['opentox', 'compound','dataset', 'parser','serializer', 'algorithm','model','task','validation','feature',
- 'rest_client_wrapper', 'authorization', 'policy', 'helper', 'to-html', 'ontology' ].each do |lib|
+#['opentox', 'compound','dataset', 'parser','serializer', 'algorithm','model','task','validation','feature', 'rest_client_wrapper', 'authorization', 'policy', 'helper', 'to-html', 'ontology' ].each do |lib|
+['opentox', 'compound','dataset', 'parser','serializer', 'algorithm','model','task','validation','feature', 'rest_client_wrapper', 'authorization', 'policy', 'ontology' ].each do |lib|
require lib
end
diff --git a/lib/opentox.rb b/lib/opentox.rb
index c76e21a..6250d86 100644
--- a/lib/opentox.rb
+++ b/lib/opentox.rb
@@ -5,8 +5,9 @@ module OpenTox
# Initialize OpenTox object with optional uri
# @param [optional, String] URI
- def initialize(uri=nil)
+ def initialize(uri=nil,subjectid=nil)
@metadata = {}
+ @subjectid = subjectid
self.uri = uri if uri
end
@@ -25,11 +26,15 @@ module OpenTox
# Load (and return) metadata from object URI
# @return [Hash] Metadata
- def load_metadata(subjectid=nil)
- @metadata = Parser::Owl::Generic.new(@uri).load_metadata(subjectid)
+ def load_metadata
+ @metadata = Parser::Owl::Generic.new(@uri).load_metadata
@metadata
end
+ # Add/modify metadata, existing entries will be overwritten
+ # @example
+ # dataset.add_metadata({DC.title => "any_title", DC.creator => "my_email"})
+ # @param [Hash] metadata Hash mapping predicate_uris to values
def add_metadata(metadata)
metadata.each do |k,v|
if v.is_a? Array
@@ -46,13 +51,12 @@ module OpenTox
def to_rdfxml
s = Serializer::Owl.new
s.add_metadata(@uri,@metadata)
- #s.add_parameters(@uri,@parameters) if @parameters
s.to_rdfxml
end
# deletes the resource, deletion should have worked when no RestCallError raised
- def delete(subjectid=nil)
- RestClientWrapper.delete(uri,:subjectid => subjectid)
+ def delete
+ RestClientWrapper.delete(uri,:subjectid => @subjectid)
end
end
diff --git a/lib/overwrite.rb b/lib/overwrite.rb
index df4e1b7..efc570d 100644
--- a/lib/overwrite.rb
+++ b/lib/overwrite.rb
@@ -1,3 +1,4 @@
+=begin
# class overwrites aka monkey patches
# hack: store sinatra instance in global var $url_provider to make url_for and halt methods accessible
before {
@@ -61,6 +62,7 @@ class Sinatra::Base
end
end
end
+=end
class String
def task_uri?
@@ -143,8 +145,10 @@ class OTLogger < Logger
end
# make migration from datamapper more straightforward
+=begin
class Ohm::Model
def self.get(id)
self[id]
end
end
+=end
diff --git a/lib/to-html.rb b/lib/to-html.rb
index 2c29f7d..04fa158 100644
--- a/lib/to-html.rb
+++ b/lib/to-html.rb
@@ -1,4 +1,3 @@
-
OT_LOGO = File.join(CONFIG[:services]["opentox-validation"],"resources/ot-logo.png")
class String
--
cgit v1.2.3
From 442aa6f6647756d10d57cd7869cb3d27c87b24a8 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Tue, 10 Jan 2012 13:04:01 +0100
Subject: untested update
---
lib/opentox-ruby.rb | 2 +-
lib/opentox.rb | 143 +++++++++++++++++++++++++++++++--------------
lib/parser.rb | 6 +-
lib/rest_client_wrapper.rb | 2 +-
lib/task.rb | 2 +-
5 files changed, 107 insertions(+), 48 deletions(-)
(limited to 'lib')
diff --git a/lib/opentox-ruby.rb b/lib/opentox-ruby.rb
index 16abee9..63935fa 100644
--- a/lib/opentox-ruby.rb
+++ b/lib/opentox-ruby.rb
@@ -1,5 +1,5 @@
#['rubygems', 'sinatra', 'sinatra/url_for', 'ohm', 'rest_client', 'yaml', 'cgi', 'spork', 'error', 'overwrite', 'environment'].each do |lib|
-['rubygems', 'rest_client', 'yaml', 'cgi', 'spork', 'error', 'overwrite', 'environment'].each do |lib|
+['rubygems', 'rest_client', 'yaml', 'cgi', 'error', 'overwrite', 'environment'].each do |lib|
require lib
end
diff --git a/lib/opentox.rb b/lib/opentox.rb
index 6250d86..dbe2360 100644
--- a/lib/opentox.rb
+++ b/lib/opentox.rb
@@ -1,51 +1,70 @@
+require "./parser.rb"
+require "./rest_client_wrapper.rb"
+require "./error.rb"
+
+SERVICES = ["Compound", "Feature", "Dataset", "Algorithm", "Model", "Validation", "Task"]
+
module OpenTox
- attr_reader :uri
- attr_accessor :metadata
+ attr_accessor :subjectid, :uri
+ attr_writer :metadata
- # Initialize OpenTox object with optional uri
- # @param [optional, String] URI
- def initialize(uri=nil,subjectid=nil)
- @metadata = {}
+ # Initialize OpenTox object with optional subjectid
+ # @param [optional, String] subjectid
+ def initialize uri=nil, subjectid=nil
+ @uri = uri
@subjectid = subjectid
- self.uri = uri if uri
end
- # Set URI
- # @param [String] URI
- def uri=(uri)
- @uri = uri
- @metadata[XSD.anyURI] = uri
- end
-
- # Get all objects from a service
- # @return [Array] List of available URIs
- def self.all(uri, subjectid=nil)
- RestClientWrapper.get(uri,:accept => "text/uri-list", :subjectid => subjectid).to_s.split(/\n/)
- end
-
- # Load (and return) metadata from object URI
- # @return [Hash] Metadata
- def load_metadata
- @metadata = Parser::Owl::Generic.new(@uri).load_metadata
- @metadata
- end
-
- # Add/modify metadata, existing entries will be overwritten
- # @example
- # dataset.add_metadata({DC.title => "any_title", DC.creator => "my_email"})
- # @param [Hash] metadata Hash mapping predicate_uris to values
- def add_metadata(metadata)
- metadata.each do |k,v|
- if v.is_a? Array
- @metadata[k] = [] unless @metadata[k]
- @metadata[k] << v
- else
- @metadata[k] = v
- end
- end
+ def metadata
+ @metadata ||= Parser::Owl::Generic.from_rdf get(:accept => "application/rdf+xml")
+ end
+
+ # REST API
+ # returns OpenTox::WrapperResult, not OpenTox objects
+
+ # perfoms a GET REST call
+ # raises OpenTox::Error if call fails (rescued in overwrite.rb -> halt 502)
+ # per default: waits for Task to finish and returns result URI of Task
+ # @param [optional,Hash] headers contains params like accept-header
+ # @param [wait,Boolean] wait set to false to NOT wait for task if result is task
+ # @return [OpenTox::WrapperResult] a String containing the result-body of the REST call
+ def get headers={}, wait=true
+ headers[:subjectid] = @subjectid
+ RestClientWrapper.get(@uri, headers, nil, wait).chomp
end
+ # performs a POST REST call
+ # raises OpenTox::Error if call fails (rescued in overwrite.rb -> halt 502)
+ # per default: waits for Task to finish and returns result URI of Task
+ # @param [optional,String] payload data posted to the service
+ # @param [optional,Hash] headers contains params like accept-header
+ # @param [wait,Boolean] wait set to false to NOT wait for task if result is task
+ # @return [OpenTox::WrapperResult] a String containing the result-body of the REST call
+ def post payload=nil, headers={}, wait=true
+ headers[:subjectid] = @subjectid
+ RestClientWrapper.post(@uri, payload, headers, nil, wait).chomp
+ end
+
+ # performs a PUT REST call
+ # raises OpenTox::Error if call fails (rescued in overwrite.rb -> halt 502)
+ # @param [optional,String] payload data put to the service
+ # @param [optional,Hash] headers contains params like accept-header
+ # @return [OpenTox::WrapperResult] a String containing the result-body of the REST call
+ def put payload=nil, headers={}
+ headers[:subjectid] = @subjectid
+ RestClientWrapper.put(@uri, payload, headers).chomp
+ end
+
+ # performs a DELETE REST call
+ # raises OpenTox::Error if call fails (rescued in overwrite.rb -> halt 502)
+ # @return [OpenTox::WrapperResult] a String containing the result-body of the REST call
+ def delete
+ RestClientWrapper.delete(@uri,:subjectid => @subjectid)
+ end
+
+ # Tools
+
# Get OWL-DL representation in RDF/XML format
# @return [application/rdf+xml] RDF/XML representation
def to_rdfxml
@@ -54,9 +73,47 @@ module OpenTox
s.to_rdfxml
end
- # deletes the resource, deletion should have worked when no RestCallError raised
- def delete
- RestClientWrapper.delete(uri,:subjectid => @subjectid)
+ def uri_available?
+ url = URI.parse(@uri)
+ #TODO: move subjectid to header
+ subjectidstr = @subjectid ? "?subjectid=#{CGI.escape @subjectid}" : ""
+ Net::HTTP.start(url.host, url.port) do |http|
+ return http.head("#{url.request_uri}#{subjectidstr}").code == "200"
+ end
+ end
+
+ # create default classes
+ SERVICES.each { |s| eval "class #{s}; include OpenTox; end" }
+
+ module Collection
+
+ include OpenTox
+
+ def find
+ uri_available? ? object_class.new(@uri, @subjectid) : nil
+ end
+
+ def create metadata
+ object_class.new post(service_uri, metadata.to_rdfxml, { :content_type => 'application/rdf+xml', :subjectid => subjectid}).to_s.chomp, @subject_id
+ end
+
+ # Get all objects from a service
+ # @return [Array] List of available Objects
+ def all
+ get(:accept => "text/uri-list").to_s.split(/\n/).collect{|uri| object_class.new uri,@subjectid}
+ end
+
+ def save object
+ object_class.new post(object.to_rdfxml, :content_type => 'application/rdf+xml').to_s, @subjectid
+ end
+
+ def object_class
+ eval self.class.to_s.sub(/::Collection/,'')
+ end
+
+ # create collection classes
+ SERVICES.each { |s| eval "class #{s}; include Collection; end" }
+
end
end
diff --git a/lib/parser.rb b/lib/parser.rb
index a6878a2..580f6f7 100644
--- a/lib/parser.rb
+++ b/lib/parser.rb
@@ -1,5 +1,5 @@
-require 'spreadsheet'
-require 'roo'
+#require 'spreadsheet'
+#require 'roo'
class String
@@ -259,6 +259,7 @@ module OpenTox
end
+=begin
# Parser for getting spreadsheet data into a dataset
class Spreadsheets
@@ -440,5 +441,6 @@ module OpenTox
end
end
+=end
end
end
diff --git a/lib/rest_client_wrapper.rb b/lib/rest_client_wrapper.rb
index 53887a2..3dd3eff 100644
--- a/lib/rest_client_wrapper.rb
+++ b/lib/rest_client_wrapper.rb
@@ -53,7 +53,7 @@ module OpenTox
private
def self.execute( rest_call, uri, payload=nil, headers={}, waiting_task=nil, wait=true )
- raise OpenTox::BadRequestError.new "uri is null" unless uri
+ raise OpenTox::BadRequestError.new "uri is nil" unless uri
raise OpenTox::BadRequestError.new "not a uri: "+uri.to_s unless uri.to_s.uri?
raise "headers are no hash: "+headers.inspect unless headers==nil or headers.is_a?(Hash)
raise OpenTox::BadRequestError.new "accept should go into the headers" if payload and payload.is_a?(Hash) and payload[:accept]
diff --git a/lib/task.rb b/lib/task.rb
index 146a756..3815177 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -231,7 +231,7 @@ module OpenTox
else
raise "content type for tasks not supported: "+content_type.to_s
end
- raise "uri is null after loading" unless @uri and @uri.to_s.strip.size>0
+ raise "uri is nil after loading" unless @uri and @uri.to_s.strip.size>0
end
=end
--
cgit v1.2.3
From e84a1b439e63ae3ed3b4bc3bc78261f95daf9ab7 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Wed, 11 Jan 2012 21:00:20 +0100
Subject: basic rest post get delete test working
---
lib/opentox.rb | 59 +++++++++++++++++++++++++---------------------
lib/overwrite.rb | 1 +
lib/parser.rb | 29 +++++++++++++++++++++++
lib/rest_client_wrapper.rb | 1 +
4 files changed, 63 insertions(+), 27 deletions(-)
(limited to 'lib')
diff --git a/lib/opentox.rb b/lib/opentox.rb
index dbe2360..b0ffcb1 100644
--- a/lib/opentox.rb
+++ b/lib/opentox.rb
@@ -1,13 +1,18 @@
-require "./parser.rb"
-require "./rest_client_wrapper.rb"
-require "./error.rb"
-
+require 'rdf'
+require 'rdf/raptor'
+#require "parser.rb"
+require "rest_client_wrapper.rb"
+require "overwrite.rb"
+require "error.rb"
+
+RDF::OT = RDF::Vocabulary.new 'http://www.opentox.org/api/1.1#'
+RDF::OTA = RDF::Vocabulary.new 'http://www.opentox.org/algorithmTypes.owl#'
SERVICES = ["Compound", "Feature", "Dataset", "Algorithm", "Model", "Validation", "Task"]
module OpenTox
- attr_accessor :subjectid, :uri
- attr_writer :metadata
+ attr_accessor :subjectid, :uri #, :service_uri
+ #attr_writer :metadata
# Initialize OpenTox object with optional subjectid
# @param [optional, String] subjectid
@@ -17,7 +22,13 @@ module OpenTox
end
def metadata
- @metadata ||= Parser::Owl::Generic.from_rdf get(:accept => "application/rdf+xml")
+ metadata = {}
+ RDF::Reader.open(@uri) do |reader|
+ reader.each_statement do |statement|
+ metadata[statement.predicate] = statement.object if statement.subject == @uri
+ end
+ end
+ metadata
end
# REST API
@@ -31,7 +42,7 @@ module OpenTox
# @return [OpenTox::WrapperResult] a String containing the result-body of the REST call
def get headers={}, wait=true
headers[:subjectid] = @subjectid
- RestClientWrapper.get(@uri, headers, nil, wait).chomp
+ RestClientWrapper.get(@uri.to_s, headers, nil, wait).chomp
end
# performs a POST REST call
@@ -41,9 +52,9 @@ module OpenTox
# @param [optional,Hash] headers contains params like accept-header
# @param [wait,Boolean] wait set to false to NOT wait for task if result is task
# @return [OpenTox::WrapperResult] a String containing the result-body of the REST call
- def post payload=nil, headers={}, wait=true
+ def post payload={}, headers={}, wait=true
headers[:subjectid] = @subjectid
- RestClientWrapper.post(@uri, payload, headers, nil, wait).chomp
+ RestClientWrapper.post(@uri.to_s, payload, headers, nil, wait).chomp
end
# performs a PUT REST call
@@ -51,40 +62,33 @@ module OpenTox
# @param [optional,String] payload data put to the service
# @param [optional,Hash] headers contains params like accept-header
# @return [OpenTox::WrapperResult] a String containing the result-body of the REST call
- def put payload=nil, headers={}
+ def put payload={}, headers={}
headers[:subjectid] = @subjectid
- RestClientWrapper.put(@uri, payload, headers).chomp
+ RestClientWrapper.put(@uri.to_s, payload, headers).chomp
end
# performs a DELETE REST call
# raises OpenTox::Error if call fails (rescued in overwrite.rb -> halt 502)
# @return [OpenTox::WrapperResult] a String containing the result-body of the REST call
def delete
- RestClientWrapper.delete(@uri,:subjectid => @subjectid)
+ RestClientWrapper.delete(@uri.to_s,:subjectid => @subjectid)
end
- # Tools
+ # create default classes
+ SERVICES.each { |s| eval "class #{s}; include OpenTox; end" }
- # Get OWL-DL representation in RDF/XML format
- # @return [application/rdf+xml] RDF/XML representation
- def to_rdfxml
- s = Serializer::Owl.new
- s.add_metadata(@uri,@metadata)
- s.to_rdfxml
- end
+=begin
+ # Tools
def uri_available?
url = URI.parse(@uri)
- #TODO: move subjectid to header
- subjectidstr = @subjectid ? "?subjectid=#{CGI.escape @subjectid}" : ""
- Net::HTTP.start(url.host, url.port) do |http|
+ req = Net::HTTP.new(url.host,url.port)
+ req['subjectid'] = @subjectid if @subjectid
+ req.start(url.host, url.port) do |http|
return http.head("#{url.request_uri}#{subjectidstr}").code == "200"
end
end
- # create default classes
- SERVICES.each { |s| eval "class #{s}; include OpenTox; end" }
-
module Collection
include OpenTox
@@ -115,6 +119,7 @@ module OpenTox
SERVICES.each { |s| eval "class #{s}; include Collection; end" }
end
+=end
end
diff --git a/lib/overwrite.rb b/lib/overwrite.rb
index efc570d..d541b61 100644
--- a/lib/overwrite.rb
+++ b/lib/overwrite.rb
@@ -1,3 +1,4 @@
+require 'uri'
=begin
# class overwrites aka monkey patches
# hack: store sinatra instance in global var $url_provider to make url_for and halt methods accessible
diff --git a/lib/parser.rb b/lib/parser.rb
index 580f6f7..7475d6d 100644
--- a/lib/parser.rb
+++ b/lib/parser.rb
@@ -1,6 +1,35 @@
#require 'spreadsheet'
#require 'roo'
+# OWL Namespaces
+class OwlNamespace
+
+ attr_accessor :uri
+ def initialize(uri)
+ @uri = uri
+ end
+
+ def [](property)
+ @uri+property.to_s
+ end
+
+ def type # for RDF.type
+ "#{@uri}type"
+ end
+
+ def method_missing(property)
+ @uri+property.to_s
+ end
+
+end
+
+RDF = OwlNamespace.new 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'
+OWL = OwlNamespace.new 'http://www.w3.org/2002/07/owl#'
+DC = OwlNamespace.new 'http://purl.org/dc/elements/1.1/'
+OT = OwlNamespace.new 'http://www.opentox.org/api/1.1#'
+OTA = OwlNamespace.new 'http://www.opentox.org/algorithmTypes.owl#'
+XSD = OwlNamespace.new 'http://www.w3.org/2001/XMLSchema#'
+
class String
# Split RDF statement into triples
diff --git a/lib/rest_client_wrapper.rb b/lib/rest_client_wrapper.rb
index 3dd3eff..30f04cc 100644
--- a/lib/rest_client_wrapper.rb
+++ b/lib/rest_client_wrapper.rb
@@ -1,3 +1,4 @@
+require 'rest-client'
module OpenTox
class WrapperResult < String
--
cgit v1.2.3
From ac54997dccc571471a0cdf62939e2fcbc42e06e2 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Fri, 13 Jan 2012 12:49:09 +0100
Subject: compound added
---
lib/compound.rb | 39 +++++++--------------------
lib/opentox-ruby-minimal.rb | 2 ++
lib/opentox.rb | 64 +++++++++++++++++++++++++++------------------
3 files changed, 51 insertions(+), 54 deletions(-)
create mode 100644 lib/opentox-ruby-minimal.rb
(limited to 'lib')
diff --git a/lib/compound.rb b/lib/compound.rb
index 189db7b..974e46e 100644
--- a/lib/compound.rb
+++ b/lib/compound.rb
@@ -6,44 +6,27 @@ module OpenTox
# Ruby wrapper for OpenTox Compound Webservices (http://opentox.org/dev/apis/api-1.2/structure).
class Compound
- attr_accessor :inchi, :uri
-
- # Create compound with optional uri
- # @example
- # compound = OpenTox::Compound.new("http://webservices.in-silico.ch/compound/InChI=1S/C6H6/c1-2-4-6-5-3-1/h1-6H"")
- # @param [optional, String] uri Compound URI
- # @return [OpenTox::Compound] Compound
- def initialize(uri=nil)
- @uri = uri
- case @uri
- when /InChI/ # shortcut for IST services
- @inchi = @uri.sub(/^.*InChI/, 'InChI')
- else
- @inchi = RestClientWrapper.get(@uri, :accept => 'chemical/x-inchi').to_s.chomp if @uri
- end
- end
-
# Create a compound from smiles string
# @example
# compound = OpenTox::Compound.from_smiles("c1ccccc1")
# @param [String] smiles Smiles string
# @return [OpenTox::Compound] Compound
- def self.from_smiles(smiles)
- Compound.new RestClientWrapper.post(CONFIG[:services]["opentox-compound"], smiles, :content_type => 'chemical/x-daylight-smiles').to_s.chomp
+ def self.from_smiles service_uri, smiles, subjectid=nil
+ Compound.new RestClientWrapper.post(service_uri, smiles, :content_type => 'chemical/x-daylight-smiles').to_s.chomp
end
# Create a compound from inchi string
# @param [String] smiles InChI string
# @return [OpenTox::Compound] Compound
- def self.from_inchi(inchi)
- Compound.new RestClientWrapper.post(CONFIG[:services]["opentox-compound"], inchi, :content_type => 'chemical/x-inchi').to_s.chomp
+ def self.from_inchi(service_uri, inchi)
+ Compound.new RestClientWrapper.post(service_uri, inchi, :content_type => 'chemical/x-inchi').to_s.chomp
end
# Create a compound from sdf string
# @param [String] smiles SDF string
# @return [OpenTox::Compound] Compound
- def self.from_sdf(sdf)
- Compound.new RestClientWrapper.post(CONFIG[:services]["opentox-compound"], sdf, :content_type => 'chemical/x-mdl-sdfile').to_s.chomp
+ def self.from_sdf(service_uri, sdf)
+ Compound.new RestClientWrapper.post(service_uri, sdf, :content_type => 'chemical/x-mdl-sdfile').to_s.chomp
end
# Create a compound from name. Relies on an external service for name lookups.
@@ -51,18 +34,16 @@ module OpenTox
# compound = OpenTox::Compound.from_name("Benzene")
# @param [String] name name can be also an InChI/InChiKey, CAS number, etc
# @return [OpenTox::Compound] Compound
- def self.from_name(name)
- c = Compound.new
+ def self.from_name(service_uri, name)
# paranoid URI encoding to keep SMILES charges and brackets
- c.inchi = RestClientWrapper.get("#{@@cactus_uri}#{URI.encode(name, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))}/stdinchi").to_s.chomp
- c.uri = File.join(CONFIG[:services]["opentox-compound"],URI.escape(c.inchi))
- c
+ inchi = RestClientWrapper.get("#{@@cactus_uri}#{URI.encode(name, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))}/stdinchi").to_s.chomp
+ Compound.new File.join(service_uri,URI.escape(inchi))
end
# Get InChI
# @return [String] InChI string
def to_inchi
- @inchi
+ RestClientWrapper.get(@uri, :accept => 'chemical/x-inchi').to_s.chomp if @uri
end
# Get (canonical) smiles
diff --git a/lib/opentox-ruby-minimal.rb b/lib/opentox-ruby-minimal.rb
new file mode 100644
index 0000000..e0d5489
--- /dev/null
+++ b/lib/opentox-ruby-minimal.rb
@@ -0,0 +1,2 @@
+require "opentox"
+require "compound"
diff --git a/lib/opentox.rb b/lib/opentox.rb
index b0ffcb1..a6ac1d4 100644
--- a/lib/opentox.rb
+++ b/lib/opentox.rb
@@ -11,8 +11,8 @@ SERVICES = ["Compound", "Feature", "Dataset", "Algorithm", "Model", "Validation"
module OpenTox
- attr_accessor :subjectid, :uri #, :service_uri
- #attr_writer :metadata
+ attr_accessor :subjectid, :uri
+ attr_writer :metadata
# Initialize OpenTox object with optional subjectid
# @param [optional, String] subjectid
@@ -21,14 +21,26 @@ module OpenTox
@subjectid = subjectid
end
- def metadata
- metadata = {}
- RDF::Reader.open(@uri) do |reader|
- reader.each_statement do |statement|
- metadata[statement.predicate] = statement.object if statement.subject == @uri
+ # Ruby interface
+
+ def metadata reload=true
+ if reload
+ @metadata = {}
+ RDF::Reader.open(@uri) do |reader|
+ reader.each_statement do |statement|
+ @metadata[statement.predicate] = statement.object if statement.subject == @uri
+ end
end
end
- metadata
+ @metadata
+ end
+
+ def save
+ rdf = RDF::Writer.buffer do |writer|
+ @metadata.each { |p,o| writer << RDF::Statement.new(RDF::URI.new(@uri), p, o) }
+ end
+ puts rdf
+ #post(@uri, rdf, { :content_type => 'application/rdf+xml', :subjectid => subjectid}).to_s.chomp, @subjectid
end
# REST API
@@ -74,17 +86,31 @@ module OpenTox
RestClientWrapper.delete(@uri.to_s,:subjectid => @subjectid)
end
+
+ module Service
+ def create service_uri, subjectid=nil
+ service = eval("#{self}.new(\"#{service_uri}\", #{subjectid})")
+ uri = service.post({}, {}, subjectid).to_s
+ eval "#{self}.new(\"#{uri}\", #{subjectid})"
+ end
+ end
+
# create default classes
- SERVICES.each { |s| eval "class #{s}; include OpenTox; end" }
+ SERVICES.each do |s|
+ eval "class #{s}
+ include OpenTox
+ extend OpenTox::Service
+ end"
+ end
=begin
- # Tools
+ private
def uri_available?
url = URI.parse(@uri)
- req = Net::HTTP.new(url.host,url.port)
- req['subjectid'] = @subjectid if @subjectid
- req.start(url.host, url.port) do |http|
+ #req = Net::HTTP.new(url.host,url.port)
+ #req['subjectid'] = @subjectid if @subjectid
+ Net::HTTP.start(url.host, url.port) do |http|
return http.head("#{url.request_uri}#{subjectidstr}").code == "200"
end
end
@@ -93,10 +119,6 @@ module OpenTox
include OpenTox
- def find
- uri_available? ? object_class.new(@uri, @subjectid) : nil
- end
-
def create metadata
object_class.new post(service_uri, metadata.to_rdfxml, { :content_type => 'application/rdf+xml', :subjectid => subjectid}).to_s.chomp, @subject_id
end
@@ -107,14 +129,6 @@ module OpenTox
get(:accept => "text/uri-list").to_s.split(/\n/).collect{|uri| object_class.new uri,@subjectid}
end
- def save object
- object_class.new post(object.to_rdfxml, :content_type => 'application/rdf+xml').to_s, @subjectid
- end
-
- def object_class
- eval self.class.to_s.sub(/::Collection/,'')
- end
-
# create collection classes
SERVICES.each { |s| eval "class #{s}; include Collection; end" }
--
cgit v1.2.3
From 354aaa649e9eeed5d81793e09d9714b45063c147 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Wed, 8 Feb 2012 13:14:11 +0100
Subject: toxbank-investigation compatible version
---
lib/algorithm.rb | 398 +---------------------
lib/authorization.rb | 156 ++++-----
lib/compound.rb | 31 +-
lib/config/config_ru.rb | 54 ---
lib/dataset.rb | 253 ++++++--------
lib/environment.rb | 83 -----
lib/error.rb | 98 ------
lib/feature.rb | 44 ---
lib/helper.rb | 98 ------
lib/model.rb | 480 +-------------------------
lib/ontology.rb | 55 ---
lib/opentox-client.rb | 7 +
lib/opentox-ruby-minimal.rb | 2 -
lib/opentox-ruby.rb | 15 -
lib/opentox.owl | 809 --------------------------------------------
lib/opentox.rb | 214 +++++++-----
lib/overwrite.rb | 155 ---------
lib/parser.rb | 475 --------------------------
lib/rest_client_wrapper.rb | 182 ----------
lib/serializer.rb | 491 ---------------------------
lib/spork.rb | 83 -----
lib/task.rb | 367 ++------------------
lib/to-html.rb | 109 ------
lib/validation.rb | 313 -----------------
24 files changed, 354 insertions(+), 4618 deletions(-)
delete mode 100644 lib/config/config_ru.rb
delete mode 100644 lib/environment.rb
delete mode 100644 lib/error.rb
delete mode 100644 lib/feature.rb
delete mode 100644 lib/helper.rb
delete mode 100644 lib/ontology.rb
create mode 100644 lib/opentox-client.rb
delete mode 100644 lib/opentox-ruby-minimal.rb
delete mode 100644 lib/opentox-ruby.rb
delete mode 100644 lib/opentox.owl
delete mode 100644 lib/overwrite.rb
delete mode 100644 lib/parser.rb
delete mode 100644 lib/rest_client_wrapper.rb
delete mode 100644 lib/serializer.rb
delete mode 100644 lib/spork.rb
delete mode 100644 lib/to-html.rb
delete mode 100644 lib/validation.rb
(limited to 'lib')
diff --git a/lib/algorithm.rb b/lib/algorithm.rb
index 4c50d32..4986c40 100644
--- a/lib/algorithm.rb
+++ b/lib/algorithm.rb
@@ -1,407 +1,15 @@
-# R integration
-# workaround to initialize R non-interactively (former rinruby versions did this by default)
-# avoids compiling R with X
-#R = nil
-#require "rinruby"
-
module OpenTox
# Wrapper for OpenTox Algorithms
- module Algorithm
-
- include OpenTox
+ class Algorithm
# Execute algorithm with parameters, please consult the OpenTox API and the webservice documentation for acceptable parameters
# @param [optional,Hash] params Algorithm parameters
# @param [optional,OpenTox::Task] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
# @return [String] URI of new resource (dataset, model, ...)
- def run(params=nil, waiting_task=nil)
- #puts @uri
- RestClientWrapper.post(@uri, params, {:accept => 'text/uri-list'}, waiting_task).to_s
- end
-
- # Get OWL-DL representation in RDF/XML format
- # @return [application/rdf+xml] RDF/XML representation
- def to_rdfxml
- s = Serializer::Owl.new
- s.add_algorithm(@uri,@metadata)
- s.to_rdfxml
- end
-
- # Generic Algorithm class, should work with all OpenTox webservices
- class Generic
- include Algorithm
-
- # Find Generic Opentox Algorithm via URI, and loads metadata, could raise NotFound/NotAuthorized error
- # @param [String] uri Algorithm URI
- # @return [OpenTox::Algorithm::Generic] Algorithm instance
- def self.find(uri, subjectid=nil)
- return nil unless uri
- alg = Generic.new(uri)
- alg.load_metadata
- raise "cannot load algorithm metadata" if alg.metadata==nil or alg.metadata.size==0
- alg
- end
-
- end
-
- # Fminer algorithms (https://github.com/amaunz/fminer2)
- module Fminer
- include Algorithm
-
- # Backbone Refinement Class mining (http://bbrc.maunz.de/)
- class BBRC
- include Fminer
- # Initialize bbrc algorithm
- def initialize(subjectid=nil)
- super File.join(CONFIG[:services]["opentox-algorithm"], "fminer/bbrc")
- load_metadata
- end
- end
-
- # LAtent STructure Pattern Mining (http://last-pm.maunz.de)
- class LAST
- include Fminer
- # Initialize last algorithm
- def initialize(subjectid=nil)
- super File.join(CONFIG[:services]["opentox-algorithm"], "fminer/last")
- load_metadata
- end
- end
-
- end
-
- # Create lazar prediction model
- class Lazar
- include Algorithm
- # Initialize lazar algorithm
- def initialize(subjectid=nil)
- super File.join(CONFIG[:services]["opentox-algorithm"], "lazar")
- load_metadata
- end
- end
-
-=begin
- # Utility methods without dedicated webservices
-
- # Similarity calculations
- module Similarity
- include Algorithm
-
- # Tanimoto similarity
- # @param [Array] features_a Features of first compound
- # @param [Array] features_b Features of second compound
- # @param [optional, Hash] weights Weights for all features
- # @return [Float] (Weighted) tanimoto similarity
- def self.tanimoto(features_a,features_b,weights=nil)
- common_features = features_a & features_b
- all_features = (features_a + features_b).uniq
- common_p_sum = 0.0
- if common_features.size > 0
- if weights
- common_features.each{|f| common_p_sum += Algorithm.gauss(weights[f])}
- all_p_sum = 0.0
- all_features.each{|f| all_p_sum += Algorithm.gauss(weights[f])}
- common_p_sum/all_p_sum
- else
- common_features.to_f/all_features
- end
- else
- 0.0
- end
- end
-
- # Euclidean similarity
- # @param [Hash] properties_a Properties of first compound
- # @param [Hash] properties_b Properties of second compound
- # @param [optional, Hash] weights Weights for all properties
- # @return [Float] (Weighted) euclidean similarity
- def self.euclidean(properties_a,properties_b,weights=nil)
- common_properties = properties_a.keys & properties_b.keys
- if common_properties.size > 1
- dist_sum = 0
- common_properties.each do |p|
- if weights
- dist_sum += ( (properties_a[p] - properties_b[p]) * Algorithm.gauss(weights[p]) )**2
- else
- dist_sum += (properties_a[p] - properties_b[p])**2
- end
- end
- 1/(1+Math.sqrt(dist_sum))
- else
- 0.0
- end
- end
- end
-
- module Neighbors
-
- # Classification with majority vote from neighbors weighted by similarity
- # @param [Array] neighbors, each neighbor is a hash with keys `:similarity, :activity`
- # @param [optional] params Ignored (only for compatibility with local_svm_regression)
- # @return [Hash] Hash with keys `:prediction, :confidence`
- def self.weighted_majority_vote(neighbors,params={}, props=nil)
- conf = 0.0
- confidence = 0.0
- neighbors.each do |neighbor|
- case neighbor[:activity].to_s
- when 'true'
- conf += Algorithm.gauss(neighbor[:similarity])
- when 'false'
- conf -= Algorithm.gauss(neighbor[:similarity])
- end
- end
- if conf > 0.0
- prediction = true
- elsif conf < 0.0
- prediction = false
- else
- prediction = nil
- end
- confidence = conf/neighbors.size if neighbors.size > 0
- {:prediction => prediction, :confidence => confidence.abs}
- end
-
- # Local support vector regression from neighbors
- # @param [Array] neighbors, each neighbor is a hash with keys `:similarity, :activity, :features`
- # @param [Hash] params Keys `:similarity_algorithm,:p_values` are required
- # @return [Hash] Hash with keys `:prediction, :confidence`
- def self.local_svm_regression(neighbors, params, props=nil)
- take_logs=true
- neighbors.each do |n|
- if (! n[:activity].nil?) && (n[:activity].to_f < 0.0)
- take_logs = false
- end
- end
- acts = neighbors.collect do |n|
- act = n[:activity]
- take_logs ? Math.log10(act.to_f) : act.to_f
- end # activities of neighbors for supervised learning
-
- sims = neighbors.collect{ |n| Algorithm.gauss(n[:similarity]) } # similarity values btwn q and nbors
- begin
- prediction = (props.nil? ? local_svm(neighbors, acts, sims, "nu-svr", params) : local_svm_prop(props, acts, "nu-svr", params))
- prediction = (take_logs ? 10**(prediction.to_f) : prediction.to_f)
- LOGGER.debug "Prediction is: '" + prediction.to_s + "'."
- rescue Exception => e
- LOGGER.debug "#{e.class}: #{e.message} #{e.backtrace}"
- end
-
- conf = sims.inject{|sum,x| sum + x }
- confidence = conf/neighbors.size if neighbors.size > 0
- {:prediction => prediction, :confidence => confidence}
-
- end
-
- # Local support vector classification from neighbors
- # @param [Array] neighbors, each neighbor is a hash with keys `:similarity, :activity, :features`
- # @param [Hash] params Keys `:similarity_algorithm,:p_values` are required
- # @param [Array] props, propositionalization of neighbors and query structure e.g. [ Array_for_q, two-nested-Arrays_for_n ]
- # @return [Hash] Hash with keys `:prediction, :confidence`
- def self.local_svm_classification(neighbors, params, props=nil)
- acts = neighbors.collect do |n|
- act = n[:activity]
- end # activities of neighbors for supervised learning
- acts_f = acts.collect {|v| v == true ? 1.0 : 0.0}
- sims = neighbors.collect{ |n| Algorithm.gauss(n[:similarity]) } # similarity values btwn q and nbors
- begin
- prediction = (props.nil? ? local_svm(neighbors, acts_f, sims, "C-bsvc", params) : local_svm_prop(props, acts_f, "C-bsvc", params))
- LOGGER.debug "Prediction is: '" + prediction.to_s + "'."
- rescue Exception => e
- LOGGER.debug "#{e.class}: #{e.message} #{e.backtrace}"
- end
-
- conf = sims.inject{|sum,x| sum + x }
- confidence = conf/neighbors.size if neighbors.size > 0
- {:prediction => prediction, :confidence => confidence}
-
- end
-
-
- # Local support vector prediction from neighbors.
- # Uses pre-defined Kernel Matrix.
- # Not to be called directly (use local_svm_regression or local_svm_classification).
- # @param [Array] neighbors, each neighbor is a hash with keys `:similarity, :activity, :features`
- # @param [Array] acts, activities for neighbors.
- # @param [Array] sims, similarities for neighbors.
- # @param [String] type, one of "nu-svr" (regression) or "C-bsvc" (classification).
- # @param [Hash] params Keys `:similarity_algorithm,:p_values` are required
- # @param [Array] props, propositionalization of neighbors and query structure e.g. [ Array_for_q, two-nested-Arrays_for_n ]
- # @return [Numeric] A prediction value.
- def self.local_svm(neighbors, acts, sims, type, params)
- LOGGER.debug "Local SVM (Weighted Tanimoto Kernel)."
- neighbor_matches = neighbors.collect{ |n| n[:features] } # URIs of matches
- gram_matrix = [] # square matrix of similarities between neighbors; implements weighted tanimoto kernel
- if neighbor_matches.size == 0
- raise "No neighbors found."
- else
- # gram matrix
- (0..(neighbor_matches.length-1)).each do |i|
- gram_matrix[i] = [] unless gram_matrix[i]
- # upper triangle
- ((i+1)..(neighbor_matches.length-1)).each do |j|
- sim = eval("#{params[:similarity_algorithm]}(neighbor_matches[i], neighbor_matches[j], params[:p_values])")
- gram_matrix[i][j] = Algorithm.gauss(sim)
- gram_matrix[j] = [] unless gram_matrix[j]
- gram_matrix[j][i] = gram_matrix[i][j] # lower triangle
- end
- gram_matrix[i][i] = 1.0
- end
-
- #LOGGER.debug gram_matrix.to_yaml
- @r = RinRuby.new(false,false) # global R instance leads to Socket errors after a large number of requests
- @r.eval "library('kernlab')" # this requires R package "kernlab" to be installed
- LOGGER.debug "Setting R data ..."
- # set data
- @r.gram_matrix = gram_matrix.flatten
- @r.n = neighbor_matches.size
- @r.y = acts
- @r.sims = sims
-
- begin
- LOGGER.debug "Preparing R data ..."
- # prepare data
- @r.eval "y<-as.vector(y)"
- @r.eval "gram_matrix<-as.kernelMatrix(matrix(gram_matrix,n,n))"
- @r.eval "sims<-as.vector(sims)"
-
- # model + support vectors
- LOGGER.debug "Creating SVM model ..."
- @r.eval "model<-ksvm(gram_matrix, y, kernel=matrix, type=\"#{type}\", nu=0.5)"
- @r.eval "sv<-as.vector(SVindex(model))"
- @r.eval "sims<-sims[sv]"
- @r.eval "sims<-as.kernelMatrix(matrix(sims,1))"
- LOGGER.debug "Predicting ..."
- if type == "nu-svr"
- @r.eval "p<-predict(model,sims)[1,1]"
- elsif type == "C-bsvc"
- @r.eval "p<-predict(model,sims)"
- end
- if type == "nu-svr"
- prediction = @r.p
- elsif type == "C-bsvc"
- prediction = (@r.p.to_f == 1.0 ? true : false)
- end
- @r.quit # free R
- rescue Exception => e
- LOGGER.debug "#{e.class}: #{e.message} #{e.backtrace}"
- end
-
- end
- prediction
- end
-
- # Local support vector prediction from neighbors.
- # Uses propositionalized setting.
- # Not to be called directly (use local_svm_regression or local_svm_classification).
- # @param [Array] neighbors, each neighbor is a hash with keys `:similarity, :activity, :features`
- # @param [Array] acts, activities for neighbors.
- # @param [Array] props, propositionalization of neighbors and query structure e.g. [ Array_for_q, two-nested-Arrays_for_n ]
- # @param [String] type, one of "nu-svr" (regression) or "C-bsvc" (classification).
- # @param [Hash] params Keys `:similarity_algorithm,:p_values` are required
- # @return [Numeric] A prediction value.
- def self.local_svm_prop(props, acts, type, params)
-
- LOGGER.debug "Local SVM (Propositionalization / Kernlab Kernel)."
- n_prop = props[0] # is a matrix, i.e. two nested Arrays.
- q_prop = props[1] # is an Array.
-
- #neighbor_matches = neighbors.collect{ |n| n[:features] } # URIs of matches
- #gram_matrix = [] # square matrix of similarities between neighbors; implements weighted tanimoto kernel
- if n_prop.size == 0
- raise "No neighbors found."
- else
- # gram matrix
- #(0..(neighbor_matches.length-1)).each do |i|
- # gram_matrix[i] = [] unless gram_matrix[i]
- # # upper triangle
- # ((i+1)..(neighbor_matches.length-1)).each do |j|
- # sim = eval("#{params[:similarity_algorithm]}(neighbor_matches[i], neighbor_matches[j], params[:p_values])")
- # gram_matrix[i][j] = Algorithm.gauss(sim)
- # gram_matrix[j] = [] unless gram_matrix[j]
- # gram_matrix[j][i] = gram_matrix[i][j] # lower triangle
- # end
- # gram_matrix[i][i] = 1.0
- #end
-
- #LOGGER.debug gram_matrix.to_yaml
- @r = RinRuby.new(false,false) # global R instance leads to Socket errors after a large number of requests
- @r.eval "library('kernlab')" # this requires R package "kernlab" to be installed
- LOGGER.debug "Setting R data ..."
- # set data
- @r.n_prop = n_prop.flatten
- @r.n_prop_x_size = n_prop.size
- @r.n_prop_y_size = n_prop[0].size
- @r.y = acts
- @r.q_prop = q_prop
-
- begin
- LOGGER.debug "Preparing R data ..."
- # prepare data
- @r.eval "y<-matrix(y)"
- @r.eval "prop_matrix<-matrix(n_prop, n_prop_x_size, n_prop_y_size, byrow=TRUE)"
- @r.eval "q_prop<-matrix(q_prop, 1, n_prop_y_size, byrow=TRUE)"
-
- # model + support vectors
- LOGGER.debug "Creating SVM model ..."
- @r.eval "model<-ksvm(prop_matrix, y, type=\"#{type}\", nu=0.5)"
- LOGGER.debug "Predicting ..."
- if type == "nu-svr"
- @r.eval "p<-predict(model,q_prop)[1,1]"
- elsif type == "C-bsvc"
- @r.eval "p<-predict(model,q_prop)"
- end
- if type == "nu-svr"
- prediction = @r.p
- elsif type == "C-bsvc"
- prediction = (@r.p.to_f == 1.0 ? true : false)
- end
- @r.quit # free R
- rescue Exception => e
- LOGGER.debug "#{e.class}: #{e.message} #{e.backtrace}"
- end
- end
- prediction
- end
-
-
- end
-
- module Substructure
- include Algorithm
- # Substructure matching
- # @param [OpenTox::Compound] compound Compound
- # @param [Array] features Array with Smarts strings
- # @return [Array] Array with matching Smarts
- def self.match(compound,features)
- compound.match(features)
- end
- end
-
- module Dataset
- include Algorithm
- # API should match Substructure.match
- def features(dataset_uri,compound_uri)
- end
- end
-
- # Gauss kernel
- # @return [Float]
- def self.gauss(x, sigma = 0.3)
- d = 1.0 - x.to_f
- Math.exp(-(d*d)/(2*sigma*sigma))
- end
-
- # Median of an array
- # @param [Array] Array with values
- # @return [Float] Median
- def self.median(array)
- return nil if array.empty?
- array.sort!
- m_pos = array.size / 2
- return array.size % 2 == 1 ? array[m_pos] : (array[m_pos-1] + array[m_pos])/2
+ def run params=nil
+ post params, {:accept => 'text/uri-list'}
end
-=end
end
end
diff --git a/lib/authorization.rb b/lib/authorization.rb
index 27ae734..d447f88 100644
--- a/lib/authorization.rb
+++ b/lib/authorization.rb
@@ -2,52 +2,52 @@ module OpenTox
#Module for Authorization and Authentication
#@example Authentication
- # require "opentox-ruby"
+ # require "opentox-client"
# OpenTox::Authorization::AA_SERVER = "https://opensso.in-silico.ch" #if not set in .opentox/conf/[environment].yaml
- # token = OpenTox::Authorization.authenticate("benutzer", "passwort")
+ # token = OpenTox::Authorization.authenticate("benutzer", "passwort")
#@see http://www.opentox.org/dev/apis/api-1.2/AA OpenTox A&A API 1.2 specification
-
+
module Authorization
#Helper Class AA to create and send default policies out of xml templates
- #@example Creating a default policy to a URI
- # aa=OpenTox::Authorization::AA.new(tok)
+ #@example Creating a default policy to a URI
+ # aa=OpenTox::Authorization::AA.new(tok)
# xml=aa.get_xml('http://uri....')
- # OpenTox::Authorization.create_policy(xml,tok)
-
+ # OpenTox::Authorization.create_policy(xml,tok)
+
class AA
- attr_accessor :user, :subjectid, :policy
-
+ attr_accessor :user, :subjectid, :policy
+
#Generates AA object - requires subjectid
- # @param [String] subjectid
+ # @param [String] subjectid
def initialize(subjectid)
@user = Authorization.get_user(subjectid)
@subjectid = subjectid
@policy = Policies.new()
end
-
+
#Cleans AA Policies and loads default xml file into policy attribute
- #set uri and user, returns Policyfile(XML) for open-sso
+ #set uri and user, returns Policyfile(XML) for open-sso
# @param [String] URI to create a policy for
def get_xml(uri)
@policy.drop_policies
@policy.load_default_policy(@user, uri)
return @policy.to_xml
- end
-
+ end
+
#Loads and sends Policyfile(XML) to open-sso server
- # @param [String] URI to create a policy for
- def send(uri)
+ # @param [String] URI to create a policy for
+ def send(uri)
xml = get_xml(uri)
ret = false
- ret = Authorization.create_policy(xml, @subjectid)
+ ret = Authorization.create_policy(xml, @subjectid)
LOGGER.debug "Policy send with subjectid: #{@subjectid}"
LOGGER.warn "Not created Policy is: #{xml}" if !ret
- ret
+ ret
end
-
+
end
-
+
#Returns the open-sso server set in the config file .opentox/config/[environment].yaml
# @return [String, nil] the openSSO server URI or nil
def self.server
@@ -55,11 +55,11 @@ module OpenTox
end
#Authentication against OpenSSO. Returns token. Requires Username and Password.
- # @param [String, String]Username,Password
+ # @param [String, String]Username,Password
# @return [String, nil] gives subjectid or nil
def self.authenticate(user, pw)
return nil if !AA_SERVER
- begin
+ begin
resource = RestClient::Resource.new("#{AA_SERVER}/auth/authenticate")
out = resource.post(:username=>user, :password => pw).sub("token.id=","").sub("\n","")
return out
@@ -67,20 +67,20 @@ module OpenTox
return nil
end
end
-
+
#Logout on opensso. Make token invalid. Requires token
- # @param [String]subjectid the subjectid
+ # @param [String]subjectid the subjectid
# @return [Boolean] true if logout is OK
def self.logout(subjectid)
begin
resource = RestClient::Resource.new("#{AA_SERVER}/auth/logout")
resource.post(:subjectid => subjectid)
- return true
+ return true
rescue
return false
end
- end
-
+ end
+
#Authorization against OpenSSO for a URI with request-method (action) [GET/POST/PUT/DELETE]
# @param [String,String,String]uri,action,subjectid
# @return [Boolean, nil] returns true, false or nil (if authorization-request fails).
@@ -91,12 +91,12 @@ module OpenTox
return true if resource.post(:uri => uri, :action => action, :subjectid => subjectid) == "boolean=true\n"
rescue
return nil
- end
+ end
end
- #Checks if a token is a valid token
- # @param [String]subjectid subjectid from openSSO session
- # @return [Boolean] subjectid is valid or not.
+ #Checks if a token is a valid token
+ # @param [String]subjectid subjectid from openSSO session
+ # @return [Boolean] subjectid is valid or not.
def self.is_token_valid(subjectid)
return true if !AA_SERVER
begin
@@ -106,7 +106,7 @@ module OpenTox
return false
end
end
-
+
#Returns array with all policies of the token owner
# @param [String]subjectid requires subjectid
# @return [Array, nil] returns an Array of policy names or nil if request fails
@@ -116,15 +116,15 @@ module OpenTox
out = resource.get(:subjectid => subjectid)
return out.split("\n")
rescue RestClient::InternalServerError => e
- raise e.response
+ raise e.response
rescue
return nil
end
end
#Returns a policy in xml-format
- # @param [String, String]policy,subjectid
- # @return [String] XML of the policy
+ # @param [String, String]policy,subjectid
+ # @return [String] XML of the policy
def self.list_policy(policy, subjectid)
begin
resource = RestClient::Resource.new("#{AA_SERVER}/pol")
@@ -133,7 +133,7 @@ module OpenTox
return nil
end
end
-
+
# Lists policies alongside with affected uris
# @param [String] subjectid
# @return [Hash] keys: all policies of the subjectid owner, values: uris affected by those policies
@@ -154,7 +154,7 @@ module OpenTox
p.load_xml( list_policy(policy, subjectid) )
p.uris
end
-
+
#Returns the owner (who created the first policy) of an URI
# @param [String, String]uri,subjectid
# return [String, nil]owner,nil returns owner of the URI
@@ -164,39 +164,39 @@ module OpenTox
return resource.get(:uri => uri, :subjectid => subjectid).sub("\n","")
rescue
return nil
- end
- end
-
+ end
+ end
+
#Checks if a policy exists to a URI. Requires URI and token.
# @param [String, String]uri,subjectid
- # return [Boolean]
+ # return [Boolean]
def self.uri_has_policy(uri, subjectid)
owner = get_uri_owner(uri, subjectid)
return true if owner and owner != "null"
false
end
-
+
#List all policynames for a URI. Requires URI and token.
# @param [String, String]uri,subjectid
- # return [Array, nil] returns an Array of policy names or nil if request fails
+ # return [Array, nil] returns an Array of policy names or nil if request fails
def self.list_uri_policies(uri, subjectid)
begin
resource = RestClient::Resource.new("#{AA_SERVER}/pol")
- out = resource.get(:uri => uri, :polnames => true, :subjectid => subjectid)
+ out = resource.get(:uri => uri, :polnames => true, :subjectid => subjectid)
policies = []; notfirstline = false
out.split("\n").each do |line|
policies << line if notfirstline
- notfirstline = true
+ notfirstline = true
end
- return policies
+ return policies
rescue
return nil
- end
- end
+ end
+ end
#Sends a policy in xml-format to opensso server. Requires policy-xml and token.
# @param [String, String]policyxml,subjectid
- # return [Boolean] returns true if policy is created
+ # return [Boolean] returns true if policy is created
def self.create_policy(policy, subjectid)
begin
resource = RestClient::Resource.new("#{AA_SERVER}/Pol/opensso-pol")
@@ -206,7 +206,7 @@ module OpenTox
return false
end
end
-
+
#Deletes a policy
# @param [String, String]policyname,subjectid
# @return [Boolean,nil]
@@ -214,7 +214,7 @@ module OpenTox
begin
resource = RestClient::Resource.new("#{AA_SERVER}/pol")
LOGGER.debug "OpenTox::Authorization.delete_policy policy: #{policy} with token: #{subjectid}"
- return true if resource.delete(:subjectid => subjectid, :id => policy)
+ return true if resource.delete(:subjectid => subjectid, :id => policy)
rescue
return nil
end
@@ -222,7 +222,7 @@ module OpenTox
#Returns array of all possible LDAP-Groups
# @param [String]subjectid
- # @return [Array]
+ # @return [Array]
def self.list_groups(subjectid)
begin
resource = RestClient::Resource.new("#{AA_SERVER}/opensso/identity/search")
@@ -233,8 +233,8 @@ module OpenTox
rescue
[]
end
- end
-
+ end
+
#Returns array of the LDAP-Groups of an user
# @param [String]subjectid
# @return [Array] gives array of LDAP groups of a user
@@ -244,17 +244,17 @@ module OpenTox
out = resource.post(:name => user, :admin => subjectid, :attributes_names => "group")
grps = []
out.split("\n").each do |line|
- grps << line.sub("identitydetails.group=","") if line.include?("identitydetails.group=")
+ grps << line.sub("identitydetails.group=","") if line.include?("identitydetails.group=")
end
return grps
rescue
[]
end
- end
-
+ end
+
#Returns the owner (user id) of a token
# @param [String]subjectid
- # @return [String]user
+ # @return [String]user
def self.get_user(subjectid)
begin
resource = RestClient::Resource.new("#{AA_SERVER}/opensso/identity/attributes")
@@ -265,14 +265,14 @@ module OpenTox
user = line.sub("userdetails.attribute.value=","") if line.include?("userdetails.attribute.value=")
check = false
end
- check = true if line.include?("userdetails.attribute.name=uid")
+ check = true if line.include?("userdetails.attribute.name=uid")
end
return user
rescue
nil
end
end
-
+
#Send default policy with Authorization::AA class
# @param [String, String]URI,subjectid
def self.send_policy(uri, subjectid)
@@ -282,7 +282,7 @@ module OpenTox
LOGGER.debug "OpenTox::Authorization send policy for URI: #{uri} | subjectid: #{subjectid} - policy created: #{ret}"
ret
end
-
+
#Deletes all policies of an URI
# @param [String, String]URI,subjectid
# @return [Boolean]
@@ -303,20 +303,20 @@ module OpenTox
# @return [Boolean] true if policy checked/created successfully (or no uri/subjectid given), false else
def self.check_policy(uri, subjectid)
return true unless uri and subjectid
- token_valid = OpenTox::Authorization.is_token_valid(subjectid)
+ token_valid = OpenTox::Authorization.is_token_valid(subjectid)
LOGGER.debug "OpenTox::Authorization.check_policy with uri: #{uri}, subjectid: #{subjectid} is valid: #{token_valid}"
# check if subjectid is valid
unless token_valid
# abort if invalid
- LOGGER.error "OpenTox::Authorization.check_policy, subjectid NOT valid: #{subjectid}"
+ LOGGER.error "OpenTox::Authorization.check_policy, subjectid NOT valid: #{subjectid}"
return false
end
-
+
if !uri_has_policy(uri, subjectid)
# if no policy exists, create a policy, return result of send policy
send_policy(uri, subjectid)
else
- # if policy exists check for POST rights
+ # if policy exists check for POST rights
if authorize(uri, "POST", subjectid)
true
else
@@ -325,19 +325,19 @@ module OpenTox
end
end
true
- end
+ end
- class << self
+ class << self
alias :token_valid? :is_token_valid
end
- # Check Authorization for a resource (identified via URI) with method and subjectid.
+ # Check Authorization for a resource (identified via URI) with method and subjectid.
# @param [String] uri
# @param [String] request_method, should be GET, POST, PUT, DELETE
# @param [String] subjectid
# @return [Boolean] true if access granted, else otherwise
def self.authorized?(uri, request_method, subjectid)
- if CONFIG[:authorization][:free_request].include?(request_method)
+ if CONFIG[:authorization][:free_request].include?(request_method)
#LOGGER.debug "authorized? >>true<< (request is free), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}"
true
elsif OpenTox::Authorization.free_uri?(uri, request_method)
@@ -355,38 +355,38 @@ module OpenTox
ret = OpenTox::Authorization.authorize(uri, request_method, subjectid)
LOGGER.debug "authorized? >>#{ret}<< (uri (not) authorized), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}" unless ret
ret
- else
+ else
LOGGER.error "invalid request/uri method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}"
false
end
end
-
+
private
def self.free_uri?(uri, request_method)
if CONFIG[:authorization][:free_uris]
CONFIG[:authorization][:free_uris].each do |request_methods,uris|
- if request_methods and uris and request_methods.include?(request_method.to_sym)
+ if request_methods and uris and request_methods.include?(request_method.to_sym)
uris.each do |u|
return true if u.match uri
end
end
end
- end
+ end
return false
end
-
+
def self.authorize_exception?(uri, request_method)
if CONFIG[:authorization][:authorize_exceptions]
CONFIG[:authorization][:authorize_exceptions].each do |request_methods,uris|
- if request_methods and uris and request_methods.include?(request_method.to_sym)
+ if request_methods and uris and request_methods.include?(request_method.to_sym)
uris.each do |u|
return true if u.match uri
end
end
end
- end
+ end
return false
- end
-
+ end
+
end
end
diff --git a/lib/compound.rb b/lib/compound.rb
index 974e46e..8761d50 100644
--- a/lib/compound.rb
+++ b/lib/compound.rb
@@ -1,5 +1,4 @@
-@@cactus_uri="http://cactus.nci.nih.gov/chemical/structure/"
-@@ambit_uri="http://ambit.uni-plovdiv.bg:8080/ambit2/depict/cdk?search="
+CACTUS_URI="http://cactus.nci.nih.gov/chemical/structure/"
module OpenTox
@@ -12,21 +11,21 @@ module OpenTox
# @param [String] smiles Smiles string
# @return [OpenTox::Compound] Compound
def self.from_smiles service_uri, smiles, subjectid=nil
- Compound.new RestClientWrapper.post(service_uri, smiles, :content_type => 'chemical/x-daylight-smiles').to_s.chomp
+ Compound.new RestClient.post(service_uri, smiles, {:content_type => 'chemical/x-daylight-smiles', :subjectid => subjectid})
end
# Create a compound from inchi string
# @param [String] smiles InChI string
# @return [OpenTox::Compound] Compound
- def self.from_inchi(service_uri, inchi)
- Compound.new RestClientWrapper.post(service_uri, inchi, :content_type => 'chemical/x-inchi').to_s.chomp
+ def self.from_inchi service_uri, inchi, subjectid=nil
+ Compound.new RestClient.post(service_uri, inchi, {:content_type => 'chemical/x-inchi', :subjectid => subjectid})
end
# Create a compound from sdf string
# @param [String] smiles SDF string
# @return [OpenTox::Compound] Compound
- def self.from_sdf(service_uri, sdf)
- Compound.new RestClientWrapper.post(service_uri, sdf, :content_type => 'chemical/x-mdl-sdfile').to_s.chomp
+ def self.from_sdf service_uri, sdf, subjectid=nil
+ Compound.new RestClient.post(service_uri, sdf, {:content_type => 'chemical/x-mdl-sdfile', :subjectid => subjectid})
end
# Create a compound from name. Relies on an external service for name lookups.
@@ -34,34 +33,32 @@ module OpenTox
# compound = OpenTox::Compound.from_name("Benzene")
# @param [String] name name can be also an InChI/InChiKey, CAS number, etc
# @return [OpenTox::Compound] Compound
- def self.from_name(service_uri, name)
- # paranoid URI encoding to keep SMILES charges and brackets
- inchi = RestClientWrapper.get("#{@@cactus_uri}#{URI.encode(name, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))}/stdinchi").to_s.chomp
- Compound.new File.join(service_uri,URI.escape(inchi))
+ def self.from_name service_uri, name, subjectid=nil
+ Compound.new RestClient.post(service_uri, name, {:content_type => 'text/plain', :subjectid => subjectid})
end
# Get InChI
# @return [String] InChI string
def to_inchi
- RestClientWrapper.get(@uri, :accept => 'chemical/x-inchi').to_s.chomp if @uri
+ get(:accept => 'chemical/x-inchi').to_s.chomp if @uri
end
# Get (canonical) smiles
# @return [String] Smiles string
def to_smiles
- RestClientWrapper.get(@uri, :accept => 'chemical/x-daylight-smiles').chomp
+ get(:accept => 'chemical/x-daylight-smiles').chomp
end
# Get sdf
# @return [String] SDF string
def to_sdf
- RestClientWrapper.get(@uri, :accept => 'chemical/x-mdl-sdfile').chomp
+ get(:accept => 'chemical/x-mdl-sdfile').chomp
end
# Get gif image
# @return [image/gif] Image data
def to_gif
- RestClientWrapper.get("#{@@cactus_uri}#{@inchi}/image")
+ get("#{CACTUS_URI}#{to_inchi}/image")
end
# Get png image
@@ -69,7 +66,7 @@ module OpenTox
# image = compound.to_png
# @return [image/png] Image data
def to_png
- RestClientWrapper.get(File.join @uri, "image")
+ get(File.join @uri, "image")
end
# Get URI of compound image
@@ -84,7 +81,7 @@ module OpenTox
# @return [String] Compound names
def to_names
begin
- RestClientWrapper.get("#{@@cactus_uri}#{@inchi}/names").split("\n")
+ get("#{CACTUS_URI}#{to_inchi}/names").split("\n")
rescue
"not available"
end
diff --git a/lib/config/config_ru.rb b/lib/config/config_ru.rb
deleted file mode 100644
index dc04263..0000000
--- a/lib/config/config_ru.rb
+++ /dev/null
@@ -1,54 +0,0 @@
-require 'rubygems'
-require 'rack'
-require 'rack/contrib'
-require 'application.rb'
-
-# log at centralized place
-logfile = "#{LOG_DIR}/#{ENV["RACK_ENV"]}.log"
-log = File.new(logfile, "a+")
-$stdout.reopen(log)
-$stderr.reopen(log)
-$stdout.sync = true
-$stderr.sync = true
-set :logging, false
-set :raise_errors, true
-set :lock, true
-
-['public','tmp'].each do |dir|
- FileUtils.mkdir_p dir unless File.exists?(dir)
-end
-
-use Rack::ShowExceptions
-=begin
-if defined?(MAIL)
-
- # monkeypatch with the original method
- # strangely enough my mailserver returns "Connection refused - connect(2)" errors without this patch
- module Rack
- class MailExceptions
-
- def send_notification(exception, env)
- mail = generate_mail(exception, env)
- smtp = config[:smtp]
- env['mail.sent'] = true
- return if smtp[:server] == 'example.com'
-
- Net::SMTP.start smtp[:server], smtp[:port], smtp[:domain], smtp[:user_name], smtp[:password], smtp[:authentication] do |server|
- mail.to.each do |recipient|
- server.send_message mail.to_s, mail.from, recipient
- end
- end
- end
- end
- end
-
-
- require "socket"
- use Rack::MailExceptions do |mail|
- mail.to MAIL[:user_name]
- mail.subject '[ERROR] %s'
- mail.from "#{Socket.gethostname}@#{MAIL[:domain]}"
- mail.smtp MAIL
- end
-end
-=end
diff --git a/lib/dataset.rb b/lib/dataset.rb
index 84dce65..3de9d1f 100644
--- a/lib/dataset.rb
+++ b/lib/dataset.rb
@@ -4,9 +4,9 @@ module OpenTox
# TODO: fix API Doc
class Dataset
- include OpenTox
+ #include OpenTox
- attr_reader :features, :compounds, :data_entries, :metadata
+ #attr_reader :features, :compounds, :data_entries, :metadata
# Create dataset with optional URI. Does not load data into the dataset - you will need to execute one of the load_* methods to pull data from a service or to insert it from other representations.
# @example Create an empty dataset
@@ -22,78 +22,19 @@ module OpenTox
@data_entries = {}
end
- # Create an empty dataset and save it at the dataset service (assigns URI to dataset)
- # @example Create new dataset and save it to obtain a URI
- # dataset = OpenTox::Dataset.create
- # @param [optional, String] uri Dataset URI
- # @return [OpenTox::Dataset] Dataset object
- def self.create(uri=CONFIG[:services]["opentox-dataset"], subjectid=nil)
- dataset = Dataset.new(nil,subjectid)
- dataset.save
- dataset
- end
-
- # Find a dataset and load all data. This can be time consuming, use Dataset.new together with one of the load_* methods for a fine grained control over data loading.
- # @param [String] uri Dataset URI
- # @return [OpenTox::Dataset] Dataset object with all data
- def self.find(uri, subjectid=nil)
- return nil unless uri
- dataset = Dataset.new(uri, subjectid)
- dataset.load_metadata
- dataset
- end
-
- # Create dataset from CSV file (format specification: http://toxcreate.org/help)
- # - loads data_entries, compounds, features
- # - sets metadata (warnings) for parser errors
- # - you will have to set remaining metadata manually
- # @param [String] file CSV file path
- # @return [OpenTox::Dataset] Dataset object with CSV data
- def self.create_from_csv_file(file, subjectid=nil)
- dataset = Dataset.create(CONFIG[:services]["opentox-dataset"], subjectid)
- #RestClientWrapper.post(dataset.uri,File.read(file), {:content_type => "text/csv", :subjectid => @subjectid})
- RestClientWrapper.post(dataset.uri,{:file => File.new(file)},{:accept => "text/uri-list", :subjectid => subjectid})#, {:content_type => "text/csv", :subjectid => @subjectid})
- dataset.load_metadata
- dataset
- end
-
- # replaces find as exist check, takes not as long, does NOT raise an un-authorized exception
- # @param [String] uri Dataset URI
- # @return [Boolean] true if dataset exists and user has get rights, false else
- def self.exist?(uri, subjectid=nil)
- return false unless uri
- dataset = Dataset.new(uri, subjectid)
- begin
- dataset.load_metadata.size > 0
- rescue
- false
- end
- end
-
- # Get all datasets from a service
- # @param [optional,String] uri URI of the dataset service, defaults to service specified in configuration
- # @return [Array] Array of dataset object without data (use one of the load_* methods to pull data from the server)
- def self.all(uri=CONFIG[:services]["opentox-dataset"], subjectid=nil)
- RestClientWrapper.get(uri,{:accept => "text/uri-list",:subjectid => subjectid}).to_s.each_line.collect{|u| Dataset.new(u.chomp, subjectid)}
- end
-
+=begin
# Load YAML representation into the dataset
# @param [String] yaml YAML representation of the dataset
# @return [OpenTox::Dataset] Dataset object with YAML data
- def store_yaml(yaml)
- RestClientWrapper.post(@uri,yaml, {:content_type => "application/x-yaml", :subjectid => @subjectid})
- end
-
- def store_rdfxml(rdfxml)
- RestClientWrapper.post(@uri, rdfxml, {:content_type => "application/rdf+xml", :subjectid => @subjectid})
+ def self.from_yaml service_uri, yaml, subjectid=nil
+ Dataset.create(service_uri, subjectid).post yaml, :content_type => "application/x-yaml"
end
# Load RDF/XML representation from a file
# @param [String] file File with RDF/XML representation of the dataset
# @return [OpenTox::Dataset] Dataset object with RDF/XML data
- def store_rdfxml_file(file)
- #RestClientWrapper.post(@uri, :file => File.new(file))#, {:content_type => "application/rdf+xml", :subjectid => @subjectid})
- RestClientWrapper.post(@uri, File.read(file), {:content_type => "application/rdf+xml", :subjectid => @subjectid})
+ def self.from_rdfxml service_uri, rdfxml, subjectid=nil
+ Dataset.create(service_uri, subjectid).post rdfxml, :content_type => "application/rdf+xml"
end
# Load CSV string (format specification: http://toxcreate.org/help)
@@ -102,8 +43,8 @@ module OpenTox
# - you will have to set remaining metadata manually
# @param [String] csv CSV representation of the dataset
# @return [OpenTox::Dataset] Dataset object with CSV data
- def store_csv(csv)
- RestClientWrapper.post(@uri, csv, {:content_type => "text/csv", :subjectid => @subjectid})
+ def self.from_csv service_uri, csv, subjectid=nil
+ Dataset.from_file(service_uri, csv, subjectid)
end
# Load Spreadsheet book (created with roo gem http://roo.rubyforge.org/, excel format specification: http://toxcreate.org/help)
@@ -112,53 +53,101 @@ module OpenTox
# - you will have to set remaining metadata manually
# @param [Excel] book Excel workbook object (created with roo gem)
# @return [OpenTox::Dataset] Dataset object with Excel data
- def store_spreadsheet_file(file)
- RestClientWrapper.post(@uri, :file => File.new(file))#, {:content_type => "application/vnd.ms-excel", :subjectid => @subjectid})
+ def self.from_xls service_uri, xls, subjectid=nil
+ Dataset.create(service_uri, subjectid).post xls, :content_type => "application/vnd.ms-excel"
end
- # Load and return only metadata of a Dataset object
- # @return [Hash] Metadata of the dataset
- def load_metadata
- if (CONFIG[:yaml_hosts].include?(URI.parse(@uri).host))
- @metadata = YAML.load(RestClientWrapper.get(File.join(@uri,"metadata"), {:accept => "application/x-yaml", :subjectid => @subjectid}))
- else
- add_metadata Parser::Owl::Dataset.new(@uri, @subjectid).load_metadata
- end
- self.uri = @uri if @uri # keep uri
- @metadata
+ def self.from_sdf service_uri, sdf, subjectid=nil
+ Dataset.create(service_uri, subjectid).post sdf, :content_type => 'chemical/x-mdl-sdfile'
end
+=end
# Load all data (metadata, data_entries, compounds and features) from URI
- def load_all
- if (CONFIG[:yaml_hosts].include?(URI.parse(@uri).host))
- copy YAML.load(RestClientWrapper.get(@uri, {:accept => "application/x-yaml", :subjectid => @subjectid}))
- else
- parser = Parser::Owl::Dataset.new(@uri, @subjectid)
- copy parser.load_uri
+ # TODO: move to opentox-server
+ def data_entries reload=true
+ if reload
+ file = Tempfile.new("ot-rdfxml")
+ file.puts get :accept => "application/rdf+xml"
+ file.close
+ to_delete = file.path
+
+ data = {}
+ feature_values = {}
+ feature = {}
+ feature_accept_values = {}
+ other_statements = {}
+ `rapper -i rdfxml -o ntriples #{file.path} 2>/dev/null`.each_line do |line|
+ triple = line.chomp.split(' ',3)
+ triple = triple[0..2].collect{|i| i.sub(/\s+.$/,'').gsub(/[<>"]/,'')}
+ case triple[1]
+ when /#{RDF::OT.values}|#{RDF::OT1.values}/i
+ data[triple[0]] = {:compound => "", :values => []} unless data[triple[0]]
+ data[triple[0]][:values] << triple[2]
+ when /#{RDF::OT.value}|#{RDF::OT1.value}/i
+ feature_values[triple[0]] = triple[2]
+ when /#{RDF::OT.compound}|#{RDF::OT1.compound}/i
+ data[triple[0]] = {:compound => "", :values => []} unless data[triple[0]]
+ data[triple[0]][:compound] = triple[2]
+ when /#{RDF::OT.feature}|#{RDF::OT1.feature}/i
+ feature[triple[0]] = triple[2]
+ when /#{RDF.type}/i
+ if triple[2]=~/#{RDF::OT.Compound}|#{RDF::OT1.Compound}/i and !data[triple[0]]
+ data[triple[0]] = {:compound => triple[0], :values => []}
+ end
+ when /#{RDF::OT.acceptValue}|#{RDF::OT1.acceptValue}/i # acceptValue in ambit datasets is only provided in dataset/ no in dataset//features
+ feature_accept_values[triple[0]] = [] unless feature_accept_values[triple[0]]
+ feature_accept_values[triple[0]] << triple[2]
+ else
+ end
+ end
+ File.delete(to_delete) if to_delete
+ data.each do |id,entry|
+ if entry[:values].size==0
+ # no feature values add plain compounds
+ @compounds << entry[:compound] unless @compounds.include? entry[:compound]
+ else
+ entry[:values].each do |value_id|
+ if feature_values[value_id]
+ split = feature_values[value_id].split(/\^\^/)
+ case split[-1]
+ when RDF::XSD.double, RDF::XSD.float
+ value = split.first.to_f
+ when RDF::XSD.boolean
+ value = split.first=~/(?i)true/ ? true : false
+ else
+ value = split.first
+ end
+ end
+ @compounds << entry[:compound] unless @compounds.include? entry[:compound]
+ @features[feature[value_id][value_id]] = {} unless @features[feature[value_id]]
+ @data_entries[entry[:compound].to_s] = {} unless @data_entries[entry[:compound].to_s]
+ @data_entries[entry[:compound].to_s][feature[value_id]] = [] unless @data_entries[entry[:compound]][feature[value_id]]
+ @data_entries[entry[:compound].to_s][feature[value_id]] << value if value!=nil
+ end
+ end
+ end
+ features subjectid
+ #feature_accept_values.each do |feature, values|
+ #self.features[feature][OT.acceptValue] = values
+ #end
+ self.metadata = metadata(subjectid)
end
+ @data_entries
end
# Load and return only compound URIs from the dataset service
# @return [Array] Compound URIs in the dataset
- def load_compounds
- RestClientWrapper.get(File.join(uri,"compounds"),{:accept=> "text/uri-list", :subjectid => @subjectid}).to_s.each_line do |compound_uri|
- @compounds << compound_uri.chomp
- end
- @compounds.uniq!
+ def compounds reload=true
+ reload ? @compounds = Compound.all(File.join(@uri,"compounds")) : @compounds
end
# Load and return only features from the dataset service
# @return [Hash] Features of the dataset
- def load_features
- if (CONFIG[:yaml_hosts].include?(URI.parse(@uri).host))
- @features = YAML.load(RestClientWrapper.get(File.join(@uri,"features"), {:accept => "application/x-yaml", :subjectid => @subjectid}))
- else
- parser = Parser::Owl::Dataset.new(@uri, @subjectid)
- @features = parser.load_features
- end
- @features
+ def features reload=true
+ reload ? @features = Feature.all(File.join(@uri,"features")) : @features
end
+=begin
# returns the accept_values of a feature, i.e. the classification domain / all possible feature values
# @param [String] feature the URI of the feature
# @return [Array] return array with strings, nil if value is not set (e.g. when feature is numeric)
@@ -182,48 +171,46 @@ module OpenTox
"unknown"
end
end
-
- # Get Spreadsheet representation
- # @return [Spreadsheet::Workbook] Workbook which can be written with the spreadsheet gem (data_entries only, metadata will will be discarded))
- def to_spreadsheet
- Spreadsheet::Workbook.new(RestClientWrapper.get(@uri, {:accept => "application/vnd.ms-excel", :subjectid => @subjectid}))
- end
+=end
# Get Excel representation (alias for to_spreadsheet)
# @return [Spreadsheet::Workbook] Workbook which can be written with the spreadsheet gem (data_entries only, metadata will will be discarded))
def to_xls
- to_spreadsheet
+ get :accept => "application/vnd.ms-excel"
end
# Get CSV string representation (data_entries only, metadata will be discarded)
# @return [String] CSV representation
def to_csv
- RestClientWrapper.get(@uri, {:accept => "text/csv", :subjectid => @subjectid})
+ get :accept => "text/csv"
+ end
+
+ def to_sdf
+ get :accept => 'chemical/x-mdl-sdfile'
end
+
# Get OWL-DL in ntriples format
# @return [String] N-Triples representation
def to_ntriples
- RestClientWrapper.get(@uri, {:accept => "application/rdf+xml", :subjectid => @subjectid})
+ get :accept => "application/rdf+xml"
end
# Get OWL-DL in RDF/XML format
# @return [String] RDF/XML representation
def to_rdfxml
- RestClientWrapper.get(@uri, {:accept => "application/rdf+xml", :subjectid => @subjectid})
+ get :accept => "application/rdf+xml"
end
# Get name (DC.title) of a feature
# @param [String] feature Feature URI
# @return [String] Feture title
def feature_name(feature)
- load_features
- @features[feature][DC.title]
+ features[feature][DC.title]
end
def title
- load_metadata
- @metadata[DC.title]
+ metadata[DC.title]
end
# Insert a statement (compound_uri,feature_uri,value)
@@ -314,11 +301,6 @@ module OpenTox
@uri
end
- # Delete dataset at the dataset service
- def delete
- RestClientWrapper.delete(@uri, :subjectid => @subjectid)
- end
-
private
# Copy a dataset (rewrites URI)
def copy(dataset)
@@ -333,39 +315,4 @@ module OpenTox
end
end
end
-
- # Class with special methods for lazar prediction datasets
- class LazarPrediction < Dataset
-
- # Find a prediction dataset and load all data.
- # @param [String] uri Prediction dataset URI
- # @return [OpenTox::Dataset] Prediction dataset object with all data
- def self.find(uri, subjectid=nil)
- prediction = LazarPrediction.new(uri, subjectid)
- prediction.load_all
- prediction
- end
-
- def value(compound)
- @data_entries[compound.uri].collect{|f,v| v.first if f.match(/value/)}.compact.first
- end
-
- def confidence(compound)
- @data_entries[compound.uri].collect{|f,v| v.first if f.match(/confidence/)}.compact.first
- end
-
- def descriptors(compound)
- @data_entries[compound.uri].collect{|f,v| @features[f] if f.match(/descriptor/)}.compact if @data_entries[compound.uri]
- end
-
- def measured_activities(compound)
- source = @metadata[OT.hasSource]
- @data_entries[compound.uri].collect{|f,v| v if f.match(/#{source}/)}.compact.flatten
- end
-
- def neighbors(compound)
- @data_entries[compound.uri].collect{|f,v| @features[f] if f.match(/neighbor/)}.compact
- end
-
- end
end
diff --git a/lib/environment.rb b/lib/environment.rb
deleted file mode 100644
index cae743c..0000000
--- a/lib/environment.rb
+++ /dev/null
@@ -1,83 +0,0 @@
-# set default environment
-ENV['RACK_ENV'] = 'production' unless ENV['RACK_ENV']
-
-# load/setup configuration
-basedir = File.join(ENV['HOME'], ".opentox")
-config_dir = File.join(basedir, "config")
-config_file = File.join(config_dir, "#{ENV['RACK_ENV']}.yaml")
-user_file = File.join(config_dir, "users.yaml")
-
-TMP_DIR = File.join(basedir, "tmp")
-LOG_DIR = File.join(basedir, "log")
-
-if File.exist?(config_file)
- CONFIG = YAML.load_file(config_file)
- raise "could not load config, config file: "+config_file.to_s unless CONFIG
-else
- FileUtils.mkdir_p TMP_DIR
- FileUtils.mkdir_p LOG_DIR
- FileUtils.mkdir_p config_dir
- FileUtils.cp(File.join(File.dirname(__FILE__), 'templates/config.yaml'), config_file)
- puts "Please edit #{config_file} and restart your application."
- exit
-end
-
-# database
-#`redis-server /opt/redis/redis.conf` unless File.exists? "/var/run/redis.pid" # removed by AM
-# Ohm.connect :thread_safe => true
-
-# load mail settings for error messages
-#load File.join config_dir,"mail.rb" if File.exists?(File.join config_dir,"mail.rb")
-
-logfile = "#{LOG_DIR}/#{ENV["RACK_ENV"]}.log"
-#LOGGER = OTLogger.new(logfile,'daily') # daily rotation
-LOGGER = OTLogger.new(logfile) # no rotation
-LOGGER.formatter = Logger::Formatter.new #this is neccessary to restore the formating in case active-record is loaded
-if CONFIG[:logger] and CONFIG[:logger] == "debug"
- LOGGER.level = Logger::DEBUG
-else
- LOGGER.level = Logger::WARN
-end
-
-# Regular expressions for parsing classification data
-TRUE_REGEXP = /^(true|active|1|1.0|tox)$/i
-FALSE_REGEXP = /^(false|inactive|0|0.0|low tox)$/i
-
-# Task durations
-DEFAULT_TASK_MAX_DURATION = 36000
-#EXTERNAL_TASK_MAX_DURATION = 36000
-
-# OWL Namespaces
-class OwlNamespace
-
- attr_accessor :uri
- def initialize(uri)
- @uri = uri
- end
-
- def [](property)
- @uri+property.to_s
- end
-
- def type # for RDF.type
- "#{@uri}type"
- end
-
- def method_missing(property)
- @uri+property.to_s
- end
-
-end
-
-RDF = OwlNamespace.new 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'
-OWL = OwlNamespace.new 'http://www.w3.org/2002/07/owl#'
-DC = OwlNamespace.new 'http://purl.org/dc/elements/1.1/'
-OT = OwlNamespace.new 'http://www.opentox.org/api/1.1#'
-OTA = OwlNamespace.new 'http://www.opentox.org/algorithmTypes.owl#'
-XSD = OwlNamespace.new 'http://www.w3.org/2001/XMLSchema#'
-
-AA_SERVER = CONFIG[:authorization] ? (CONFIG[:authorization][:server] ? CONFIG[:authorization][:server] : nil) : nil
-CONFIG[:authorization][:authenticate_request] = [""] unless CONFIG[:authorization][:authenticate_request]
-CONFIG[:authorization][:authorize_request] = [""] unless CONFIG[:authorization][:authorize_request]
-CONFIG[:authorization][:free_request] = [""] unless CONFIG[:authorization][:free_request]
-
diff --git a/lib/error.rb b/lib/error.rb
deleted file mode 100644
index 45b7545..0000000
--- a/lib/error.rb
+++ /dev/null
@@ -1,98 +0,0 @@
-# adding additional fields to Exception class to format errors according to OT-API
-class Exception
- attr_accessor :errorCause
- def http_code; 500; end
-end
-
-module OpenTox
-
- class BadRequestError < RuntimeError
- def http_code; 400; end
- end
-
- class NotAuthorizedError < RuntimeError
- def http_code; 401; end
- end
-
- class NotFoundError < RuntimeError
- def http_code; 404; end
- end
-
- class ServiceUnavailableError < RuntimeError
- def http_code; 503; end
- end
-
- class RestCallError < RuntimeError
- attr_accessor :rest_params
- def http_code; 502; end
- end
-
- class ErrorReport
-
- # TODO replace params with URIs (errorCause -> OT.errorCause)
- attr_reader :message, :actor, :errorCause, :http_code, :errorDetails, :errorType
-
- private
- def initialize( http_code, erroType, message, actor, errorCause, rest_params=nil, backtrace=nil )
- @http_code = http_code
- @errorType = erroType
- @message = message
- @actor = actor
- @errorCause = errorCause
- @rest_params = rest_params
- @backtrace = backtrace
- end
-
- public
- # creates a error report object, from an ruby-exception object
- # @param [Exception] error
- # @param [String] actor, URI of the call that cause the error
- def self.create( error, actor )
- rest_params = error.rest_params if error.is_a?(OpenTox::RestCallError) and error.rest_params
- backtrace = error.backtrace.short_backtrace if CONFIG[:backtrace]
- ErrorReport.new( error.http_code, error.class.to_s, error.message, actor, error.errorCause, rest_params, backtrace )
- end
-
- def self.from_rdf(rdf)
- metadata = OpenTox::Parser::Owl.from_rdf( rdf, OT.ErrorReport ).metadata
- ErrorReport.new(metadata[OT.statusCode], metadata[OT.errorCode], metadata[OT.message], metadata[OT.actor], metadata[OT.errorCause])
- end
-
- # overwrite sorting to make easier readable
- def to_yaml_properties
- p = super
- p = ( p - ["@backtrace"]) + ["@backtrace"] if @backtrace
- p = ( p - ["@errorCause"]) + ["@errorCause"] if @errorCause
- p
- end
-
- def rdf_content()
- c = {
- RDF.type => [OT.ErrorReport],
- OT.statusCode => @http_code,
- OT.message => @message,
- OT.actor => @actor,
- OT.errorCode => @errorType,
- }
- c[OT.errorCause] = @errorCause.rdf_content if @errorCause
- c
- end
-
- def to_rdfxml
- s = Serializer::Owl.new
- s.add_resource(CONFIG[:services]["opentox-task"]+"/tmpId/ErrorReport/tmpId", OT.errorReport, rdf_content)
- s.to_rdfxml
- end
- end
-end
-
-class Array
- def short_backtrace
- short = []
- each do |c|
- break if c =~ /sinatra\/base/
- short << c
- end
- short.join("\n")
- end
-end
diff --git a/lib/feature.rb b/lib/feature.rb
deleted file mode 100644
index 84a85b9..0000000
--- a/lib/feature.rb
+++ /dev/null
@@ -1,44 +0,0 @@
-module OpenTox
- class Feature
- include OpenTox
-
- attr_accessor :subjectid
-
- # Find a feature
- # @param [String] uri Feature URI
- # @return [OpenTox::Feature] Feature object
- def self.find(uri, subjectid=nil)
- return nil unless uri
- feature = Feature.new uri, subjectid
- if (CONFIG[:yaml_hosts].include?(URI.parse(uri).host))
- feature.add_metadata YAML.load(RestClientWrapper.get(uri,{:accept => "application/x-yaml", :subjectid => @subjectid}))
- else
- feature.add_metadata Parser::Owl::Dataset.new(uri).load_metadata
- end
- feature.subjectid = subjectid
- feature
- end
-
- # provides feature type, possible types are "regression" or "classification"
- # @return [String] feature type, unknown if OT.isA property is unknown/ not set
- def feature_type
- if metadata[RDF.type].flatten.include?(OT.NominalFeature)
- "classification"
- elsif metadata[RDF.type].flatten.include?(OT.NumericFeature)
- "regression"
- elsif metadata[OWL.sameAs]
- metadata[OWL.sameAs].each do |f|
- begin
- type = Feature.find(f, subjectid).feature_type
- return type unless type=="unknown"
- rescue => ex
- LOGGER.warn "could not load same-as-feature '"+f.to_s+"' for feature '"+uri.to_s+"' : "+ex.message.to_s
- end
- end
- "unknown"
- else
- "unknown"
- end
- end
- end
-end
diff --git a/lib/helper.rb b/lib/helper.rb
deleted file mode 100644
index 04300e0..0000000
--- a/lib/helper.rb
+++ /dev/null
@@ -1,98 +0,0 @@
-=begin
-helpers do
-
- # Authentification
- def protected!(subjectid)
- if env["session"]
- unless authorized?(subjectid)
- flash[:notice] = "You don't have access to this section: "
- redirect back
- end
- elsif !env["session"] && subjectid
- unless authorized?(subjectid)
- LOGGER.debug "URI not authorized: clean: " + clean_uri("#{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}#{request.env['REQUEST_URI']}").to_s + " full: #{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}#{request.env['REQUEST_URI']} with request: #{request.env['REQUEST_METHOD']}"
- raise OpenTox::NotAuthorizedError.new "Not authorized"
- end
- else
- raise OpenTox::NotAuthorizedError.new "Not authorized" unless authorized?(subjectid)
- end
- end
-
- #Check Authorization for URI with method and subjectid.
- def authorized?(subjectid)
- request_method = request.env['REQUEST_METHOD']
- uri = clean_uri("#{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}#{request.env['REQUEST_URI']}")
- request_method = "GET" if request_method == "POST" && uri =~ /\/model\/\d+\/?$/
- return OpenTox::Authorization.authorized?(uri, request_method, subjectid)
- end
-
- #cleans URI from querystring and file-extension. Sets port 80 to emptystring
- # @param [String] uri
- def clean_uri(uri)
- uri = uri.sub(" ", "%20") #dirty hacks => to fix
- uri = uri[0,uri.index("InChI=")] if uri.index("InChI=")
-
- out = URI.parse(uri)
- out.path = out.path[0, out.path.length - (out.path.reverse.rindex(/\/{1}\d+\/{1}/))] if out.path.index(/\/{1}\d+\/{1}/) #cuts after /id/ for a&a
- port = (out.scheme=="http" && out.port==80)||(out.scheme=="https" && out.port==443) ? "" : ":#{out.port.to_s}"
- "#{out.scheme}://#{out.host}#{port}#{out.path.chomp("/")}" #"
- end
-
- #unprotected uri for login
- def login_requests
- return env['REQUEST_URI'] =~ /\/login$/
- end
-
- def uri_available?(urlStr)
- url = URI.parse(urlStr)
- subjectidstr = @subjectid ? "?subjectid=#{CGI.escape @subjectid}" : ""
- Net::HTTP.start(url.host, url.port) do |http|
- return http.head("#{url.request_uri}#{subjectidstr}").code == "200"
- end
- end
-
- def get_subjectid
- begin
- subjectid = nil
- subjectid = session[:subjectid] if session[:subjectid]
- subjectid = params[:subjectid] if params[:subjectid] and !subjectid
- subjectid = request.env['HTTP_SUBJECTID'] if request.env['HTTP_SUBJECTID'] and !subjectid
- subjectid = request.cookies["subjectid"] unless subjectid
- # see http://rack.rubyforge.org/doc/SPEC.html
- subjectid = CGI.unescape(subjectid) if subjectid.include?("%23")
- @subjectid = subjectid
- rescue
- subjectid = nil
- end
- end
- def get_extension
- extension = File.extname(request.path_info)
- unless extension.empty?
- case extension.gsub(".","")
- when "html"
- @accept = 'text/html'
- when "yaml"
- @accept = 'application/x-yaml'
- when "csv"
- @accept = 'text/csv'
- when "rdfxml"
- @accept = 'application/rdf+xml'
- when "xls"
- @accept = 'application/ms-excel'
- when "css"
- @accept = 'text/css'
- else
- # halt 404, "File format #{extension} not supported."
- end
- end
- end
-end
-
-before do
- @subjectid = get_subjectid()
- @accept = get_extension()
- unless !AA_SERVER or login_requests or CONFIG[:authorization][:free_request].include?(env['REQUEST_METHOD'])
- protected!(@subjectid)
- end
-end
-=end
diff --git a/lib/model.rb b/lib/model.rb
index a806b74..95aa9ff 100644
--- a/lib/model.rb
+++ b/lib/model.rb
@@ -1,488 +1,14 @@
module OpenTox
- module Model
-
- include OpenTox
-
- # Find a lazar model
- # @param [String] uri Model URI
- # @return [OpenTox::Model::Lazar] lazar model
- def self.find(uri, subjectid=nil)
- if CONFIG[:yaml_hosts].include?(URI.parse(uri).host)
- YAML.load RestClientWrapper.get(uri,{:accept => 'application/x-yaml', :subjectid => subjectid})
- else
- parser = Parser::Owl::Feature.new(uri, @subjectid)
- @metadata = parser.load_uri.metadata
- end
- end
-
- # Get URIs of all models
- # @return [Array] List of lazar model URIs
- def self.all(subjectid=nil)
- RestClientWrapper.get(CONFIG[:services]["opentox-model"], :subjectid => subjectid).to_s.split("\n")
- end
+ class Model
# Run a model with parameters
# @param [Hash] params Parameters for OpenTox model
# @param [optional,OpenTox::Task] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
# @return [text/uri-list] Task or resource URI
- def run( params, accept_header=nil, waiting_task=nil )
- unless accept_header
- if CONFIG[:yaml_hosts].include?(URI.parse(@uri).host)
- accept_header = 'application/x-yaml'
- else
- accept_header = 'application/rdf+xml'
- end
- end
- LOGGER.info "running model "+@uri.to_s+", params: "+params.inspect+", accept: "+accept_header.to_s
- RestClientWrapper.post(@uri,params,{:accept => accept_header},waiting_task).to_s
- end
-
- # Generic OpenTox model class for all API compliant services
- class Generic
- include Model
-
- # Find Generic Opentox Model via URI, and loads metadata, could raise NotFound/NotAuthorized error
- # @param [String] uri Model URI
- # @return [OpenTox::Model::Generic] Model instance
- def self.find(uri,subjectid=nil)
- return nil unless uri
- model = Generic.new(uri,subjectid)
- model.load_metadata
- raise "could not load model metadata '"+uri.to_s+"'" if model.metadata==nil or model.metadata.size==0
- model
- end
-
- # provides feature type, possible types are "regression" or "classification"
- # @return [String] feature type, "unknown" if type could not be estimated
- def feature_type
- unless @feature_type
- load_predicted_variables unless @predicted_variable
- @feature_type = OpenTox::Feature.find( @predicted_variable, @subjectid ).feature_type
- end
- @feature_type
- end
-
- def predicted_variable
- load_predicted_variables unless @predicted_variable
- @predicted_variable
- end
-
- def predicted_confidence
- load_predicted_variables unless @predicted_confidence
- @predicted_confidence
- end
-
- private
- def load_predicted_variables
- load_metadata if @metadata==nil or @metadata.size==0 or (@metadata.size==1 && @metadata.values[0]==@uri)
- if @metadata[OT.predictedVariables]
- predictedVariables = @metadata[OT.predictedVariables]
- if predictedVariables.is_a?(Array)
- if (predictedVariables.size==1)
- @predicted_variable = predictedVariables[0]
- elsif (predictedVariables.size==2)
- # PENDING identify confidence
- conf_index = -1
- predictedVariables.size.times do |i|
- f = OpenTox::Feature.find(predictedVariables[i])
- conf_index = i if f.metadata[DC.title]=~/(?i)confidence/
- end
- raise "could not estimate predicted variable from model: '"+uri.to_s+
- "', number of predicted-variables==2, but no confidence found" if conf_index==-1
- @predicted_variable = predictedVariables[1-conf_index]
- @predicted_confidence = predictedVariables[conf_index]
- else
- raise "could not estimate predicted variable from model: '"+uri.to_s+"', number of predicted-variables > 2"
- end
- else
- raise "could not estimate predicted variable from model: '"+uri.to_s+"', predicted-variables is no array"
- end
- end
- raise "could not estimate predicted variable from model: '"+uri.to_s+"'" unless @predicted_variable
- end
+ def run params=nil
+ post params, {:accept => 'text/uri-list'}
end
- # Lazy Structure Activity Relationship class
- class Lazar < Generic
-
- #include Model
- include Algorithm
-
- attr_accessor :compound, :prediction_dataset, :features, :effects, :activities, :p_values, :fingerprints, :feature_calculation_algorithm, :similarity_algorithm, :prediction_algorithm, :min_sim, :subjectid, :prop_kernel, :value_map
-
- def initialize(uri=nil,subjectid=nil)
-
- if uri
- super uri
- else
- super CONFIG[:services]["opentox-model"]
- end
-
- @metadata[OT.algorithm] = File.join(CONFIG[:services]["opentox-algorithm"],"lazar")
-
- @features = []
- @effects = {}
- @activities = {}
- @p_values = {}
- @fingerprints = {}
- @value_map = {}
-
- @feature_calculation_algorithm = "Substructure.match"
- @similarity_algorithm = "Similarity.tanimoto"
- @prediction_algorithm = "Neighbors.weighted_majority_vote"
-
- @min_sim = 0.3
- @prop_kernel = false
-
- end
-
- # Find a lazar model via URI, and loads metadata, could raise NotFound/NotAuthorized error
- # @param [String] uri Model URI
- # @return [OpenTox::Model::Generic] Model instance
- def self.find(uri,subjectid=nil)
- return nil unless uri
- model = Lazar.new(uri,subjectid)
- model.load_metadata
- raise "could not load model metadata '"+uri.to_s+"'" if model.metadata==nil or model.metadata.size==0
- model
- end
-
- # Create a new lazar model
- # @param [optional,Hash] params Parameters for the lazar algorithm (OpenTox::Algorithm::Lazar)
- # @return [OpenTox::Model::Lazar] lazar model
- def self.create(params)
- subjectid = params[:subjectid]
- lazar_algorithm = OpenTox::Algorithm::Generic.new File.join( CONFIG[:services]["opentox-algorithm"],"lazar")
- model_uri = lazar_algorithm.run(params)
- OpenTox::Model::Lazar.find(model_uri, subjectid)
- end
-
-=begin
- # Get a parameter value
- # @param [String] param Parameter name
- # @return [String] Parameter value
- def parameter(param)
- @metadata[OT.parameters].collect{|p| p[OT.paramValue] if p[DC.title] == param}.compact.first
- end
-
- # Predict a dataset
- # @param [String] dataset_uri Dataset URI
- # @param [optional,subjectid]
- # @param [optional,OpenTox::Task] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
- # @return [OpenTox::Dataset] Dataset with predictions
- def predict_dataset(dataset_uri, subjectid=nil, waiting_task=nil)
- @prediction_dataset = Dataset.create(CONFIG[:services]["opentox-dataset"], subjectid)
- @prediction_dataset.add_metadata({
- OT.hasSource => @uri,
- DC.creator => @uri,
- DC.title => URI.decode(File.basename( @metadata[OT.dependentVariables] )),
- OT.parameters => [{DC.title => "dataset_uri", OT.paramValue => dataset_uri}]
- })
- d = Dataset.new(dataset_uri,subjectid)
- d.load_compounds(subjectid)
- count = 0
- d.compounds.each do |compound_uri|
- begin
- predict(compound_uri,false,subjectid)
- count += 1
- waiting_task.progress( count/d.compounds.size.to_f*100.0 ) if waiting_task
- rescue => ex
- LOGGER.warn "prediction for compound "+compound_uri.to_s+" failed: "+ex.message
- end
- end
- @prediction_dataset.save(subjectid)
- @prediction_dataset
- end
-
- # Predict a compound
- # @param [String] compound_uri Compound URI
- # @param [optinal,Boolean] verbose Verbose prediction (output includes neighbors and features)
- # @return [OpenTox::Dataset] Dataset with prediction
- def predict(compound_uri,verbose=false,subjectid=nil)
-
- @compound = Compound.new compound_uri
- features = {}
-
- unless @prediction_dataset
- @prediction_dataset = Dataset.create(CONFIG[:services]["opentox-dataset"], subjectid)
- @prediction_dataset.add_metadata( {
- OT.hasSource => @uri,
- DC.creator => @uri,
- DC.title => URI.decode(File.basename( @metadata[OT.dependentVariables] )),
- OT.parameters => [{DC.title => "compound_uri", OT.paramValue => compound_uri}]
- } )
- end
-
- return @prediction_dataset if database_activity(subjectid)
-
- load_metadata(subjectid)
- case OpenTox::Feature.find(metadata[OT.dependentVariables]).feature_type
- when "classification"
- # AM: Balancing, see http://www.maunz.de/wordpress/opentox/2011/balanced-lazar
- l = Array.new # larger
- s = Array.new # smaller fraction
-
- raise "no fingerprints in model" if @fingerprints.size==0
-
- @fingerprints.each do |training_compound,training_features|
- @activities[training_compound].each do |act|
- case act.to_s
- when "false"
- l << training_compound
- when "true"
- s << training_compound
- else
- LOGGER.warn "BLAZAR: Activity #{act.to_s} should not be reached."
- end
- end
- end
- if s.size > l.size then
- l,s = s,l # happy swapping
- LOGGER.info "BLAZAR: |s|=#{s.size}, |l|=#{l.size}."
- end
- # determine ratio
- modulo = l.size.divmod(s.size)# modulo[0]=ratio, modulo[1]=rest
- LOGGER.info "BLAZAR: Balance: #{modulo[0]}, rest #{modulo[1]}."
-
- # AM: Balanced predictions
- addon = (modulo[1].to_f/modulo[0]).ceil # what will be added in each round
- slack = (addon!=0 ? modulo[1].divmod(addon)[1] : 0) # what remains for the last round
- position = 0
- predictions = Array.new
-
- prediction_best=nil
- neighbors_best=nil
-
- begin
- for i in 1..modulo[0] do
- (i == modulo[0]) && (slack>0) ? lr_size = s.size + slack : lr_size = s.size + addon # determine fraction
- LOGGER.info "BLAZAR: Neighbors round #{i}: #{position} + #{lr_size}."
- neighbors_balanced(s, l, position, lr_size) # get ratio fraction of larger part
- if @prop_kernel && @prediction_algorithm.include?("svm")
- props = get_props
- else
- props = nil
- end
- prediction = eval("#{@prediction_algorithm}(@neighbors,{:similarity_algorithm => @similarity_algorithm, :p_values => @p_values}, props)")
- if prediction_best.nil? || prediction[:confidence].abs > prediction_best[:confidence].abs
- prediction_best=prediction
- neighbors_best=@neighbors
- end
- position = position + lr_size
- end
- rescue Exception => e
- LOGGER.error "BLAZAR failed in prediction: "+e.class.to_s+": "+e.message
- end
-
- prediction=prediction_best
- @neighbors=neighbors_best
- ### END AM balanced predictions
-
- else # AM: no balancing
- LOGGER.info "LAZAR: Unbalanced."
- neighbors
- if @prop_kernel && @prediction_algorithm.include?("svm")
- props = get_props
- else
- props = nil
- end
- prediction = eval("#{@prediction_algorithm}(@neighbors,{:similarity_algorithm => @similarity_algorithm, :p_values => @p_values}, props)")
- end
-
- value_feature_uri = File.join( @uri, "predicted", "value")
- confidence_feature_uri = File.join( @uri, "predicted", "confidence")
-
- #prediction_feature_uris = {value_feature_uri => prediction[:prediction], confidence_feature_uri => prediction[:confidence]}
- #prediction_feature_uris[value_feature_uri] = nil if @neighbors.size == 0 or prediction[:prediction].nil?
-
- @prediction_dataset.metadata[OT.dependentVariables] = @metadata[OT.dependentVariables]
- @prediction_dataset.metadata[OT.predictedVariables] = [value_feature_uri, confidence_feature_uri]
-
- if OpenTox::Feature.find(metadata[OT.dependentVariables]).feature_type == "classification"
- @prediction_dataset.add @compound.uri, value_feature_uri, @value_map[prediction[:prediction]]
- else
- @prediction_dataset.add @compound.uri, value_feature_uri, prediction[:prediction]
- end
- @prediction_dataset.add @compound.uri, confidence_feature_uri, prediction[:confidence]
- #prediction_feature_uris.each do |prediction_feature_uri,value|
- #@prediction_dataset.add @compound.uri, prediction_feature_uri, @value_map[value]
- #end
-
- if verbose
- if @feature_calculation_algorithm == "Substructure.match"
- f = 0
- @compound_features.each do |feature|
- feature_uri = File.join( @prediction_dataset.uri, "feature", "descriptor", f.to_s)
- features[feature] = feature_uri
- @prediction_dataset.add_feature(feature_uri, {
- RDF.type => [OT.Substructure],
- OT.smarts => feature,
- OT.pValue => @p_values[feature],
- OT.effect => @effects[feature]
- })
- @prediction_dataset.add @compound.uri, feature_uri, true
- f+=1
- end
- else
- @compound_features.each do |feature|
- features[feature] = feature
- @prediction_dataset.add @compound.uri, feature, true
- end
- end
- n = 0
- @neighbors.each do |neighbor|
- neighbor_uri = File.join( @prediction_dataset.uri, "feature", "neighbor", n.to_s )
- @prediction_dataset.add_feature(neighbor_uri, {
- OT.compound => neighbor[:compound],
- OT.similarity => neighbor[:similarity],
- OT.measuredActivity => neighbor[:activity],
- RDF.type => [OT.Neighbor]
- })
- @prediction_dataset.add @compound.uri, neighbor_uri, true
- f = 0 unless f
- neighbor[:features].each do |feature|
- if @feature_calculation_algorithm == "Substructure.match"
- feature_uri = File.join( @prediction_dataset.uri, "feature", "descriptor", f.to_s) unless feature_uri = features[feature]
- else
- feature_uri = feature
- end
- @prediction_dataset.add neighbor[:compound], feature_uri, true
- unless features.has_key? feature
- features[feature] = feature_uri
- @prediction_dataset.add_feature(feature_uri, {
- RDF.type => [OT.Substructure],
- OT.smarts => feature,
- OT.pValue => @p_values[feature],
- OT.effect => @effects[feature]
- })
- f+=1
- end
- end
- n+=1
- end
- end
- #end
-
- @prediction_dataset.save(subjectid)
- @prediction_dataset
- end
-
- # Calculate the propositionalization matrix aka instantiation matrix (0/1 entries for features)
- # Same for the vector describing the query compound
- def get_props
- matrix = Array.new
- begin
- @neighbors.each do |n|
- n = n[:compound]
- row = []
- @features.each do |f|
- if ! @fingerprints[n].nil?
- row << (@fingerprints[n].include?(f) ? 0.0 : @p_values[f])
- else
- row << 0.0
- end
- end
- matrix << row
- end
- row = []
- @features.each do |f|
- row << (@compound.match([f]).size == 0 ? 0.0 : @p_values[f])
- end
- rescue Exception => e
- LOGGER.debug "get_props failed with '" + $! + "'"
- end
- [ matrix, row ]
- end
-
- # Find neighbors and store them as object variable, access only a subset of compounds for that.
- def neighbors_balanced(s, l, start, offset)
- @compound_features = eval("#{@feature_calculation_algorithm}(@compound,@features)") if @feature_calculation_algorithm
- @neighbors = []
- [ l[start, offset ] , s ].flatten.each do |training_compound| # AM: access only a balanced subset
- training_features = @fingerprints[training_compound]
- add_neighbor training_features, training_compound
- end
-
- end
-
- # Find neighbors and store them as object variable, access all compounds for that.
- def neighbors
- @compound_features = eval("#{@feature_calculation_algorithm}(@compound,@features)") if @feature_calculation_algorithm
- @neighbors = []
- @fingerprints.each do |training_compound,training_features| # AM: access all compounds
- add_neighbor training_features, training_compound
- end
- end
-
- # Adds a neighbor to @neighbors if it passes the similarity threshold.
- def add_neighbor(training_features, training_compound)
- sim = eval("#{@similarity_algorithm}(@compound_features,training_features,@p_values)")
- if sim > @min_sim
- @activities[training_compound].each do |act|
- @neighbors << {
- :compound => training_compound,
- :similarity => sim,
- :features => training_features,
- :activity => act
- }
- end
- end
- end
-
- # Find database activities and store them in @prediction_dataset
- # @return [Boolean] true if compound has databasse activities, false if not
- def database_activity(subjectid)
- if @activities[@compound.uri]
- @activities[@compound.uri].each { |act| @prediction_dataset.add @compound.uri, @metadata[OT.dependentVariables], act }
- @prediction_dataset.add_metadata(OT.hasSource => @metadata[OT.trainingDataset])
- @prediction_dataset.save(subjectid)
- true
- else
- false
- end
- end
-
- def prediction_features
- [prediction_value_feature,prediction_confidence_feature]
- end
-
- def prediction_value_feature
- dependent_uri = @metadata[OT.dependentVariables].first
- feature = OpenTox::Feature.new File.join( @uri, "predicted", "value")
- feature.add_metadata( {
- RDF.type => [OT.ModelPrediction],
- OT.hasSource => @uri,
- DC.creator => @uri,
- DC.title => URI.decode(File.basename( dependent_uri )),
- OWL.sameAs => dependent_uri
- })
- feature
- end
-
- def prediction_confidence_feature
- dependent_uri = @metadata[OT.dependentVariables].first
- feature = OpenTox::Feature.new File.join( @uri, "predicted", "confidence")
- feature.add_metadata( {
- RDF.type => [OT.ModelPrediction],
- OT.hasSource => @uri,
- DC.creator => @uri,
- DC.title => "#{URI.decode(File.basename( dependent_uri ))} confidence"
- })
- feature
- end
-
- # Save model at model service
- def save(subjectid)
- self.uri = RestClientWrapper.post(@uri,self.to_yaml,{:content_type => "application/x-yaml", :subjectid => subjectid})
- end
-
- # Delete model at model service
- def delete(subjectid)
- RestClientWrapper.delete(@uri, :subjectid => subjectid) unless @uri == CONFIG[:services]["opentox-model"]
- end
-
-=end
- end
end
end
diff --git a/lib/ontology.rb b/lib/ontology.rb
deleted file mode 100644
index fa4ea6f..0000000
--- a/lib/ontology.rb
+++ /dev/null
@@ -1,55 +0,0 @@
-module OpenTox
- module Ontology
- module Echa
-=begin
- require 'sparql/client'
- @sparql = SPARQL::Client.new("http://apps.ideaconsult.net:8080/ontology")
- def self.qs(classname="Endpoints")
- return "PREFIX ot:
- PREFIX ota:
- PREFIX owl:
- PREFIX dc:
- PREFIX rdfs:
- PREFIX rdf:
- PREFIX otee:
- PREFIX toxcast:
- select *
- where {
- ?endpoint rdfs:subClassOf otee:#{classname}.
- ?endpoint dc:title ?title.
- }"
- end
-
- def self.make_option_list(endpoint="Endpoints", level=1)
- out = ""
- results = @sparql.query(qs(endpoint)) rescue results = []
- results.each do |result|
- endpointname = result.Endpoints.to_s.split('#').last
- title = result.bound?(:title) ? result.title : endpointname
- out += "\n"
- out += make_option_list(endpointname, level + 1)
- end
- return out
- end
-
- def self.get_endpoint_selectlist(include_blank=true)
- out = "\n"
- return out
- end
-=end
-
- def self.endpoints
- RestClientWrapper.get("http://apps.ideaconsult.net:8080/ambit2/query/ndatasets_endpoint",:accept => "text/csv").collect { |line| line.split(',').first if line.match(/^http/) }.compact
- end
-
- def self.datasets(endpoint)
- RestClientWrapper.get("http://apps.ideaconsult.net:8080/ambit2/dataset?feature_sameas=#{URI.encode endpoint}", :accept => "text/uri-list").split("\n")
- end
-
- end
-
- end
-end
diff --git a/lib/opentox-client.rb b/lib/opentox-client.rb
new file mode 100644
index 0000000..bc297b5
--- /dev/null
+++ b/lib/opentox-client.rb
@@ -0,0 +1,7 @@
+require 'rdf'
+require 'rdf/raptor'
+require "rest-client"
+require "opentox"
+require "task"
+require "compound"
+require "dataset"
diff --git a/lib/opentox-ruby-minimal.rb b/lib/opentox-ruby-minimal.rb
deleted file mode 100644
index e0d5489..0000000
--- a/lib/opentox-ruby-minimal.rb
+++ /dev/null
@@ -1,2 +0,0 @@
-require "opentox"
-require "compound"
diff --git a/lib/opentox-ruby.rb b/lib/opentox-ruby.rb
deleted file mode 100644
index 63935fa..0000000
--- a/lib/opentox-ruby.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-#['rubygems', 'sinatra', 'sinatra/url_for', 'ohm', 'rest_client', 'yaml', 'cgi', 'spork', 'error', 'overwrite', 'environment'].each do |lib|
-['rubygems', 'rest_client', 'yaml', 'cgi', 'error', 'overwrite', 'environment'].each do |lib|
- require lib
-end
-
-#begin
- #require 'openbabel'
-#rescue LoadError
- #puts "Please install Openbabel with 'rake openbabel:install' in the compound component"
-#end
-
-#['opentox', 'compound','dataset', 'parser','serializer', 'algorithm','model','task','validation','feature', 'rest_client_wrapper', 'authorization', 'policy', 'helper', 'to-html', 'ontology' ].each do |lib|
-['opentox', 'compound','dataset', 'parser','serializer', 'algorithm','model','task','validation','feature', 'rest_client_wrapper', 'authorization', 'policy', 'ontology' ].each do |lib|
- require lib
-end
diff --git a/lib/opentox.owl b/lib/opentox.owl
deleted file mode 100644
index 4760055..0000000
--- a/lib/opentox.owl
+++ /dev/null
@@ -1,809 +0,0 @@
-
-
-
- http://opentox.org/dev/apis/api-1.1
- 2009-11-22
- martin.guetlein@gmail.com
- jeliazkova.nina@gmail.com
- OpenTox resource ontology
- OpenTox API
- OpenTox
-
-
-
- http://opentox.org/dev/apis/api-1.1/dataset
-
- /dataset/{datasetid}
-
- Original source of the dataset
-
-
- Provides access to chemical compounds and their features (e.g. structural, physical-chemical, biological, toxicological properties)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- A generic OpenTox resource
- name of the resource
- URI of the resource
- 1.1
-
-
-
-
-
-
-
-
- TODO: Specify allowed values for model content
- The native format of the model content (e.g. PMML, Weka model, etc.)
-
-
-
- TODO: Introduce a link to User resource
- /model/{modelid}
- The model creator (perhaps a link to User resource)
-
-
- The date of model creation
-
-
- A validation corresponds to the validation of a model on a test dataset. The results are stored in another dataset. Parameters with default values are optional.
- Datetime
- http://opentox.org/dev/apis/api-1.1/Validation
-
-
-
- http://opentox.org/dev/apis/api-1.1/Validation#validation-report
-
-
-
- TODO: AlgorithmType, or link to Algorithm ontology
- 1.1
- Reference
- TODO: statistics supported - is it possible to reuse ValidationInfo classes?
- /algorithm/{algorithmid}
-
- http://opentox.org/dev/apis/api-1.1/Algorithm
- Name of the algorithm
-
-
-
-
-
-
-
-
-
-
-
-
- Provides access to OpenTox algorithms
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- encapsulates validation information
-
-
-
-
-
-
-
- /compound/{compoundid}
- http://opentox.org/dev/apis/api-1.1/structure
-
-
-
-
- 1.1
-
-
-
-
-
-
-
- API for OpenTox compound webservices
-
-
-
-
-
-
-
- true
-
-
-
- [Optional] support for multiple (e.g. 3D) structures per chemical compound (single structure by default)
- /compound/{compoundid}/conformer/{conformerid}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 1.1
-
-
-
- /feature/{featureid}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- /dataset/{datasetid}/compound/{compoundid}?feature_uri[]=featureuris
-
-
- 1.1
-
- Encapsulates a dataset entry - defined by a single Compound (or conformer) and multiple FeatureValues. Could be regarded as "Compound with features"
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- PredictionDatasetURI
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- A model can have one or more dependent variables, described as multiple features, specified by this relationship.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Algorithms and Models can have multiple parameters
- http://opentox.org/api/1.1
-
-
-
-
-
-
-
-
-
-
-
-
- Test dataset , used in a validation exercise
-
-
-
-
-
- http://opentox.org/api/1.1
-
- Variables, holding the predicted values, generated by the model
-
-
- http://opentox.org/api/1.1
-
-
- A Dataset contains multiple DataEntries. This property specifies the relationship between Dataset and DataEntry.
-
-
-
-
-
- a link to UnscrambledDataset
- UnscrambledDatasetURI
-
-
-
- http://opentox.org/api/1.1
- A model can have multiple independent variables, described as multiple features, specified by this relationship.
-
-
-
-
-
- Links Validation with Validation Info. One validation exercise may have multiple types of validation informaton
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- A DataEntry is defined with a single compound and multiple feature values. This property sets the relationship between a DataEntry and multiple FeatureValues
- http://opentox.org/api/1.1
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Cancelled
-
-
- Running
-
-
- Completed
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Parameter value
- The value of a Parameter
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Units
- Units for a feature value
- TODO: make use of units ontology
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Allows to define "is a" relationships outside of particular class hierarchy
-
-
-
- Model used in a validation exercise
-
-
-
-
-
-
-
- Number incorrect
-
-
-
-
-
-
- Percent Correct
-
-
-
-
-
-
- RootMeanSquaredError
-
-
-
-
-
-
-
- YScramblingEnabled
-
- YScramblingEnabled
-
-
-
-
- YScramblingSeed
- YScramblingSeed
-
-
-
-
-
-
-
-
-
-
- Has 3D structure
-
- True, if the compound has 3D structure
-
-
-
-
-
- Literal
-
- Feature value
-
-
-
-
-
- A model is derived by applying an Algorithm on a training Dataset.
- http://opentox.org/api/1.1
-
-
-
-
-
-
-
-
-
- http://opentox.org/api/1.1
- The algorithm, used to create the Model
-
-
-
-
-
-
-
-
-
- Number correct
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- specifies if a parameter is optional or mandatory
-
-
-
-
-
-
- optional
-
- mandatory
-
-
-
- Parameter scope
-
-
-
-
- Percentage completed
-
-
-
-
- http://opentox.org/api/1.1
-
-
-
- A DataEntry is defined with a single compound and multiple feature values. This property sets the relationship between a DataEntry and a Compound
-
-
-
-
- Percent Incorrect
-
-
-
-
-
- MeanAbsolutError
-
-
-
-
-
- FeatureValue contains a value for specific Feature, specified by this relationship.
-
-
- http://opentox.org/api/1.1
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/lib/opentox.rb b/lib/opentox.rb
index a6ac1d4..a9cbeab 100644
--- a/lib/opentox.rb
+++ b/lib/opentox.rb
@@ -1,23 +1,100 @@
-require 'rdf'
-require 'rdf/raptor'
-#require "parser.rb"
-require "rest_client_wrapper.rb"
-require "overwrite.rb"
-require "error.rb"
-
-RDF::OT = RDF::Vocabulary.new 'http://www.opentox.org/api/1.1#'
+#TODO: switch services to 1.2
+#TODO: error handling
+RDF::OT = RDF::Vocabulary.new 'http://www.opentox.org/api/1.2#'
+RDF::OT1 = RDF::Vocabulary.new 'http://www.opentox.org/api/1.1#'
RDF::OTA = RDF::Vocabulary.new 'http://www.opentox.org/algorithmTypes.owl#'
SERVICES = ["Compound", "Feature", "Dataset", "Algorithm", "Model", "Validation", "Task"]
+# not working
+RestClient.add_before_execution_proc do |req, params|
+ params[:subjectid] = @subjectid
+end
+
+class String
+ def to_object
+ # TODO: fix, this is unsafe
+ self =~ /dataset/ ? uri = File.join(self.chomp,"metadata") : uri = self.chomp
+ raise "#{uri} is not a valid URI." unless RDF::URI.new(uri).uri?
+ RDF::Reader.open(uri) do |reader|
+ reader.each_statement do |statement|
+ if statement.predicate == RDF.type and statement.subject == uri
+ klass = "OpenTox::#{statement.object.to_s.split("#").last}"
+ object = eval "#{klass}.new \"#{uri}\""
+ end
+ end
+ end
+ # fallback: guess class from uri
+ # TODO: fix services and remove
+ unless object
+ case uri
+ when /compound/
+ object = OpenTox::Compound.new uri
+ when /feature/
+ object = OpenTox::Feature.new uri
+ when /dataset/
+ object = OpenTox::Dataset.new uri.sub(/\/metadata/,'')
+ when /algorithm/
+ object = OpenTox::Algorithm.new uri
+ when /model/
+ object = OpenTox::Model.new uri
+ when /validation/
+ object = OpenTox::Validation.new uri
+ when /task/
+ object = OpenTox::Task.new uri
+ else
+ raise "Class for #{uri} not found."
+ end
+ end
+ if object.class == Task # wait for tasks
+ object.wait_for_completion
+ object = object.result_uri.to_s.to_object
+ end
+ object
+ end
+
+=begin
+ def object_from_uri
+ # TODO: fix, this is unsafe
+ self =~ /dataset/ ? uri = File.join(self.chomp,"metadata") : uri = self.chomp
+ RDF::Reader.open(uri) do |reader|
+ reader.each_statement do |statement|
+ if statement.predicate == RDF.type and statement.subject == uri
+ klass = "OpenTox::#{statement.object.to_s.split("#").last}"
+ return eval "#{klass}.new \"#{uri}\""
+ end
+ end
+ end
+ # guess class from uri
+ # TODO: fix services and remove
+ case uri
+ when /compound/
+ return OpenTox::Compound.new uri
+ when /feature/
+ return OpenTox::Feature.new uri
+ when /dataset/
+ return OpenTox::Dataset.new uri.sub(/\/metadata/,'')
+ when /algorithm/
+ return OpenTox::Algorithm.new uri
+ when /model/
+ return OpenTox::Model.new uri
+ when /validation/
+ return OpenTox::Validation.new uri
+ when /task/
+ return OpenTox::Task.new uri
+ else
+ raise "Class for #{uri} not found."
+ end
+ end
+=end
+end
+
module OpenTox
- attr_accessor :subjectid, :uri
+ attr_accessor :subjectid, :uri, :response
attr_writer :metadata
- # Initialize OpenTox object with optional subjectid
- # @param [optional, String] subjectid
def initialize uri=nil, subjectid=nil
- @uri = uri
+ @uri = uri.chomp
@subjectid = subjectid
end
@@ -36,104 +113,73 @@ module OpenTox
end
def save
- rdf = RDF::Writer.buffer do |writer|
+ rdf = RDF::Writer.for(:rdfxml).buffer do |writer|
@metadata.each { |p,o| writer << RDF::Statement.new(RDF::URI.new(@uri), p, o) }
end
- puts rdf
- #post(@uri, rdf, { :content_type => 'application/rdf+xml', :subjectid => subjectid}).to_s.chomp, @subjectid
+ post rdf, { :content_type => 'application/rdf+xml'}
end
# REST API
- # returns OpenTox::WrapperResult, not OpenTox objects
-
- # perfoms a GET REST call
- # raises OpenTox::Error if call fails (rescued in overwrite.rb -> halt 502)
- # per default: waits for Task to finish and returns result URI of Task
- # @param [optional,Hash] headers contains params like accept-header
- # @param [wait,Boolean] wait set to false to NOT wait for task if result is task
- # @return [OpenTox::WrapperResult] a String containing the result-body of the REST call
- def get headers={}, wait=true
- headers[:subjectid] = @subjectid
- RestClientWrapper.get(@uri.to_s, headers, nil, wait).chomp
+ def get params={}
+ params[:subjectid] ||= @subjectid
+ params[:accept] ||= 'application/rdf+xml'
+ @response = RestClient.get @uri, params
end
- # performs a POST REST call
- # raises OpenTox::Error if call fails (rescued in overwrite.rb -> halt 502)
- # per default: waits for Task to finish and returns result URI of Task
- # @param [optional,String] payload data posted to the service
- # @param [optional,Hash] headers contains params like accept-header
- # @param [wait,Boolean] wait set to false to NOT wait for task if result is task
- # @return [OpenTox::WrapperResult] a String containing the result-body of the REST call
- def post payload={}, headers={}, wait=true
- headers[:subjectid] = @subjectid
- RestClientWrapper.post(@uri.to_s, payload, headers, nil, wait).chomp
+ def post payload={}, params={}
+ params[:subjectid] ||= @subjectid
+ params[:accept] ||= 'application/rdf+xml'
+ @response = RestClient.post(@uri.to_s, payload, params)
+ begin
+ @response.to_s.to_object
+ rescue
+ @response
+ end
end
- # performs a PUT REST call
- # raises OpenTox::Error if call fails (rescued in overwrite.rb -> halt 502)
- # @param [optional,String] payload data put to the service
- # @param [optional,Hash] headers contains params like accept-header
- # @return [OpenTox::WrapperResult] a String containing the result-body of the REST call
- def put payload={}, headers={}
- headers[:subjectid] = @subjectid
- RestClientWrapper.put(@uri.to_s, payload, headers).chomp
+ def put payload={}, params={}
+ params[:subjectid] ||= @subjectid
+ params[:accept] ||= 'application/rdf+xml'
+ @response = RestClient.put(@uri.to_s, payload, params)
end
- # performs a DELETE REST call
- # raises OpenTox::Error if call fails (rescued in overwrite.rb -> halt 502)
- # @return [OpenTox::WrapperResult] a String containing the result-body of the REST call
- def delete
- RestClientWrapper.delete(@uri.to_s,:subjectid => @subjectid)
+ def delete params={}
+ params[:subjectid] ||= @subjectid
+ params[:accept] ||= 'application/rdf+xml'
+ @response = RestClient.delete(@uri.to_s,:subjectid => @subjectid)
end
+ # class methods
+ module ClassMethods
- module Service
def create service_uri, subjectid=nil
- service = eval("#{self}.new(\"#{service_uri}\", #{subjectid})")
- uri = service.post({}, {}, subjectid).to_s
- eval "#{self}.new(\"#{uri}\", #{subjectid})"
+ uri = RestClient.post(service_uri, {}, :subjectid => subjectid).chomp
+ eval("#{self}.new(\"#{uri}\", #{subjectid})")
end
+
+ def from_file service_uri, file, subjectid=nil
+ RestClient.post(service_uri, :file => File.new(file), :subjectid => subjectid).chomp.to_object
+ end
+
+ def all service_uri, subjectid=nil
+ uris = RestClient.get(service_uri, {:accept => 'text/uri-list'}).split("\n").compact
+ uris.collect{|uri| eval "#{self}.new(\"#{uri}\", #{subjectid})"}
+ end
+
+ end
+
+ class FromUri
end
# create default classes
SERVICES.each do |s|
eval "class #{s}
include OpenTox
- extend OpenTox::Service
+ extend OpenTox::ClassMethods
end"
end
-=begin
private
- def uri_available?
- url = URI.parse(@uri)
- #req = Net::HTTP.new(url.host,url.port)
- #req['subjectid'] = @subjectid if @subjectid
- Net::HTTP.start(url.host, url.port) do |http|
- return http.head("#{url.request_uri}#{subjectidstr}").code == "200"
- end
- end
-
- module Collection
-
- include OpenTox
-
- def create metadata
- object_class.new post(service_uri, metadata.to_rdfxml, { :content_type => 'application/rdf+xml', :subjectid => subjectid}).to_s.chomp, @subject_id
- end
-
- # Get all objects from a service
- # @return [Array] List of available Objects
- def all
- get(:accept => "text/uri-list").to_s.split(/\n/).collect{|uri| object_class.new uri,@subjectid}
- end
-
- # create collection classes
- SERVICES.each { |s| eval "class #{s}; include Collection; end" }
-
- end
-=end
-
end
diff --git a/lib/overwrite.rb b/lib/overwrite.rb
deleted file mode 100644
index d541b61..0000000
--- a/lib/overwrite.rb
+++ /dev/null
@@ -1,155 +0,0 @@
-require 'uri'
-=begin
-# class overwrites aka monkey patches
-# hack: store sinatra instance in global var $url_provider to make url_for and halt methods accessible
-before {
- raise "should not happen, url provider already differently initialized "+
- $url_provider.request.host.to_s+" != "+self.request.host.to_s if
- $url_provider and $url_provider.request.host!=self.request.host and
- $url_provider.request.script_name!=self.request.script_name
- $url_provider = self
- # stupid internet explorer does not ask for text/html, add this manually
- request.env['HTTP_ACCEPT'] += ";text/html" if request.env["HTTP_USER_AGENT"]=~/MSIE/
- request.env['HTTP_ACCEPT']=request.params["media"] if request.params["media"]
-}
-
-# Error handling
-# Errors are logged as error and formated according to acccept-header
-# Non OpenTox::Errors (defined in error.rb) are handled as internal error (500), stacktrace is logged
-# IMPT: set sinatra settings :show_exceptions + :raise_errors to false in config.ru, otherwise Rack::Showexceptions takes over
-error Exception do
- error = request.env['sinatra.error']
- # log error message and backtrace to logfile
- LOGGER.error error.class.to_s+": "+error.message
- LOGGER.error ":\n"+error.backtrace.join("\n")
-
- actor = "#{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}#{request.env['REQUEST_URI']}"
- rep = OpenTox::ErrorReport.create(error, actor)
-
- case request.env['HTTP_ACCEPT']
- when /rdf/
- content_type 'application/rdf+xml'
- halt error.http_code,rep.to_rdfxml
- when /html/
- content_type 'text/html'
- halt error.http_code,(OpenTox.text_to_html rep.to_yaml, @subjectid)
- else
- content_type 'application/x-yaml'
- halt error.http_code,rep.to_yaml
- end
-end
-
-class Sinatra::Base
-
- def return_task( task )
- raise "http_code == nil" unless task.http_code!=nil
- case request.env['HTTP_ACCEPT']
- when /rdf/
- response['Content-Type'] = "application/rdf+xml"
- halt task.http_code,task.to_rdfxml
- when /yaml/
- response['Content-Type'] = "application/x-yaml"
- halt task.http_code,task.to_yaml # PENDING differs from task-webservice
- when /html/
- response['Content-Type'] = "text/html"
- halt task.http_code,OpenTox.text_to_html(task.to_yaml, @subjectid)
- else # default /uri-list/
- response['Content-Type'] = "text/uri-list"
- if task.completed?
- halt task.http_code,task.resultURI+"\n"
- else
- halt task.http_code,task.uri+"\n"
- end
- end
- end
-end
-=end
-
-class String
- def task_uri?
- self.uri? && !self.match(/task/).nil?
- end
-
- def dataset_uri?
- self.uri? && !self.match(/dataset/).nil?
- end
-
- def self.model_uri?
- self.uri? && !self.match(/model/).nil?
- end
-
- def uri?
- begin
- u = URI::parse(self)
- return (u.scheme!=nil and u.host!=nil)
- rescue URI::InvalidURIError
- return false
- end
- end
-
- def underscore
- self.gsub(/::/, '/').
- gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
- gsub(/([a-z\d])([A-Z])/,'\1_\2').
- tr("-", "_").
- downcase
- end
-end
-
-require 'logger'
-# logging
-#class Logger
-class OTLogger < Logger
-
- def pwd
- path = Dir.pwd.to_s
- index = path.rindex(/\//)
- return path if index==nil
- path[(index+1)..-1]
- end
-
- def trace()
- lines = caller(0)
- n = 2
- line = lines[n]
-
- while (line =~ /spork.rb/ or line =~ /create/ or line =~ /overwrite.rb/)
- n += 1
- line = lines[n]
- end
-
- index = line.rindex(/\/.*\.rb/)
- return line if index==nil
- line[index..-1]
- end
-
- def format(msg)
- pwd.ljust(18)+" :: "+msg.to_s+" :: "+trace
- end
-
- def debug(msg)
- super format(msg)
- end
-
- def info(msg)
- super format(msg)
- end
-
- def warn(msg)
- super format(msg)
- end
-
- def error(msg)
- super format(msg)
- end
-
-end
-
-# make migration from datamapper more straightforward
-=begin
-class Ohm::Model
- def self.get(id)
- self[id]
- end
-end
-=end
diff --git a/lib/parser.rb b/lib/parser.rb
deleted file mode 100644
index 7475d6d..0000000
--- a/lib/parser.rb
+++ /dev/null
@@ -1,475 +0,0 @@
-#require 'spreadsheet'
-#require 'roo'
-
-# OWL Namespaces
-class OwlNamespace
-
- attr_accessor :uri
- def initialize(uri)
- @uri = uri
- end
-
- def [](property)
- @uri+property.to_s
- end
-
- def type # for RDF.type
- "#{@uri}type"
- end
-
- def method_missing(property)
- @uri+property.to_s
- end
-
-end
-
-RDF = OwlNamespace.new 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'
-OWL = OwlNamespace.new 'http://www.w3.org/2002/07/owl#'
-DC = OwlNamespace.new 'http://purl.org/dc/elements/1.1/'
-OT = OwlNamespace.new 'http://www.opentox.org/api/1.1#'
-OTA = OwlNamespace.new 'http://www.opentox.org/algorithmTypes.owl#'
-XSD = OwlNamespace.new 'http://www.w3.org/2001/XMLSchema#'
-
-class String
-
- # Split RDF statement into triples
- # @return [Array] Array with [subject,predicate,object]
- def to_triple
- self.chomp.split(' ',3).collect{|i| i.sub(/\s+.$/,'').gsub(/[<>"]/,'')}
- end
-
-end
-
-module OpenTox
-
- # Parser for various input formats
- module Parser
-
- # OWL-DL parser
- module Owl
-
- # Create a new OWL-DL parser
- # @param uri URI of OpenTox object
- # @return [OpenTox::Parser::Owl] OWL-DL parser
- def initialize(uri)
- @uri = uri
- @metadata = {}
- end
-
- # Read metadata from opentox service
- # @return [Hash] Object metadata
- def load_metadata(subjectid=nil)
- # avoid using rapper directly because of 2 reasons:
- # * http errors wont be noticed
- # * subjectid cannot be sent as header
- ##uri += "?subjectid=#{CGI.escape(subjectid)}" if subjectid
- ## `rapper -i rdfxml -o ntriples #{uri} 2>/dev/null`.each_line do |line|
- if File.exist?(@uri)
- file = File.new(@uri)
- else
- file = Tempfile.new("ot-rdfxml")
- if @dataset
- # do not concat /metadata to uri string, this would not work for dataset/R401577?max=3
- uri = URI::parse(@uri)
- uri.path = File.join(uri.path,"metadata")
- uri = uri.to_s
- else
- uri = @uri
- end
- file.puts OpenTox::RestClientWrapper.get uri,{:subjectid => subjectid,:accept => "application/rdf+xml"},nil,false
- file.close
- to_delete = file.path
- end
- statements = []
- parameter_ids = []
- `rapper -i rdfxml -o ntriples #{file.path} 2>/dev/null`.each_line do |line|
- triple = line.to_triple
- if triple[0] == @uri
- if triple[1] == RDF.type || triple[1]==OT.predictedVariables # allow multiple types
- @metadata[triple[1]] = [] unless @metadata[triple[1]]
- @metadata[triple[1]] << triple[2].split('^^').first
- else
- @metadata[triple[1]] = triple[2].split('^^').first
- end
- end
- statements << triple
- parameter_ids << triple[2] if triple[1] == OT.parameters
- end
- File.delete(to_delete) if to_delete
- unless parameter_ids.empty?
- @metadata[OT.parameters] = []
- parameter_ids.each do |p|
- parameter = {}
- statements.each{ |t| parameter[t[1]] = t[2] if t[0] == p and t[1] != RDF['type']}
- @metadata[OT.parameters] << parameter
- end
- end
- @metadata
- end
-
- # creates owl object from rdf-data
- # @param [String] rdf
- # @param [String] type of the info (e.g. OT.Task, OT.ErrorReport) needed to get the subject-uri
- # @return [Owl] with uri and metadata set
- def self.from_rdf( rdf, type )
- # write to file and read convert with rapper into tripples
- file = Tempfile.new("ot-rdfxml")
- file.puts rdf
- file.close
- #puts "cmd: rapper -i rdfxml -o ntriples #{file} 2>/dev/null"
- triples = `rapper -i rdfxml -o ntriples #{file.path} 2>/dev/null`
-
- # load uri via type
- uri = nil
- triples.each_line do |line|
- triple = line.to_triple
- if triple[1] == RDF['type'] and triple[2]==type
- raise "uri already set, two uris found with type: "+type.to_s if uri
- uri = triple[0]
- end
- end
- File.delete(file.path)
- # load metadata
- metadata = {}
- triples.each_line do |line|
- triple = line.to_triple
- metadata[triple[1]] = triple[2].split('^^').first if triple[0] == uri and triple[1] != RDF['type']
- end
- owl = Owl::Generic.new(uri)
- owl.metadata = metadata
- owl
- end
-
- # Generic parser for all OpenTox classes
- class Generic
- include Owl
-
- attr_accessor :uri, :metadata
- end
-
- # OWL-DL parser for datasets
- class Dataset
-
- include Owl
-
- attr_writer :uri
-
- # Create a new OWL-DL dataset parser
- # @param uri Dataset URI
- # @return [OpenTox::Parser::Owl::Dataset] OWL-DL parser
- def initialize(uri, subjectid=nil)
- super uri
- @dataset = ::OpenTox::Dataset.new(@uri, subjectid)
- end
-
- # Read data from dataset service. Files can be parsed by setting #uri to a filename (after initialization with a real URI)
- # @example Read data from an external service
- # parser = OpenTox::Parser::Owl::Dataaset.new "http://wwbservices.in-silico.ch/dataset/1"
- # dataset = parser.load_uri
- # @example Create dataset from RDF/XML file
- # dataset = OpenTox::Dataset.create
- # parser = OpenTox::Parser::Owl::Dataaset.new dataset.uri
- # parser.uri = "dataset.rdfxml" # insert your input file
- # dataset = parser.load_uri
- # dataset.save
- # @return [Hash] Internal dataset representation
- def load_uri(subjectid=nil)
-
- # avoid using rapper directly because of 2 reasons:
- # * http errors wont be noticed
- # * subjectid cannot be sent as header
- ##uri += "?subjectid=#{CGI.escape(subjectid)}" if subjectid
- ##`rapper -i rdfxml -o ntriples #{file} 2>/dev/null`.each_line do |line|
- if File.exist?(@uri)
- file = File.new(@uri)
- else
- file = Tempfile.new("ot-rdfxml")
- file.puts OpenTox::RestClientWrapper.get @uri,{:subjectid => subjectid,:accept => "application/rdf+xml"},nil,false
- file.close
- to_delete = file.path
- end
-
- data = {}
- feature_values = {}
- feature = {}
- feature_accept_values = {}
- other_statements = {}
- `rapper -i rdfxml -o ntriples #{file.path} 2>/dev/null`.each_line do |line|
- triple = line.chomp.split(' ',3)
- triple = triple[0..2].collect{|i| i.sub(/\s+.$/,'').gsub(/[<>"]/,'')}
- case triple[1]
- when /#{OT.values}/i
- data[triple[0]] = {:compound => "", :values => []} unless data[triple[0]]
- data[triple[0]][:values] << triple[2]
- when /#{OT.value}/i
- feature_values[triple[0]] = triple[2]
- when /#{OT.compound}/i
- data[triple[0]] = {:compound => "", :values => []} unless data[triple[0]]
- data[triple[0]][:compound] = triple[2]
- when /#{OT.feature}/i
- feature[triple[0]] = triple[2]
- when /#{RDF.type}/i
- if triple[2]=~/#{OT.Compound}/i and !data[triple[0]]
- data[triple[0]] = {:compound => triple[0], :values => []}
- end
- when /#{OT.acceptValue}/i # acceptValue in ambit datasets is only provided in dataset/ no in dataset//features
- feature_accept_values[triple[0]] = [] unless feature_accept_values[triple[0]]
- feature_accept_values[triple[0]] << triple[2]
- else
- end
- end
- File.delete(to_delete) if to_delete
- data.each do |id,entry|
- if entry[:values].size==0
- # no feature values add plain compounds
- @dataset.add_compound(entry[:compound])
- else
- entry[:values].each do |value_id|
- if feature_values[value_id]
- split = feature_values[value_id].split(/\^\^/)
- case split[-1]
- when XSD.double, XSD.float
- value = split.first.to_f
- when XSD.boolean
- value = split.first=~/(?i)true/ ? true : false
- else
- value = split.first
- end
- end
- @dataset.add entry[:compound],feature[value_id],value
- end
- end
- end
- load_features subjectid
- feature_accept_values.each do |feature, values|
- @dataset.features[feature][OT.acceptValue] = values
- end
- @dataset.metadata = load_metadata(subjectid)
- @dataset
- end
-
- # Read only features from a dataset service.
- # @return [Hash] Internal features representation
- def load_features(subjectid=nil)
- if File.exist?(@uri)
- file = File.new(@uri)
- else
- file = Tempfile.new("ot-rdfxml")
- # do not concat /features to uri string, this would not work for dataset/R401577?max=3
- uri = URI::parse(@uri)
- # PENDING
- # ambit models return http://host/dataset/id?feature_uris[]=sth but
- # amibt dataset services does not support http://host/dataset/id/features?feature_uris[]=sth
- # -> load features from complete dataset
- uri.path = File.join(uri.path,"features") unless @uri=~/\?feature_uris\[\]/
- uri = uri.to_s
- file.puts OpenTox::RestClientWrapper.get uri,{:subjectid => subjectid,:accept => "application/rdf+xml"},nil,false
- file.close
- to_delete = file.path
- end
- statements = []
- features = Set.new
- `rapper -i rdfxml -o ntriples #{file.path} 2>/dev/null`.each_line do |line|
- triple = line.chomp.split('> ').collect{|i| i.sub(/\s+.$/,'').gsub(/[<>"]/,'')}[0..2]
- statements << triple
- features << triple[0] if triple[1] == RDF.type and (triple[2] =~ /Feature|Substructure/)
- end
- File.delete(to_delete) if to_delete
- statements.each do |triple|
- if features.include? triple[0]
- @dataset.features[triple[0]] = {} unless @dataset.features[triple[0]]
- @dataset.features[triple[0]][triple[1]] = triple[2].split('^^').first
- end
- end
- @dataset.features
- end
-
- end
-
- end
-
-=begin
- # Parser for getting spreadsheet data into a dataset
- class Spreadsheets
-
- attr_accessor :dataset
-
- def initialize
- @data = []
- @features = []
- @feature_types = {}
-
- @format_errors = ""
- @smiles_errors = []
- @activity_errors = []
- @duplicates = {}
- end
-
- # Load Spreadsheet book (created with roo gem http://roo.rubyforge.org/, excel format specification: http://toxcreate.org/help)
- # @param [Excel] book Excel workbook object (created with roo gem)
- # @return [OpenTox::Dataset] Dataset object with Excel data
- def load_spreadsheet(book)
- book.default_sheet = 0
- add_features book.row(1)
-
- # AM: fix mixed read in
- regression_features=false
- 2.upto(book.last_row) { |i|
- row = book.row(i)
- regression_features = detect_regression_features row
- break if regression_features==true
- }
-
- 2.upto(book.last_row) { |i| add_values book.row(i),regression_features }
- warnings
- @dataset
- end
-
- # Load CSV string (format specification: http://toxcreate.org/help)
- # @param [String] csv CSV representation of the dataset
- # @return [OpenTox::Dataset] Dataset object with CSV data
- def load_csv(csv)
- row = 0
- input = csv.split("\n")
- add_features split_row(input.shift)
-
-
- # AM: fix mixed read in
- regression_features=false
- input.each { |row|
- row = split_row(row)
- regression_features = detect_regression_features row
- break if regression_features==true
- }
- input.each { |row| add_values split_row(row),regression_features }
- warnings
- @dataset
- end
-
-
- private
-
- def warnings
-
- info = ''
- @feature_types.each do |feature,types|
- if types.uniq.size > 1
- type = OT.NumericFeature
- else
- type = types.first
- end
- @dataset.add_feature_metadata(feature,{RDF.type => [type]})
- info += "\"#{@dataset.feature_name(feature)}\" detected as #{type.split('#').last}."
-
- # TODO: rewrite feature values
- # TODO if value.to_f == 0 @activity_errors << "#{smiles} Zero values not allowed for regression datasets - entry ignored."
- end
-
- @dataset.metadata[OT.Info] = info
-
- warnings = ''
- warnings += "
Duplicated structures (all structures/activities used for model building, please make sure, that the results were obtained from independent experiments):
" + duplicate_warnings unless duplicate_warnings.empty?
-
- @dataset.metadata[OT.Warnings] = warnings
-
- end
-
- def add_features(row)
- row.shift # get rid of smiles entry
- row.each do |feature_name|
- feature_uri = File.join(@dataset.uri,"feature",URI.encode(feature_name))
- @feature_types[feature_uri] = []
- @features << feature_uri
- @dataset.add_feature(feature_uri,{DC.title => feature_name})
- end
- end
-
- def detect_regression_features row
- row.shift
- regression_features=false
- row.each_index do |i|
- value = row[i]
- type = feature_type(value)
- if type == OT.NumericFeature
- regression_features=true
- end
- end
- regression_features
- end
-
- def add_values(row, regression_features=false)
-
- smiles = row.shift
- compound = Compound.from_smiles(smiles)
- if compound.nil? or compound.inchi.nil? or compound.inchi == ""
- @smiles_errors << smiles+", "+row.join(", ")
- return false
- end
- @duplicates[compound.inchi] = [] unless @duplicates[compound.inchi]
- @duplicates[compound.inchi] << smiles+", "+row.join(", ")
-
- row.each_index do |i|
- value = row[i]
- feature = @features[i]
- type = feature_type(value)
-
- @feature_types[feature] << type
-
- if (regression_features)
- val = value.to_f
- else
- case type
- when OT.NominalFeature
- case value.to_s
- when TRUE_REGEXP
- val = true
- when FALSE_REGEXP
- val = false
- end
- when OT.NumericFeature
- val = value.to_f
- when OT.StringFeature
- val = value.to_s
- @activity_errors << smiles+", "+row.join(", ")
- end
- end
- if val!=nil
- @dataset.add(compound.uri, feature, val)
- if type!=OT.NumericFeature
- @dataset.features[feature][OT.acceptValue] = [] unless @dataset.features[feature][OT.acceptValue]
- @dataset.features[feature][OT.acceptValue] << val.to_s unless @dataset.features[feature][OT.acceptValue].include?(val.to_s)
- end
- end
- end
- end
-
- def numeric?(value)
- true if Float(value) rescue false
- end
-
- def classification?(value)
- !value.to_s.strip.match(TRUE_REGEXP).nil? or !value.to_s.strip.match(FALSE_REGEXP).nil?
- end
-
- def feature_type(value)
- if classification? value
- return OT.NominalFeature
- elsif numeric? value
- return OT.NumericFeature
- else
- return OT.StringFeature
- end
- end
-
- def split_row(row)
- row.chomp.gsub(/["']/,'').split(/\s*[,;]\s*/) # remove quotes
- end
-
- end
-=end
- end
-end
diff --git a/lib/rest_client_wrapper.rb b/lib/rest_client_wrapper.rb
deleted file mode 100644
index 30f04cc..0000000
--- a/lib/rest_client_wrapper.rb
+++ /dev/null
@@ -1,182 +0,0 @@
-require 'rest-client'
-module OpenTox
-
- class WrapperResult < String
- attr_accessor :content_type, :code
- end
-
- class RestClientWrapper
-
- # performs a GET REST call
- # raises OpenTox::Error if call fails (rescued in overwrite.rb -> halt 502)
- # per default: waits for Task to finish and returns result URI of Task
- # @param [String] uri destination URI
- # @param [optional,Hash] headers contains params like accept-header
- # @param [optional,OpenTox::Task] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
- # @param [wait,Boolean] wait set to false to NOT wait for task if result is task
- # @return [OpenTox::WrapperResult] a String containing the result-body of the REST call
- def self.get(uri, headers={}, waiting_task=nil, wait=true )
- execute( "get", uri, nil, headers, waiting_task, wait)
- end
-
- # performs a POST REST call
- # raises OpenTox::Error if call fails (rescued in overwrite.rb -> halt 502)
- # per default: waits for Task to finish and returns result URI of Task
- # @param [String] uri destination URI
- # @param [optional,String] payload data posted to the service
- # @param [optional,Hash] headers contains params like accept-header
- # @param [optional,OpenTox::Task] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
- # @param [wait,Boolean] wait set to false to NOT wait for task if result is task
- # @return [OpenTox::WrapperResult] a String containing the result-body of the REST call
- def self.post(uri, payload=nil, headers={}, waiting_task=nil, wait=true )
- execute( "post", uri, payload, headers, waiting_task, wait )
- end
-
- # performs a PUT REST call
- # raises OpenTox::Error if call fails (rescued in overwrite.rb -> halt 502)
- # @param [String] uri destination URI
- # @param [optional,Hash] headers contains params like accept-header
- # @param [optional,String] payload data put to the service
- # @return [OpenTox::WrapperResult] a String containing the result-body of the REST call
- def self.put(uri, payload=nil, headers={} )
- execute( "put", uri, payload, headers )
- end
-
- # performs a DELETE REST call
- # raises OpenTox::Error if call fails (rescued in overwrite.rb -> halt 502)
- # @param [String] uri destination URI
- # @param [optional,Hash] headers contains params like accept-header
- # @return [OpenTox::WrapperResult] a String containing the result-body of the REST call
- def self.delete(uri, headers=nil )
- execute( "delete", uri, nil, headers)
- end
-
- private
- def self.execute( rest_call, uri, payload=nil, headers={}, waiting_task=nil, wait=true )
-
- raise OpenTox::BadRequestError.new "uri is nil" unless uri
- raise OpenTox::BadRequestError.new "not a uri: "+uri.to_s unless uri.to_s.uri?
- raise "headers are no hash: "+headers.inspect unless headers==nil or headers.is_a?(Hash)
- raise OpenTox::BadRequestError.new "accept should go into the headers" if payload and payload.is_a?(Hash) and payload[:accept]
- raise OpenTox::BadRequestError.new "content_type should go into the headers" if payload and payload.is_a?(Hash) and payload[:content_type]
- raise "__waiting_task__ must be 'nil' or '(sub)task', is "+waiting_task.class.to_s if
- waiting_task!=nil and !(waiting_task.is_a?(Task) || waiting_task.is_a?(SubTask))
- headers.each{ |k,v| headers.delete(k) if v==nil } if headers #remove keys with empty values, as this can cause problems
- ## PENDING partner services accept subjectid only in header
- headers = {} unless headers
- headers[:subjectid] = payload.delete(:subjectid) if payload and payload.is_a?(Hash) and payload.has_key?(:subjectid)
-
- # PENDING needed for NUTA, until we finally agree on how to send subjectid
- headers[:subjectid] = payload.delete(:subjectid) if uri=~/ntua/ and payload and payload.is_a?(Hash) and payload.has_key?(:subjectid)
-
- begin
- #LOGGER.debug "RestCall: "+rest_call.to_s+" "+uri.to_s+" "+headers.inspect+" "+payload.inspect
- resource = RestClient::Resource.new(uri,{:timeout => 60})
- if rest_call=="post" || rest_call=="put"
- result = resource.send(rest_call, payload, headers)
- else
- result = resource.send(rest_call, headers)
- end
- #LOGGER.debug "result body size: #{result.body.size}"
-
- # PENDING NTUA does return errors with 200
- raise RestClient::ExceptionWithResponse.new(result) if uri=~/ntua/ and result.body =~ /about.*http:\/\/anonymous.org\/error/
-
- # result is a string, with the additional fields content_type and code
- res = WrapperResult.new(result.body)
- res.content_type = result.headers[:content_type]
- raise "content-type not set" unless res.content_type
- res.code = result.code
-
- # TODO: Ambit returns task representation with 200 instead of result URI
- return res if res.code==200 || !wait
-
- while (res.code==201 || res.code==202)
- res = wait_for_task(res, uri, waiting_task)
- end
- raise "illegal status code: '"+res.code.to_s+"'" unless res.code==200
- return res
-
- rescue RestClient::RequestTimeout => ex
- received_error ex.message, 408, nil, {:rest_uri => uri, :headers => headers, :payload => payload}
- rescue Errno::ETIMEDOUT => ex
- received_error ex.message, 408, nil, {:rest_uri => uri, :headers => headers, :payload => payload}
- rescue Errno::ECONNREFUSED => ex
- received_error ex.message, 500, nil, {:rest_uri => uri, :headers => headers, :payload => payload}
- rescue RestClient::ExceptionWithResponse => ex
- # error comming from a different webservice,
- received_error ex.http_body, ex.http_code, ex.response.net_http_res.content_type, {:rest_uri => uri, :headers => headers, :payload => payload}
- rescue OpenTox::RestCallError => ex
- # already a rest-error, probably comes from wait_for_task, just pass through
- raise ex
- rescue => ex
- # some internal error occuring in rest_client_wrapper, just pass through
- raise ex
- end
- end
-
- def self.wait_for_task( res, base_uri, waiting_task=nil )
- #TODO remove TUM hack
- res.content_type = "text/uri-list" if base_uri =~/tu-muenchen/ and res.content_type == "application/x-www-form-urlencoded;charset=UTF-8"
-
- task = nil
- case res.content_type
- when /application\/rdf\+xml/
- task = OpenTox::Task.from_rdfxml(res)
- when /yaml/
- task = OpenTox::Task.from_yaml(res)
- when /text\//
- raise "uri list has more than one entry, should be a task" if res.content_type=~/text\/uri-list/ and res.split("\n").size > 1 #if uri list contains more then one uri, its not a task
- task = OpenTox::Task.find(res.to_s.chomp) if res.to_s.uri?
- else
- raise "unknown content-type for task : '"+res.content_type.to_s+"'"+" base-uri: "+base_uri.to_s+" content: "+res[0..200].to_s
- end
-
- #LOGGER.debug "result is a task '"+task.uri.to_s+"', wait for completion"
- task.wait_for_completion waiting_task
- unless task.completed? # maybe task was cancelled / error
- if task.errorReport
- received_error task.errorReport, task.http_code, nil, {:rest_uri => task.uri, :rest_code => task.http_code}
- else
- raise "task status: '"+task.status.to_s+"' but errorReport nil"
- end
- end
-
- res = WrapperResult.new task.result_uri
- res.code = task.http_code
- res.content_type = "text/uri-list"
- return res
- end
-
- def self.received_error( body, code, content_type=nil, params=nil )
-
- # try to parse body
- report = nil
- if body.is_a?(OpenTox::ErrorReport)
- report = body
- else
- case content_type
- when /yaml/
- report = YAML.load(body)
- when /rdf/
- report = OpenTox::ErrorReport.from_rdf(body)
- end
- end
-
- unless report
- # parsing was not successfull
- # raise 'plain' RestCallError
- err = OpenTox::RestCallError.new("REST call returned error: '"+body.to_s+"'")
- err.rest_params = params
- raise err
- else
- # parsing sucessfull
- # raise RestCallError with parsed report as error cause
- err = OpenTox::RestCallError.new("REST call subsequent error")
- err.errorCause = report
- err.rest_params = params
- raise err
- end
- end
- end
-end
diff --git a/lib/serializer.rb b/lib/serializer.rb
deleted file mode 100644
index 5a9fd0a..0000000
--- a/lib/serializer.rb
+++ /dev/null
@@ -1,491 +0,0 @@
-require 'spreadsheet'
-require 'yajl'
-
-module OpenTox
-
- # Serialzer for various oputput formats
- module Serializer
-
- # OWL-DL Serializer, modelled according to to http://n2.talis.com/wiki/RDF_JSON_Specification
- class Owl
-
- attr_accessor :object
-
- def initialize
-
- @object = {
- # this should come from opentox.owl
- OT.Compound => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
- OT.Feature => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
- OT.Model => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
- OT.NominalFeature => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
- OT.NumericFeature => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
- OT.StringFeature => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
- OT.Dataset => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
- OT.DataEntry => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
- OT.FeatureValue => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
- OT.Algorithm => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
- OT.Parameter => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
- OT.Task => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
- OTA.PatternMiningSupervised => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
- OTA.ClassificationLazySingleTarget => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
- OTA.RegressionLazySingleTarget => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
-
- #classes for validation
- OT.Validation => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
- OT.ClassificationStatistics => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
- OT.ConfusionMatrix => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
- OT.ConfusionMatrixCell => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
- OT.ClassValueStatistics => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
- OT.RegressionStatistics => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
- OT.Crossvalidation => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
- OT.CrossvalidationInfo => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
- OT.ErrorReport => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } ,
-
- OT.compound => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
- OT.feature => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
- OT.dataEntry => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
- OT.values => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
- OT.algorithm => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
- OT.parameters => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
- OT.featureDataset => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
- OT.dependentVariables => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
- OT.predictedVariables => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
- OT.paramValue => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
-
- #object props for validation#
- OT.model => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
- OT.trainingDataset => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
- OT.predictionFeature => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
- OT.predictionDataset => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
- OT.crossvalidation => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
- OT.testTargetDataset => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
- OT.testDataset => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
- OT.classificationStatistics => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
- OT.confusionMatrix => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
- OT.confusionMatrixCell => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
- OT.classValueStatistics => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
- OT.regressionStatistics => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
- OT.validation => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
- OT.crossvalidationInfo => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
- OT.dataset => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } ,
-
- DC.title => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- DC.identifier => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- DC.contributor => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- DC.creator => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- DC.description => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- DC.date => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- #OT.isA => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.Warnings => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- XSD.anyURI => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.hasStatus => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.resultURI => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.percentageCompleted => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.acceptValue => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
-
- # annotation props for validation
- OT.numUnpredicted => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.crossvalidationFold => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.numInstances => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.numWithoutClass => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.percentWithoutClass => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.percentUnpredicted => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.confusionMatrixActual => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.confusionMatrixPredicted => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.confusionMatrixValue => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.numIncorrect => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.percentCorrect => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.numCorrect => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.accuracy => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.trueNegativeRate => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.truePositiveRate => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.falseNegativeRate => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.falsePositiveRate => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.numTrueNegatives => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.numTruePositives => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.numFalseNegatives => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.numFalsePositives => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.classValue => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.precision => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.areaUnderRoc => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.weightedAreaUnderRoc => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.weightedAccuracy => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.fMeasure => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.percentIncorrect => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.validationType => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.realRuntime => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.sampleCorrelationCoefficient => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.targetVarianceActual => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.targetVariancePredicted => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.meanAbsoluteError => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.sumSquaredError => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.rootMeanSquaredError => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.rSquare => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.stratified => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.numFolds => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.randomSeed => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.reportType => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.message => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.statusCode => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.actor => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
- OT.errorCode => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } ,
-
- OT.hasSource => { RDF["type"] => [{ "type" => "uri", "value" => OWL.DatatypeProperty }] } ,
- OT.value => { RDF["type"] => [{ "type" => "uri", "value" => OWL.DatatypeProperty }] } ,
- OT.paramScope => { RDF["type"] => [{ "type" => "uri", "value" => OWL.DatatypeProperty }] } ,
- #OT.paramValue => { RDF["type"] => [{ "type" => "uri", "value" => OWL.DatatypeProperty }] } ,
- }
-
- @data_entries = {}
- @values_id = 0
- @parameter_id = 0
-
- @classes = Set.new
- @object_properties = Set.new
- @annotation_properties = Set.new
- @datatype_properties = Set.new
-
- @objects = Set.new
- end
-
- # Add a compound
- # @param [String] uri Compound URI
- def add_compound(uri)
- @object[uri] = { RDF["type"] => [{ "type" => "uri", "value" => OT.Compound }] }
- end
-
- # Add a feature
- # @param [String] uri Feature URI
- def add_feature(uri,metadata)
- @object[uri] = { RDF["type"] => [{ "type" => "uri", "value" => OT.Feature }] }
- add_metadata uri, metadata
- end
-
- # Add a dataset
- # @param [String] uri Dataset URI
- def add_dataset(dataset)
- @dataset = dataset.uri
- @object[dataset.uri] = { RDF["type"] => [{ "type" => "uri", "value" => OT.Dataset }] }
- add_metadata dataset.uri, dataset.metadata
- dataset.compounds.each { |compound| add_compound compound }
- dataset.features.each { |feature,metadata| add_feature feature,metadata }
- dataset.data_entries.each do |compound,entry|
- entry.each do |feature,values|
- values.each { |value| add_data_entry compound,feature,value }
- end
- end
- end
-
- # Add a algorithm
- # @param [String] uri Algorithm URI
- def add_algorithm(uri,metadata)
- @object[uri] = { RDF["type"] => [{ "type" => "uri", "value" => OT.Algorithm }] }
- add_metadata uri, metadata
- end
-
- # Add a model
- # @param [String] uri Model URI
- def add_model(uri,metadata)
- @object[uri] = { RDF["type"] => [{ "type" => "uri", "value" => OT.Model }] }
- add_metadata uri, metadata
- @object[metadata[OT.featureDataset]] = { RDF["type"] => [{ "type" => "uri", "value" => OT.Dataset }] }
- @object[metadata[OT.trainingDataset]] = { RDF["type"] => [{ "type" => "uri", "value" => OT.Dataset }] }
- @object[metadata[OT.dependentVariables]] = { RDF["type"] => [{ "type" => "uri", "value" => OT.Feature }] }
- metadata[OT.predictedVariables].each{|feature| @object[feature] = { RDF["type"] => [{ "type" => "uri", "value" => OT.Feature }] }}
- # TODO: add algorithms from parameters
- @object["http://ot-dev.in-silico.ch/algorithm/fminer/bbrc"] = { RDF["type"] => [{ "type" => "uri", "value" => OT.Algorithm }] }
- @object["http://ot-dev.in-silico.ch/algorithm/fminer/last"] = { RDF["type"] => [{ "type" => "uri", "value" => OT.Algorithm }] }
- @object["http://ot-dev.in-silico.ch/algorithm/lazar"] = { RDF["type"] => [{ "type" => "uri", "value" => OT.Algorithm }] }
- end
-
- # Add a task
- # @param [String] uri Model URI
- def add_task(uri,metadata)
- @object[uri] = { RDF["type"] => [{ "type" => "uri", "value" => OT.Task }] }
- add_metadata uri, metadata
- end
-
- # Add a resource defined by resource_class and content
- # (see documentation of add_content for example)
- # @param [String] uri of resource
- # @param [String] resource class, e.g. OT.Validation
- # @param [Hash] content as hash
- def add_resource(uri, resource_class, content)
- @object[uri] = { RDF["type"] => [{ "type" => "uri", "value" => resource_class }] }
- @@content_id = 1
- add_content uri, content
- end
-
- private
- @@content_id = 1
-
- # Recursiv function to add content
- # @example
- # { DC.description => "bla",
- # OT.similar_resources => [ "http://uri1", "http://uri2" ],
- # OT.matrixCells =>
- # [ { RDF.type => OT.MatrixCell, OT.cellIndex=1 OT.cellValue => "xy" },
- # { RDF.type => OT.MatrixCell, OT.cellIndex=2 OT.cellValue => "z" } ],
- # OT.info => { RDF.type => OT.ImportantInfo,
- # DC.description => "blub" }
- # }
- # @param [String] uri
- # @param [Hash] content as hash, uri must already have been added to @object
- def add_content(uri, hash)
- raise "content is no hash: "+hash.class.to_s unless hash.is_a?(Hash)
- hash.each do |u,v|
- if v.is_a? Hash
- # value is again a hash, i.e. a new owl class is added
- # first make sure type (==class) is set
- type = v[RDF.type]
- raise "type missing for "+u.to_s+" content:\n"+v.inspect unless type
- raise "class unknown "+type.to_s+" (for "+u.to_s+")" unless @object.has_key?(type)
- # create new node and add to current uri
- genid = "_:#{type.split('#')[-1]}#{@@content_id}"
- @@content_id += 1
- @object[uri] = {} unless @object[uri]
- @object[uri][u] = [{ "type" => "bnode", "value" => genid }]
- # add content to new class
- add_content(genid,v)
- elsif v.is_a? Array
- # value is an array, i.e. a list of values with property is added
- v.each{ |vv| add_content( uri, { u => vv } ) }
- else # v.is_a? String
- # simple string value
- @object[uri] = {} unless @object[uri]
- @object[uri][u] = [] unless @object[uri][u]
- raise "property unknown "+u.to_s if !@object.has_key?(u) and u!=RDF.type
- # use << to allow different values for one property
- @object[uri][u] << {"type" => type(v), "value" => v }
- end
- end
- end
-
- public
-
- # Add metadata
- # @param [Hash] metadata
- def add_metadata(uri,metadata)
- id = 0
- metadata.each do |u,v|
- #if v.is_a? Array and (u == OT.parameters or u == RDF.type)
- if v.is_a? Array and u == OT.parameters#or u == RDF.type)
- @object[uri][u] = [] unless @object[uri][u]
- v.each do |value|
- id+=1
- genid = "_:genid#{id}"
- @object[uri][u] << {"type" => "bnode", "value" => genid}
- @object[genid] = { RDF["type"] => [{ "type" => "uri", "value" => OT.Parameter}] }
- value.each do |name,entry|
- @object[genid][name] = [{"type" => type(entry), "value" => entry }]
- end
- end
- elsif v.is_a? Array #and u == RDF.type
- @object[uri] = {} unless @object[uri]
- v.each do |value|
- @object[uri][u] = [] unless @object[uri][u]
- @object[uri][u] << {"type" => type(value), "value" => value }
- end
- elsif v.is_a? String
- @object[uri] = {} unless @object[uri]
- @object[uri][u] = [{"type" => type(v), "value" => v }]
- end
- end
- end
-
- # Add a data entry
- # @param [String] compound Compound URI
- # @param [String] feature Feature URI
- # @param [Boolead,Float] value Feature value
- def add_data_entry(compound,feature,value)
- add_compound(compound) unless @object[compound]
- add_feature(feature,{}) unless @object[feature]
- unless data_entry = @data_entries[compound]
- data_entry = "_:dataentry#{@data_entries.size}"
- @data_entries[compound] = data_entry
- @object[@dataset][OT.dataEntry] = [] unless @object[@dataset][OT.dataEntry]
- @object[@dataset][OT.dataEntry] << {"type" => "bnode", "value" => data_entry}
- @object[data_entry] = {
- RDF["type"] => [{ "type" => "uri", "value" => OT.DataEntry }],
- OT.compound => [{ "type" => "uri", "value" => compound }],
- OT.values => [],
- }
- end
- values = "_:values#{@values_id}"
- @values_id += 1
- @object[data_entry][OT.values] << {"type" => "bnode", "value" => values}
- case type(value)
- when "uri"
- v = [{ "type" => "uri", "value" => value}]
- when "literal"
- v = [{ "type" => "literal", "value" => value, "datatype" => datatype(value) }]
- else
- raise "Illegal type #{type(value)} for #{value}."
- end
- @object[values] = {
- RDF["type"] => [{ "type" => "uri", "value" => OT.FeatureValue }],
- OT.feature => [{ "type" => "uri", "value" => feature }],
- OT.value => v
- }
- @object[feature][RDF["type"]] << { "type" => "uri", "value" => featuretype(value) }
- #@object[feature][RDF["type"]] = { "type" => "uri", "value" => featuretype(value) }
- end
-
- # Serializers
-
- # Convert to N-Triples
- # @return [text/plain] Object OWL-DL in N-Triples format
- def to_ntriples
-
- @triples = Set.new
- @object.each do |s,entry|
- s = url(s) if type(s) == "uri"
- entry.each do |p,objects|
- p = url(p)
- objects.each do |o|
- case o["type"]
- when "uri"
- o = url(o["value"])
- when "literal"
- o = literal(o["value"],datatype(o["value"]))
- when "bnode"
- o = o["value"]
- end
- @triples << [s,p,o]
- end
- end
- end
- @triples.sort.collect{ |s| s.join(' ').concat(" .") }.join("\n")+"\n"
- end
-
- # Convert to RDF/XML
- # @return [text/plain] Object OWL-DL in RDF/XML format
- def to_rdfxml
- Tempfile.open("owl-serializer"){|f| f.write(self.to_ntriples); @path = f.path}
- # TODO: add base uri for ist services
- `rapper -i ntriples -f 'xmlns:ot="#{OT.uri}"' -f 'xmlns:ota="#{OTA.uri}"' -f 'xmlns:dc="#{DC.uri}"' -f 'xmlns:rdf="#{RDF.uri}"' -f 'xmlns:owl="#{OWL.uri}"' -o rdfxml #{@path} 2>/dev/null`
- end
-
- # Convert to JSON as specified in http://n2.talis.com/wiki/RDF_JSON_Specification
- # (Ambit services use a different JSON representation)
- # @return [text/plain] Object OWL-DL in JSON format
- def to_json
- #rdf_types
- Yajl::Encoder.encode(@object)
- end
-
- # Helpers for type detection
- private
-
- def datatype(value)
- if value.is_a? TrueClass or value.is_a? FalseClass
- XSD.boolean
- elsif value.is_a? Float
- XSD.float
- else
- XSD.string
- end
- end
-
- def featuretype(value)
- if value.is_a? TrueClass or value.is_a? FalseClass
- datatype = OT.NominalFeature
- elsif value.is_a? Float
- datatype = OT.NumericFeature
- else
- datatype = OT.StringFeature
- end
- end
-
- def type(value)
- begin
- uri = URI.parse(value)
- if uri.class == URI::HTTP or uri.class == URI::HTTPS
- "uri"
- elsif value.match(/^_/)
- "bnode"
- else
- "literal"
- end
- rescue
- "literal"
- end
- end
-
- def literal(value,type)
- # concat and << are faster string concatination operators than +
- '"'.concat(value.to_s).concat('"^^<').concat(type).concat('>')
- end
-
- def url(uri)
- # concat and << are faster string concatination operators than +
- '<'.concat(uri).concat('>')
- end
-
- def rdf_types
- @classes.each { |c| @object[c] = { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } }
- @object_properties.each { |p| @object[p] = { RDF["type"] => [{ "type" => "uri", "value" => OWL['ObjectProperty'] }] } }
- @annotation_properties.each { |a| @object[a] = { RDF["type"] => [{ "type" => "uri", "value" => OWL['AnnotationProperty'] }] } }
- @datatype_properties.each { |d| @object[d] = { RDF["type"] => [{ "type" => "uri", "value" => OWL['DatatypeProperty'] }] } }
- end
-
- end
-
- # Serializer for spreadsheet formats
- class Spreadsheets # to avoid nameclash with Spreadsheet gem
-
- # Create a new spreadsheet serializer
- # @param [OpenTox::Dataset] dataset Dataset object
- def initialize(dataset)
- @rows = []
- @rows << ["SMILES"]
- features = dataset.features.keys
- @rows.first << features
- @rows.first.flatten!
- dataset.data_entries.each do |compound,entries|
- smiles = Compound.new(compound).to_smiles
- row = Array.new(@rows.first.size)
- row[0] = smiles
- entries.each do |feature, values|
- i = features.index(feature)+1
- values.each do |value|
- if row[i]
- row[i] = "#{row[i]} #{value}" # multiple values
- else
- row[i] = value
- end
- end
- end
- @rows << row
- end
- end
-
- # Convert to CSV string
- # @return [String] CSV string
- def to_csv
- @rows.collect{|r| r.join(", ")}.join("\n")
- end
-
- # Convert to spreadsheet workbook
- # @return [Spreadsheet::Workbook] Workbook object (use the spreadsheet gemc to write a file)
- def to_spreadsheet
- Spreadsheet.client_encoding = 'UTF-8'
- book = Spreadsheet::Workbook.new
- sheet = book.create_worksheet(:name => '')
- sheet.column(0).width = 100
- i = 0
- @rows.each do |row|
- row.each do |c|
- sheet.row(i).push c
- end
- i+=1
- end
- book
- end
-
- end
-
-
- end
-end
diff --git a/lib/spork.rb b/lib/spork.rb
deleted file mode 100644
index c77b5b5..0000000
--- a/lib/spork.rb
+++ /dev/null
@@ -1,83 +0,0 @@
-# A way to cleanly handle process forking in Sinatra when using Passenger, aka "sporking some code".
-# This will allow you to properly execute some code asynchronously, which otherwise does not work correctly.
-#
-# Written by Ron Evans
-# More info at http://deadprogrammersociety.com
-#
-# Mostly lifted from the Spawn plugin for Rails (http://github.com/tra/spawn)
-# but with all of the Rails stuff removed.... cause you are using Sinatra. If you are using Rails, Spawn is
-# what you need. If you are using something else besides Sinatra that is Rack-based under Passenger, and you are having trouble with
-# asynch processing, let me know if spork helped you.
-#
-module Spork
- # things to close in child process
- @@resources = []
- def self.resources
- @@resources
- end
-
- # set the resource to disconnect from in the child process (when forking)
- def self.resource_to_close(resource)
- @@resources << resource
- end
-
- # close all the resources added by calls to resource_to_close
- def self.close_resources
- @@resources.each do |resource|
- resource.close if resource && resource.respond_to?(:close) && !resource.closed?
- end
- @@resources = []
- end
-
- # actually perform the fork... er, spork
- # valid options are:
- # :priority => to set the process priority of the child
- # :logger => a logger object to use from the child
- # :no_detach => true if you want to keep the child process under the parent control. usually you do NOT want this
- def self.spork(options={})
- logger = options[:logger]
- logger.debug "spork> parent PID = #{Process.pid}" if logger
-
- child = fork do
- begin
- start = Time.now
- logger.debug "spork> child PID = #{Process.pid}" if logger
-
- # set the nice priority if needed
- Process.setpriority(Process::PRIO_PROCESS, 0, options[:priority]) if options[:priority]
-
- # disconnect from the rack
- Spork.close_resources
-
- # run the block of code that takes so long
- yield
-
- rescue => ex
- #raise ex
- logger.error "spork> Exception in child[#{Process.pid}] - #{ex.class}: #{ex.message}" if logger
- ensure
- logger.info "spork> child[#{Process.pid}] took #{Time.now - start} sec" if logger
- # this form of exit doesn't call at_exit handlers
- exit!(0)
- end
- end
-
- # detach from child process (parent may still wait for detached process if they wish)
- Process.detach(child) unless options[:no_detach]
-
- return child
- end
-
-end
-
-# Patch to work with passenger
-if defined? Passenger::Rack::RequestHandler
- class Passenger::Rack::RequestHandler
- alias_method :orig_process_request, :process_request
- def process_request(env, input, output)
- Spork.resource_to_close(input)
- Spork.resource_to_close(output)
- orig_process_request(env, input, output)
- end
- end
-end
diff --git a/lib/task.rb b/lib/task.rb
index 3815177..0adb7a0 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -1,401 +1,72 @@
-
+DEFAULT_TASK_MAX_DURATION = 36000
module OpenTox
# Class for handling asynchronous tasks
class Task
- include OpenTox
- attr_accessor :http_code, :due_to_time
-
- def initialize(uri=nil)
- super uri
- @http_code = 202
- @metadata = {
- DC.title => "",
- DC.date => "",
- OT.hasStatus => "Running",
- OT.percentageCompleted => 0.0,
- OT.resultURI => "",
- DC.creator => "", # not mandatory according to API
- DC.description => "", # not mandatory according to API
- }
- end
-
- # Create a new task for the code in the block. Catches halts and exceptions and sets task state to error if necessary. The block has to return the URI of the created resource.
- # @example
- # task = OpenTox::Task.create do
- # # this code will be executed as a task
- # model = OpenTox::Algorithm.run(params) # this can be time consuming
- # model.uri # Important: return URI of the created resource
- # end
- # task.status # returns "Running", because tasks are forked
- # @param [String] title Task title
- # @param [String] creator Task creator
- # @return [OPenTox::Task] Task
- def self.create( title=nil, creator=nil, max_duration=DEFAULT_TASK_MAX_DURATION, description=nil )
-
- params = {:title=>title, :creator=>creator, :max_duration=>max_duration, :description=>description }
- task_uri = RestClientWrapper.post(CONFIG[:services]["opentox-task"], params, {}, nil, false).to_s
- task = Task.new(task_uri.chomp)
-
- # measure current memory consumption
-=begin
- memory = `free -m|sed -n '2p'`.split
- free_memory = memory[3].to_i + memory[6].to_i # include cache
- if free_memory < 20 # require at least 200 M free memory
- LOGGER.warn "Cannot start task - not enough memory left (#{free_memory} M free)"
- task.cancel
- return task
- #raise "Insufficient memory to start a new task"
- end
-
- cpu_load = `cat /proc/loadavg`.split(/\s+/)[0..2].collect{|c| c.to_f}
- nr_cpu_cores = `cat /proc/cpuinfo |grep "cpu cores"|cut -d ":" -f2|tr -d " "`.split("\n").collect{|c| c.to_i}.inject{|sum,n| sum+n}
- nr_cpu_cores = 1 if !nr_cpu_cores
- #if cpu_load[0] > nr_cpu_cores and cpu_load[0] > cpu_load[1] and cpu_load[1] > cpu_load[2] # average CPU load of the last minute is high and CPU load is increasing
- # LOGGER.warn "Cannot start task - CPU load too high (#{cpu_load.join(", ")})"
- # task.cancel
- # return task
- # #raise "Server too busy to start a new task"
- #end
-=end
- task_pid = Spork.spork(:logger => LOGGER) do
- LOGGER.debug "Task #{task.uri} started #{Time.now}"
- begin
- result = yield task
- LOGGER.debug "Task #{task.uri} done #{Time.now} -> "+result.to_s
- task.completed(result)
- rescue => error
- LOGGER.error "task failed: "+error.class.to_s+": "+error.message
- LOGGER.error ":\n"+error.backtrace.join("\n")
- task.error(OpenTox::ErrorReport.create(error, creator))
- end
- end
- task.pid = task_pid
- LOGGER.debug "Started task: "+task.uri.to_s
- task
- end
-
- # Find a task for querying, status changes
- # @param [String] uri Task URI
- # @return [OpenTox::Task] Task object
- def self.find(uri)
- return nil unless uri
- task = Task.new(uri)
- task.load_metadata
- raise "could not load task metadata" if task.metadata==nil or task.metadata.size==0
- task
- end
- # Find a task for querying, status changes
- # @param [String] uri Task URI
- # @return [OpenTox::Task] Task object
- def self.exist?(uri)
- begin
- return find(uri)
- rescue
- end
+ def self.create service_uri
+ Task.new RestClient.post(service_uri,{}).chomp
+ #eval("#{self}.new(\"#{uri}\", #{subjectid})")
end
- # Get a list of all tasks
- # @param [optional, String] uri URI of task service
- # @return [text/uri-list] Task URIs
- def self.all(uri=CONFIG[:services]["opentox-task"])
- OpenTox.all uri
- end
-
- def self.from_yaml(yaml)
- @metadata = YAML.load(yaml)
- end
-
- def self.from_rdfxml(rdfxml)
- owl = OpenTox::Parser::Owl.from_rdf(rdfxml, OT.Task)
- task = Task.new(owl.uri)
- task.add_metadata(owl.metadata)
- task
- end
-
- def to_rdfxml
- s = Serializer::Owl.new
- @metadata[OT.errorReport] = @uri+"/ErrorReport/tmpId" if @error_report
- s.add_task(@uri,@metadata)
- s.add_resource(@uri+"/ErrorReport/tmpId", OT.errorReport, @error_report.rdf_content) if @error_report
- s.to_rdfxml
+ def http_code
+ get(@uri).code
end
def status
- @metadata[OT.hasStatus]
+ metadata[RDF::OT.hasStatus].to_s
end
def result_uri
- @metadata[OT.resultURI]
+ metadata[RDF::OT.resultURI]
end
def description
- @metadata[DC.description]
+ metadata[RDF::DC.description]
end
def errorReport
- @metadata[OT.errorReport]
+ metadata[RDF::OT.errorReport]
end
def cancel
- RestClientWrapper.put(File.join(@uri,'Cancelled'),{:cannot_be => "empty"})
- load_metadata
+ RestClient.put(File.join(@uri,'Cancelled'),{:cannot_be => "empty"})
end
def completed(uri)
- RestClientWrapper.put(File.join(@uri,'Completed'),{:resultURI => uri})
- load_metadata
+ RestClient.put(File.join(@uri,'Completed'),{:resultURI => uri})
end
def error(error_report)
raise "no error report" unless error_report.is_a?(OpenTox::ErrorReport)
- RestClientWrapper.put(File.join(@uri,'Error'),{:errorReport => error_report.to_yaml})
- load_metadata
- end
-
- # not stored just for to_rdf
- def add_error_report( error_report )
- raise "not an error report: "+error_report.class.to_s unless error_report.is_a?(ErrorReport)
- @error_report = error_report
+ RestClient.put(File.join(@uri,'Error'),{:errorReport => error_report.to_yaml})
end
def pid=(pid)
- RestClientWrapper.put(File.join(@uri,'pid'), {:pid => pid})
+ RestClient.put(File.join(@uri,'pid'), {:pid => pid})
end
def running?
- @metadata[OT.hasStatus] == 'Running'
+ metadata[RDF::OT.hasStatus] == 'Running'
end
def completed?
- @metadata[OT.hasStatus] == 'Completed'
+ metadata[RDF::OT.hasStatus] == 'Completed'
end
def error?
- @metadata[OT.hasStatus] == 'Error'
+ metadata[RDF::OT.hasStatus] == 'Error'
end
- def load_metadata
- if (CONFIG[:yaml_hosts].include?(URI.parse(@uri).host))
- result = RestClientWrapper.get(@uri, {:accept => 'application/x-yaml'}, nil, false)
- @metadata = YAML.load result.to_s
- @http_code = result.code
- else
- @metadata = Parser::Owl::Generic.new(@uri).load_metadata
- @http_code = RestClientWrapper.get(uri, {:accept => 'application/rdf+xml'}, nil, false).code
- end
- raise "could not load task metadata for task "+@uri.to_s if @metadata==nil || @metadata.size==0
- end
-
- # create is private now, use OpenTox::Task.as_task
- #def self.create( params )
- #task_uri = RestClientWrapper.post(CONFIG[:services]["opentox-task"], params, {}, false).to_s
- #Task.find(task_uri.chomp)
- #end
-
-=begin
- def self.from_data(data, content_type, code, base_uri)
- task = Task.new(nil)
- task.http_code = code
- task.reload_from_data(data, content_type, base_uri)
- return task
- end
-
- def reload( accept_header=nil )
- unless accept_header
- if (CONFIG[:yaml_hosts].include?(URI.parse(uri).host))
- accept_header = "application/x-yaml"
- else
- accept_header = 'application/rdf+xml'
- end
- end
- result = RestClientWrapper.get(uri, {:accept => accept_header}, false)#'application/x-yaml'})
- @http_code = result.code
- reload_from_data(result, result.content_type, uri)
- end
-
- def reload_from_data( data, content_type, base_uri )
- case content_type
- when /yaml/
- task = YAML.load data
- TASK_ATTRIBS.each do |a|
- raise "task yaml data invalid, key missing: "+a.to_s unless task.has_key?(a)
- send("#{a.to_s}=".to_sym,task[a])
- end
- when /application\/rdf\+xml/
- owl = OpenTox::Owl.from_data(data,base_uri,"Task")
- self.uri = owl.uri
- (TASK_ATTRIBS-[:uri]).each{|a| self.send("#{a.to_s}=".to_sym, owl.get(a.to_s))}
- else
- raise "content type for tasks not supported: "+content_type.to_s
- end
- raise "uri is nil after loading" unless @uri and @uri.to_s.strip.size>0
- end
-=end
-
# waits for a task, unless time exceeds or state is no longer running
- # @param [optional,OpenTox::Task] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
# @param [optional,Numeric] dur seconds pausing before cheking again for completion
- def wait_for_completion( waiting_task=nil, dur=0.3)
-
- waiting_task.waiting_for(self.uri) if waiting_task
+ def wait_for_completion(dur=0.3)
due_to_time = Time.new + DEFAULT_TASK_MAX_DURATION
- LOGGER.debug "start waiting for task "+@uri.to_s+" at: "+Time.new.to_s+", waiting at least until "+due_to_time.to_s
-
- load_metadata # for extremely fast tasks
- check_state
while self.running?
- sleep dur
- load_metadata
- # if another (sub)task is waiting for self, set progress accordingly
- waiting_task.progress(@metadata[OT.percentageCompleted].to_f) if waiting_task
- check_state
- if (Time.new > due_to_time)
- raise "max wait time exceeded ("+DEFAULT_TASK_MAX_DURATION.to_s+"sec), task: '"+@uri.to_s+"'"
- end
- end
- waiting_task.waiting_for(nil) if waiting_task
- LOGGER.debug "Task '"+@metadata[OT.hasStatus].to_s+"': "+@uri.to_s+", Result: "+@metadata[OT.resultURI].to_s
- end
-
- # updates percentageCompleted value (can only be increased)
- # task has to be running
- # @param [Numeric] pct value between 0 and 100
- def progress(pct)
- #puts "task := "+pct.to_s
- raise "no numeric >= 0 and <= 100 : '"+pct.to_s+"'" unless pct.is_a?(Numeric) and pct>=0 and pct<=100
- if (pct > @metadata[OT.percentageCompleted] + 0.0001)
- RestClientWrapper.put(File.join(@uri,'Running'),{:percentageCompleted => pct})
- load_metadata
- end
- end
-
- def waiting_for(task_uri)
- RestClientWrapper.put(File.join(@uri,'Running'),{:waiting_for => task_uri})
- end
-
- private
- VALID_TASK_STATES = ["Cancelled", "Completed", "Running", "Error"]
-
- def check_state
- begin
- raise "illegal task state, invalid status: '"+@metadata[OT.hasStatus].to_s+"'" unless
- @metadata[OT.hasStatus] unless VALID_TASK_STATES.include?(@metadata[OT.hasStatus])
- raise "illegal task state, task is completed, resultURI is no URI: '"+@metadata[OT.resultURI].to_s+
- "'" unless @metadata[OT.resultURI] and @metadata[OT.resultURI].to_s.uri? if completed?
- if @http_code == 202
- raise "#{@uri}: illegal task state, code is 202, but hasStatus is not Running: '"+@metadata[OT.hasStatus]+"'" unless running?
- elsif @http_code == 201
- # ignore hasStatus
- # raise "#{@uri}: illegal task state, code is 201, but hasStatus is not Completed: '"+@metadata[OT.hasStatus]+"'" unless completed?
- raise "#{@uri}: illegal task state, code is 201, resultURI is no task-URI: '"+@metadata[OT.resultURI].to_s+
- "'" unless @metadata[OT.resultURI] and @metadata[OT.resultURI].to_s.uri?
- end
- rescue => ex
- raise OpenTox::BadRequestError.new ex.message+" (task-uri:"+@uri+")"
+ raise "max wait time exceeded ("+DEFAULT_TASK_MAX_DURATION.to_s+"sec), task: '"+@uri.to_s+"'" if (Time.new > due_to_time)
end
end
end
- # Convenience class to split a (sub)task into subtasks
- #
- # example:
- # a crossvalidation is split into creating datasets and performing the validations
- # creating the dataset is 1/3 of the work, perform the validations is 2/3:
- # Task.as_task do |task|
- # create_datasets( SubTask.new(task, 0, 33) )
- # perfom_validations( SubTask.new(task, 33, 100) )
- # end
- # inside the create_datasets / perform_validations you can use subtask.progress()
- # with vals from 0-100
- #
- # note that you can split a subtask into further subtasks
- class SubTask
-
- def initialize(task, min, max)
- raise "not a task or subtask" if task!=nil and !(task.is_a?(Task) or task.is_a?(SubTask))
- raise "invalid max ("+max.to_s+"), min ("+min.to_s+") params" unless
- min.is_a?(Numeric) and max.is_a?(Numeric) and min >= 0 and max <= 100 and max > min
- @task = task
- @min = min
- @max = max
- @delta = max - min
- end
-
- # convenience method to handle null tasks
- def self.create(task, min, max)
- if task
- SubTask.new(task, min, max)
- else
- nil
- end
- end
-
- def waiting_for(task_uri)
- @task.waiting_for(task_uri)
- end
-
- def progress(pct)
- raise "no numeric >= 0 and <= 100 : '"+pct.to_s+"'" unless pct.is_a?(Numeric) and pct>=0 and pct<=100
- #puts "subtask := "+pct.to_s+" -> task := "+(@min + @delta * pct.to_f * 0.01).to_s
- @task.progress( @min + @delta * pct.to_f * 0.01 )
- end
-
- def running?()
- @task.running?
- end
- end
-
-
- # The David Gallagher feature:
- # a fake sub task to keep the progress bar movin for external jobs
- # note: param could be a subtask
- #
- # usage (for a call that is normally finished in under 60 seconds):
- # fsk = FakeSubTask.new(task, 60)
- # external_lib_call.start
- # external_lib_call.wait_until_finished
- # fsk.finished
- #
- # what happens:
- # the FakeSubTask updates the task.progress each second until
- # runtime is up or the finished mehtod is called
- #
- # example if the param runtime is too low:
- # 25% .. 50% .. 75% .. 100% .. 100% .. 100% .. 100% .. 100%
- # example if the param runtime is too high:
- # 5% .. 10% .. 15% .. 20% .. 25% .. 30% .. 35% .. 100%
- # the latter example is better (keep the bar movin!)
- # -> better make a conservative runtime estimate
- class FakeSubTask
-
- def initialize(task, runtime)
- @task = task
- @thread = Thread.new do
- timeleft = runtime
- while (timeleft > 0 and @task.running?)
- sleep 1
- timeleft -= 1
- @task.progress( (runtime - timeleft) / runtime.to_f * 100 )
- end
- end
- end
-
- # convenience method to handle null tasks
- def self.create(task, runtime)
- if task
- FakeSubTask.new(task, runtime)
- else
- nil
- end
- end
-
- def finished
- @thread.exit
- @task.progress(100) if @task.running?
- end
- end
-
end
diff --git a/lib/to-html.rb b/lib/to-html.rb
deleted file mode 100644
index 04fa158..0000000
--- a/lib/to-html.rb
+++ /dev/null
@@ -1,109 +0,0 @@
-OT_LOGO = File.join(CONFIG[:services]["opentox-validation"],"resources/ot-logo.png")
-
-class String
-
- # encloses URI in text with with link tag
- # @return [String] new text with marked links
- def link_urls
- self.gsub(/(?i)http(s?):\/\/[^\r\n\s']*/, '\0')
- end
-end
-
-module OpenTox
-
- # produces a html page for making web services browser friendly
- # format of text (=string params) is preserved (e.g. line breaks)
- # urls are marked as links
- # @example post params:
- # [ [ [:mandatory_param_1], [:mandatory_param_2], [:optional_param,"default_value"] ],
- # [ [:alteranative_mandatory_param_1], [:alteranative_mandatory_param_2] ]
- # ]
- # @param [String] text this is the actual content,
- # @param [optional,String] related_links info on related resources
- # @param [optional,String] description general info
- # @param [optional,Array] post_params, array of arrays containing info on POST operation, see example
- # @return [String] html page
- def self.text_to_html( text, subjectid=nil, related_links=nil, description=nil, post_params=nil )
-
- # TODO add title as parameter
- title = nil #$sinatra.url_for($sinatra.request.env['PATH_INFO'], :full) if $sinatra
- html = ""
- html += ""+title+"" if title
- html += "<\/img>"
-
- if AA_SERVER
- user = OpenTox::Authorization.get_user(subjectid) if subjectid
- html += "
"
- unless user
- html += "You are currently not signed in to "+$url_provider.url_for("",:full)+
- ", sign in"
- else
- html += "You are signed in as '#{user}' to "+$url_provider.url_for("",:full)+
- ", sign out"
- end
- html += "
"
- end
-
- html += "
Description
"+description.link_urls+"
" if description
- html += "
Related links
"+related_links.link_urls+"
" if related_links
- if post_params
- html += "
POST parameters
"
- count = 0
- post_params.each do |p|
- html += "
alternatively:
" if count > 0
- html += "
param
default_value
"
- p.each do |k,v|
- html += "
"+k.to_s+"
"+(v!=nil ? v.to_s : "mandatory")+"
"
- end
- html += "
"
- count += 1
- end
- end
- html += "
Content
" if description || related_links
- html += "
"
- html += text.link_urls
- html += "
"
- html
- end
-
- def self.sign_in( msg=nil )
- html = "Login"
- html += ""
- html
- end
-end
-
-get '/sign_out/?' do
- response.set_cookie("subjectid",{:value=>nil})
- content_type "text/html"
- content = "Sucessfully signed out from "+$url_provider.url_for("",:full)
- OpenTox.text_to_html(content)
-end
-
-get '/sign_in/?' do
- content_type "text/html"
- OpenTox.sign_in
-end
-
-post '/sign_in/?' do
- subjectid = OpenTox::Authorization.authenticate(params[:user], params[:password])
- if (subjectid)
- response.set_cookie("subjectid",{:value=>subjectid})
- content_type "text/html"
- content = "Sucessfully signed in as '"+params[:user]+"' to "+$url_provider.url_for("",:full)
- OpenTox.text_to_html(content,subjectid)
- else
- content_type "text/html"
- OpenTox.sign_in("Login failed, please try again")
- end
-end
-
diff --git a/lib/validation.rb b/lib/validation.rb
deleted file mode 100644
index d7a337c..0000000
--- a/lib/validation.rb
+++ /dev/null
@@ -1,313 +0,0 @@
-module OpenTox
- class Validation
- include OpenTox
-
- # find validation, raises error if not found
- # @param [String] uri
- # @param [String,optional] subjectid
- # @return [OpenTox::Validation]
- def self.find( uri, subjectid=nil )
- val = Validation.new(uri)
- val.load_metadata( subjectid )
- val
- end
-
- # returns a filtered list of validation uris
- # @param [Hash,optional] params, validation-params to filter the uris (could be model, training_dataset, ..)
- # @return [Array]
- def self.list( params={} )
- filter_string = ""
- params.each do |k,v|
- filter_string = "?" if filter_string.length==0
- filter_string += k.to_s+"="+v
- end
- (OpenTox::RestClientWrapper.get(CONFIG[:services]["opentox-validation"]+filter_string).split("\n"))
- end
-
- # creates a training test split validation, waits until it finishes, may take some time
- # @param [Hash] params (required:algorithm_uri,dataset_uri,prediction_feature, optional:algorithm_params,split_ratio(0.67),random_seed(1))
- # @param [String,optional] subjectid
- # @param [OpenTox::Task,optional] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
- # @return [OpenTox::Validation]
- def self.create_training_test_split( params, subjectid=nil, waiting_task=nil )
- params[:subjectid] = subjectid if subjectid
- uri = OpenTox::RestClientWrapper.post( File.join(CONFIG[:services]["opentox-validation"],"training_test_split"),
- params,{:content_type => "text/uri-list"},waiting_task )
- Validation.new(uri)
- end
-
- # looks for report for this validation, creates a report if no report is found
- # @param [String,optional] subjectid
- # @param [OpenTox::Task,optional] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
- # @return [String] report uri
- def find_or_create_report( subjectid=nil, waiting_task=nil )
- @report = ValidationReport.find_for_validation(@uri, subjectid) unless @report
- @report = ValidationReport.create(@uri, subjectid, waiting_task) unless @report
- @report.uri
- end
-
- # creates a validation object from crossvaldiation statistics, raise error if not found
- # (as crossvaldiation statistics are returned as an average valdidation over all folds)
- # @param [String] crossvalidation uri
- # @param [String,optional] subjectid
- # @return [OpenTox::Validation]
- def self.from_cv_statistics( crossvalidation_uri, subjectid=nil )
- find( File.join(crossvalidation_uri, 'statistics'),subjectid )
- end
-
- # loads metadata via yaml from validation object
- # fields (like for example the validated model) can be acces via validation.metadata[OT.model]
- def load_metadata( subjectid=nil )
- @metadata = YAML.load(OpenTox::RestClientWrapper.get(uri,{:subjectid => subjectid, :accept => "application/x-yaml"}))
- end
-
- # PENDING: creates summary as used for ToxCreate
- def summary
- if @metadata[OT.classificationStatistics]
- res = {
- :nr_predictions => @metadata[OT.numInstances].to_i - @metadata[OT.numUnpredicted].to_i,
- :correct_predictions => @metadata[OT.classificationStatistics][OT.percentCorrect],
- :weighted_area_under_roc => @metadata[OT.classificationStatistics][OT.weightedAreaUnderRoc],
- }
- @metadata[OT.classificationStatistics][OT.classValueStatistics].each do |s|
- if s[OT.classValue].to_s=="true"
- res[:true_positives] = s[OT.numTruePositives]
- res[:false_positives] = s[OT.numFalsePositives]
- res[:true_negatives] = s[OT.numTrueNegatives]
- res[:false_negatives] = s[OT.numFalseNegatives]
- res[:sensitivity] = s[OT.truePositiveRate]
- res[:specificity] = s[OT.trueNegativeRate]
- break
- end
- end
- res
- elsif @metadata[OT.regressionStatistics]
- {
- :nr_predictions => @metadata[OT.numInstances].to_i - @metadata[OT.numUnpredicted].to_i,
- :r_square => @metadata[OT.regressionStatistics][OT.rSquare],
- :root_mean_squared_error => @metadata[OT.regressionStatistics][OT.rootMeanSquaredError],
- :mean_absolute_error => @metadata[OT.regressionStatistics][OT.meanAbsoluteError],
- }
- end
- end
- end
-
- class Crossvalidation
- include OpenTox
-
- attr_reader :report
-
- # find crossvalidation, raises error if not found
- # @param [String] uri
- # @param [String,optional] subjectid
- # @return [OpenTox::Crossvalidation]
- def self.find( uri, subjectid=nil )
- cv = Crossvalidation.new(uri)
- cv.load_metadata( subjectid )
- cv
- end
-
- # returns a filtered list of crossvalidation uris
- # @param [Hash,optional] params, crossvalidation-params to filter the uris (could be algorithm, dataset, ..)
- # @return [Array]
- def self.list( params={} )
- filter_string = ""
- params.each do |k,v|
- filter_string = "?" if filter_string.length==0
- filter_string += k.to_s+"="+v
- end
- (OpenTox::RestClientWrapper.get(File.join(CONFIG[:services]["opentox-validation"],"crossvalidation")+filter_string).split("\n"))
- end
-
- # creates a crossvalidations, waits until it finishes, may take some time
- # @param [Hash] params (required:algorithm_uri,dataset_uri,prediction_feature, optional:algorithm_params,num_folds(10),random_seed(1),stratified(false))
- # @param [String,optional] subjectid
- # @param [OpenTox::Task,optional] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
- # @return [OpenTox::Crossvalidation]
- def self.create( params, subjectid=nil, waiting_task=nil )
- params[:subjectid] = subjectid if subjectid
- uri = OpenTox::RestClientWrapper.post( File.join(CONFIG[:services]["opentox-validation"],"crossvalidation"),
- params,{:content_type => "text/uri-list"},waiting_task )
- Crossvalidation.new(uri)
- end
-
- # looks for report for this crossvalidation, creates a report if no report is found
- # @param [String,optional] subjectid
- # @param [OpenTox::Task,optional] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
- # @return [String] report uri
- def find_or_create_report( subjectid=nil, waiting_task=nil )
- @report = CrossvalidationReport.find_for_crossvalidation(@uri, subjectid) unless @report
- @report = CrossvalidationReport.create(@uri, subjectid, waiting_task) unless @report
- @report.uri
- end
-
- # loads metadata via yaml from crossvalidation object
- # fields (like for example the validations) can be acces via validation.metadata[OT.validation]
- def load_metadata( subjectid=nil )
- @metadata = YAML.load(OpenTox::RestClientWrapper.get(uri,{:subjectid => subjectid, :accept => "application/x-yaml"}))
- end
-
- # PENDING: creates summary as used for ToxCreate
- def summary( subjectid=nil )
- Validation.from_cv_statistics( @uri, subjectid ).summary
- end
- end
-
- class ValidationReport
- include OpenTox
-
- # finds ValidationReport via uri, raises error if not found
- # @param [String] uri
- # @param [String,optional] subjectid
- # @return [OpenTox::ValidationReport]
- def self.find( uri, subjectid=nil )
- OpenTox::RestClientWrapper.get(uri,{:subjectid => subjectid})
- rep = ValidationReport.new(uri)
- rep.load_metadata( subjectid )
- rep
- end
-
- # finds ValidationReport for a particular validation
- # @param [String] crossvalidation uri
- # @param [String,optional] subjectid
- # @return [OpenTox::ValidationReport] nil if no report found
- def self.find_for_validation( validation_uri, subjectid=nil )
- uris = RestClientWrapper.get(File.join(CONFIG[:services]["opentox-validation"],
- "/report/validation?validation="+validation_uri), {:subjectid => subjectid}).chomp.split("\n")
- uris.size==0 ? nil : ValidationReport.new(uris[-1])
- end
-
- # creates a validation report via validation
- # @param [String] validation uri
- # @param [String,optional] subjectid
- # @param [OpenTox::Task,optional] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
- # @return [OpenTox::ValidationReport]
- def self.create( validation_uri, subjectid=nil, waiting_task=nil )
- uri = RestClientWrapper.post(File.join(CONFIG[:services]["opentox-validation"],"/report/validation"),
- { :validation_uris => validation_uri, :subjectid => subjectid }, {}, waiting_task )
- ValidationReport.new(uri)
- end
-
- end
-
- class CrossvalidationReport
- include OpenTox
-
- # finds CrossvalidationReport via uri, raises error if not found
- # @param [String] uri
- # @param [String,optional] subjectid
- # @return [OpenTox::CrossvalidationReport]
- def self.find( uri, subjectid=nil )
- OpenTox::RestClientWrapper.get(uri,{:subjectid => subjectid})
- rep = CrossvalidationReport.new(uri)
- rep.load_metadata( subjectid )
- rep
- end
-
- # finds CrossvalidationReport for a particular crossvalidation
- # @param [String] crossvalidation uri
- # @param [String,optional] subjectid
- # @return [OpenTox::CrossvalidationReport] nil if no report found
- def self.find_for_crossvalidation( crossvalidation_uri, subjectid=nil )
- uris = RestClientWrapper.get(File.join(CONFIG[:services]["opentox-validation"],
- "/report/crossvalidation?crossvalidation="+crossvalidation_uri), {:subjectid => subjectid}).chomp.split("\n")
- uris.size==0 ? nil : CrossvalidationReport.new(uris[-1])
- end
-
- # creates a crossvalidation report via crossvalidation
- # @param [String] crossvalidation uri
- # @param [String,optional] subjectid
- # @param [OpenTox::Task,optional] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
- # @return [OpenTox::CrossvalidationReport]
- def self.create( crossvalidation_uri, subjectid=nil, waiting_task=nil )
- uri = RestClientWrapper.post(File.join(CONFIG[:services]["opentox-validation"],"/report/crossvalidation"),
- { :validation_uris => crossvalidation_uri, :subjectid => subjectid }, {}, waiting_task )
- CrossvalidationReport.new(uri)
- end
- end
-
-
- class AlgorithmComparisonReport
- include OpenTox
-
- # finds AlgorithmComparisonReport via uri, raises error if not found
- # @param [String] uri
- # @param [String,optional] subjectid
- # @return [OpenTox::CrossvalidationReport]
- def self.find( uri, subjectid=nil )
- OpenTox::RestClientWrapper.get(uri,{:subjectid => subjectid})
- rep = AlgorithmComparisonReport.new(uri)
- rep.load_metadata( subjectid )
- rep
- end
-
- # finds AlgorithmComparisonReport for a particular crossvalidation
- # @param [String] crossvalidation uri
- # @param [String,optional] subjectid
- # @return [OpenTox::AlgorithmComparisonReport] nil if no report found
- def self.find_for_crossvalidation( crossvalidation_uri, subjectid=nil )
- uris = RestClientWrapper.get(File.join(CONFIG[:services]["opentox-validation"],
- "/report/algorithm_comparison?crossvalidation="+crossvalidation_uri), {:subjectid => subjectid}).chomp.split("\n")
- uris.size==0 ? nil : AlgorithmComparisonReport.new(uris[-1])
- end
-
- # creates a crossvalidation report via crossvalidation
- # @param [Hash] crossvalidation uri_hash, see example
- # @param [String,optional] subjectid
- # @param [OpenTox::Task,optional] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
- # @return [OpenTox::AlgorithmComparisonReport]
- # example for hash:
- # { :lazar-bbrc => [ http://host/validation/crossvalidation/x1, http://host/validation/crossvalidation/x2 ],
- # :lazar-last => [ http://host/validation/crossvalidation/xy, http://host/validation/crossvalidation/xy ] }
- def self.create( crossvalidation_uri_hash, subjectid=nil, waiting_task=nil )
- identifier = []
- validation_uris = []
- crossvalidation_uri_hash.each do |id, uris|
- uris.each do |uri|
- identifier << id
- validation_uris << uri
- end
- end
- uri = RestClientWrapper.post(File.join(CONFIG[:services]["opentox-validation"],"/report/algorithm_comparison"),
- { :validation_uris => validation_uris.join(","), :identifier => identifier.join(","), :subjectid => subjectid }, {}, waiting_task )
- AlgorithmComparisonReport.new(uri)
- end
- end
-
- class QMRFReport
- include OpenTox
-
- # finds QMRFReport, raises Error if not found
- # @param [String] uri
- # @param [String,optional] subjectid
- # @return [OpenTox::QMRFReport]
- def self.find( uri, subjectid=nil )
- # PENDING load crossvalidation data?
- OpenTox::RestClientWrapper.get(uri,{:subjectid => subjectid})
- QMRFReport.new(uri)
- end
-
- # finds QMRF report for a particular model
- # @param [String] model_uri
- # @param [String,optional] subjectid
- # @return [OpenTox::QMRFReport] nil if no report found
- def self.find_for_model( model_uri, subjectid=nil )
- uris = RestClientWrapper.get(File.join(CONFIG[:services]["opentox-validation"],
- "/reach_report/qmrf?model="+model_uri), {:subjectid => subjectid}).chomp.split("\n")
- uris.size==0 ? nil : QMRFReport.new(uris[-1])
- end
-
- # creates a qmrf report via model
- # @param [String] model_uri
- # @param [String,optional] subjectid
- # @param [OpenTox::Task,optional] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
- # @return [OpenTox::QMRFReport]
- def self.create( model_uri, subjectid=nil, waiting_task=nil )
- uri = RestClientWrapper.post(File.join(CONFIG[:services]["opentox-validation"],"/reach_report/qmrf"),
- { :model_uri => model_uri, :subjectid => subjectid }, {}, waiting_task )
- QMRFReport.new(uri)
- end
- end
-
-end
-
--
cgit v1.2.3
From 9ed209b262e0b540af967e24e9b9845600a0669c Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Wed, 15 Feb 2012 18:06:46 +0100
Subject: tests fixed for new task api
---
lib/error.rb | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
lib/spork.rb | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++
lib/task.rb | 68 +++++++++++++++++------------------------
3 files changed, 210 insertions(+), 40 deletions(-)
create mode 100644 lib/error.rb
create mode 100644 lib/spork.rb
(limited to 'lib')
diff --git a/lib/error.rb b/lib/error.rb
new file mode 100644
index 0000000..b92f2a4
--- /dev/null
+++ b/lib/error.rb
@@ -0,0 +1,99 @@
+
+# adding additional fields to Exception class to format errors according to OT-API
+class Exception
+ attr_accessor :errorCause
+ def http_code; 500; end
+end
+
+module OpenTox
+
+ class BadRequestError < RuntimeError
+ def http_code; 400; end
+ end
+
+ class NotAuthorizedError < RuntimeError
+ def http_code; 401; end
+ end
+
+ class NotFoundError < RuntimeError
+ def http_code; 404; end
+ end
+
+ class ServiceUnavailableError < RuntimeError
+ def http_code; 503; end
+ end
+
+ class RestCallError < RuntimeError
+ attr_accessor :rest_params
+ def http_code; 502; end
+ end
+
+ class ErrorReport
+
+ # TODO replace params with URIs (errorCause -> OT.errorCause)
+ attr_reader :message, :actor, :errorCause, :http_code, :errorDetails, :errorType
+
+ private
+ def initialize( http_code, erroType, message, actor, errorCause, rest_params=nil, backtrace=nil )
+ @http_code = http_code
+ @errorType = erroType
+ @message = message
+ @actor = actor
+ @errorCause = errorCause
+ @rest_params = rest_params
+ @backtrace = backtrace
+ end
+
+ public
+ # creates a error report object, from an ruby-exception object
+ # @param [Exception] error
+ # @param [String] actor, URI of the call that cause the error
+ def self.create( error, actor )
+ rest_params = error.rest_params if error.is_a?(OpenTox::RestCallError) and error.rest_params
+ backtrace = error.backtrace.short_backtrace if CONFIG[:backtrace]
+ ErrorReport.new( error.http_code, error.class.to_s, error.message, actor, error.errorCause, rest_params, backtrace )
+ end
+
+ def self.from_rdf(rdf)
+ metadata = OpenTox::Parser::Owl.from_rdf( rdf, OT.ErrorReport ).metadata
+ ErrorReport.new(metadata[OT.statusCode], metadata[OT.errorCode], metadata[OT.message], metadata[OT.actor], metadata[OT.errorCause])
+ end
+
+ # overwrite sorting to make easier readable
+ def to_yaml_properties
+ p = super
+ p = ( p - ["@backtrace"]) + ["@backtrace"] if @backtrace
+ p = ( p - ["@errorCause"]) + ["@errorCause"] if @errorCause
+ p
+ end
+
+ def rdf_content()
+ c = {
+ RDF.type => [OT.ErrorReport],
+ OT.statusCode => @http_code,
+ OT.message => @message,
+ OT.actor => @actor,
+ OT.errorCode => @errorType,
+ }
+ c[OT.errorCause] = @errorCause.rdf_content if @errorCause
+ c
+ end
+
+ def to_rdfxml
+ s = Serializer::Owl.new
+ s.add_resource(CONFIG[:services]["opentox-task"]+"/tmpId/ErrorReport/tmpId", OT.errorReport, rdf_content)
+ s.to_rdfxml
+ end
+ end
+end
+
+class Array
+ def short_backtrace
+ short = []
+ each do |c|
+ break if c =~ /sinatra\/base/
+ short << c
+ end
+ short.join("\n")
+ end
+end
diff --git a/lib/spork.rb b/lib/spork.rb
new file mode 100644
index 0000000..c77b5b5
--- /dev/null
+++ b/lib/spork.rb
@@ -0,0 +1,83 @@
+# A way to cleanly handle process forking in Sinatra when using Passenger, aka "sporking some code".
+# This will allow you to properly execute some code asynchronously, which otherwise does not work correctly.
+#
+# Written by Ron Evans
+# More info at http://deadprogrammersociety.com
+#
+# Mostly lifted from the Spawn plugin for Rails (http://github.com/tra/spawn)
+# but with all of the Rails stuff removed.... cause you are using Sinatra. If you are using Rails, Spawn is
+# what you need. If you are using something else besides Sinatra that is Rack-based under Passenger, and you are having trouble with
+# asynch processing, let me know if spork helped you.
+#
+module Spork
+ # things to close in child process
+ @@resources = []
+ def self.resources
+ @@resources
+ end
+
+ # set the resource to disconnect from in the child process (when forking)
+ def self.resource_to_close(resource)
+ @@resources << resource
+ end
+
+ # close all the resources added by calls to resource_to_close
+ def self.close_resources
+ @@resources.each do |resource|
+ resource.close if resource && resource.respond_to?(:close) && !resource.closed?
+ end
+ @@resources = []
+ end
+
+ # actually perform the fork... er, spork
+ # valid options are:
+ # :priority => to set the process priority of the child
+ # :logger => a logger object to use from the child
+ # :no_detach => true if you want to keep the child process under the parent control. usually you do NOT want this
+ def self.spork(options={})
+ logger = options[:logger]
+ logger.debug "spork> parent PID = #{Process.pid}" if logger
+
+ child = fork do
+ begin
+ start = Time.now
+ logger.debug "spork> child PID = #{Process.pid}" if logger
+
+ # set the nice priority if needed
+ Process.setpriority(Process::PRIO_PROCESS, 0, options[:priority]) if options[:priority]
+
+ # disconnect from the rack
+ Spork.close_resources
+
+ # run the block of code that takes so long
+ yield
+
+ rescue => ex
+ #raise ex
+ logger.error "spork> Exception in child[#{Process.pid}] - #{ex.class}: #{ex.message}" if logger
+ ensure
+ logger.info "spork> child[#{Process.pid}] took #{Time.now - start} sec" if logger
+ # this form of exit doesn't call at_exit handlers
+ exit!(0)
+ end
+ end
+
+ # detach from child process (parent may still wait for detached process if they wish)
+ Process.detach(child) unless options[:no_detach]
+
+ return child
+ end
+
+end
+
+# Patch to work with passenger
+if defined? Passenger::Rack::RequestHandler
+ class Passenger::Rack::RequestHandler
+ alias_method :orig_process_request, :process_request
+ def process_request(env, input, output)
+ Spork.resource_to_close(input)
+ Spork.resource_to_close(output)
+ orig_process_request(env, input, output)
+ end
+ end
+end
diff --git a/lib/task.rb b/lib/task.rb
index 0adb7a0..aee6c62 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -1,62 +1,31 @@
+require File.join(File.dirname(__FILE__),'spork')
DEFAULT_TASK_MAX_DURATION = 36000
module OpenTox
# Class for handling asynchronous tasks
class Task
-
- def self.create service_uri
- Task.new RestClient.post(service_uri,{}).chomp
- #eval("#{self}.new(\"#{uri}\", #{subjectid})")
- end
-
- def http_code
- get(@uri).code
- end
-
- def status
- metadata[RDF::OT.hasStatus].to_s
- end
-
- def result_uri
- metadata[RDF::OT.resultURI]
+ def self.create service_uri, params={}
+ task = Task.new RestClient.post(service_uri,params).chomp
+ pid = Spork.spork { yield }
+ task.pid = pid
+ task
end
def description
metadata[RDF::DC.description]
end
- def errorReport
- metadata[RDF::OT.errorReport]
- end
-
def cancel
- RestClient.put(File.join(@uri,'Cancelled'),{:cannot_be => "empty"})
+ RestClient.put(File.join(@uri,'Cancelled'),{})
end
def completed(uri)
RestClient.put(File.join(@uri,'Completed'),{:resultURI => uri})
end
- def error(error_report)
- raise "no error report" unless error_report.is_a?(OpenTox::ErrorReport)
- RestClient.put(File.join(@uri,'Error'),{:errorReport => error_report.to_yaml})
- end
-
- def pid=(pid)
- RestClient.put(File.join(@uri,'pid'), {:pid => pid})
- end
-
- def running?
- metadata[RDF::OT.hasStatus] == 'Running'
- end
-
- def completed?
- metadata[RDF::OT.hasStatus] == 'Completed'
- end
-
- def error?
- metadata[RDF::OT.hasStatus] == 'Error'
+ def error(error)
+ RestClient.put(File.join(@uri,'Error'),{:errorReport => OpenTox::Error.new(error)})
end
# waits for a task, unless time exceeds or state is no longer running
@@ -69,4 +38,23 @@ module OpenTox
end
end
+ def method_missing(method,*args)
+ method = method.to_s
+ begin
+ case method
+ when /=/
+ res = RestClient.put(File.join(@uri,method.sub(/=/,'')),{})
+ super unless res.code == 200
+ when /\?/
+ return metadata[RDF::OT.hasStatus] == method.sub(/\?/,'').capitalize
+ else
+ return metadata[RDF::OT[method]].to_s
+ end
+ rescue
+ super
+ end
+ end
+
+ #TODO: subtasks
+
end
--
cgit v1.2.3
From 6d88f38d61dbabd355a48e65bb49e94ba87a350c Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Wed, 15 Feb 2012 22:53:14 +0000
Subject: empty subjectids fixed, adjustments for ree 1.8.7
---
lib/opentox-client.rb | 9 +++++----
lib/opentox.rb | 4 ++--
2 files changed, 7 insertions(+), 6 deletions(-)
(limited to 'lib')
diff --git a/lib/opentox-client.rb b/lib/opentox-client.rb
index bc297b5..7c7fb11 100644
--- a/lib/opentox-client.rb
+++ b/lib/opentox-client.rb
@@ -1,7 +1,8 @@
+require 'rubygems'
require 'rdf'
require 'rdf/raptor'
require "rest-client"
-require "opentox"
-require "task"
-require "compound"
-require "dataset"
+require File.join(File.dirname(__FILE__),"opentox.rb")
+require File.join(File.dirname(__FILE__),"task.rb")
+require File.join(File.dirname(__FILE__),"compound.rb")
+require File.join(File.dirname(__FILE__),"dataset.rb")
diff --git a/lib/opentox.rb b/lib/opentox.rb
index a9cbeab..51bc17a 100644
--- a/lib/opentox.rb
+++ b/lib/opentox.rb
@@ -154,7 +154,7 @@ module OpenTox
def create service_uri, subjectid=nil
uri = RestClient.post(service_uri, {}, :subjectid => subjectid).chomp
- eval("#{self}.new(\"#{uri}\", #{subjectid})")
+ subjectid ? eval("#{self}.new(\"#{uri}\", #{subjectid})") : eval("#{self}.new(\"#{uri}\")")
end
def from_file service_uri, file, subjectid=nil
@@ -163,7 +163,7 @@ module OpenTox
def all service_uri, subjectid=nil
uris = RestClient.get(service_uri, {:accept => 'text/uri-list'}).split("\n").compact
- uris.collect{|uri| eval "#{self}.new(\"#{uri}\", #{subjectid})"}
+ uris.collect{|uri| subjectid ? eval("#{self}.new(\"#{uri}\", #{subjectid})") : eval("#{self}.new(\"#{uri}\")")}
end
end
--
cgit v1.2.3
From 6cacf7bbc3545ed87e21d0ca5a19ab4300699fdc Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Thu, 16 Feb 2012 15:10:19 +0000
Subject: bundler instead of jeweller for gem management
---
lib/opentox-client/version.rb | 5 +++++
1 file changed, 5 insertions(+)
create mode 100644 lib/opentox-client/version.rb
(limited to 'lib')
diff --git a/lib/opentox-client/version.rb b/lib/opentox-client/version.rb
new file mode 100644
index 0000000..d90a728
--- /dev/null
+++ b/lib/opentox-client/version.rb
@@ -0,0 +1,5 @@
+module Opentox
+ module Client
+ VERSION = "0.0.1"
+ end
+end
--
cgit v1.2.3
From 0600fdc62e7446caa75ffcff4d097338818e0df9 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Thu, 16 Feb 2012 22:17:50 +0000
Subject: Task.wait_for_completion fixed
---
lib/opentox-client.rb | 2 ++
lib/task.rb | 11 +++++++++--
2 files changed, 11 insertions(+), 2 deletions(-)
(limited to 'lib')
diff --git a/lib/opentox-client.rb b/lib/opentox-client.rb
index 7c7fb11..0bd048c 100644
--- a/lib/opentox-client.rb
+++ b/lib/opentox-client.rb
@@ -1,4 +1,6 @@
+require "opentox-client/version"
require 'rubygems'
+require "bundler/setup"
require 'rdf'
require 'rdf/raptor'
require "rest-client"
diff --git a/lib/task.rb b/lib/task.rb
index aee6c62..50616d7 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -7,7 +7,13 @@ module OpenTox
def self.create service_uri, params={}
task = Task.new RestClient.post(service_uri,params).chomp
- pid = Spork.spork { yield }
+ pid = Spork.spork do
+ begin
+ task.completed yield
+ rescue => error
+ task.error error
+ end
+ end
task.pid = pid
task
end
@@ -33,6 +39,7 @@ module OpenTox
def wait_for_completion(dur=0.3)
due_to_time = Time.new + DEFAULT_TASK_MAX_DURATION
while self.running?
+ sleep dur
raise "max wait time exceeded ("+DEFAULT_TASK_MAX_DURATION.to_s+"sec), task: '"+@uri.to_s+"'" if (Time.new > due_to_time)
end
end
@@ -46,7 +53,7 @@ module OpenTox
res = RestClient.put(File.join(@uri,method.sub(/=/,'')),{})
super unless res.code == 200
when /\?/
- return metadata[RDF::OT.hasStatus] == method.sub(/\?/,'').capitalize
+ return hasStatus == method.sub(/\?/,'').capitalize
else
return metadata[RDF::OT[method]].to_s
end
--
cgit v1.2.3
From 9fe1f6870cfd12c34eb4efef8f4e199e8324c1af Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Sun, 19 Feb 2012 16:03:10 +0000
Subject: task handling fixed for http codes > 202
---
lib/authorization.rb | 30 ++++++-------
lib/error.rb | 3 +-
lib/opentox-client.rb | 5 ++-
lib/opentox.rb | 117 +++++++++++++++++++++-----------------------------
lib/spork.rb | 83 -----------------------------------
lib/task.rb | 68 ++++++++++++++++++++++++-----
6 files changed, 128 insertions(+), 178 deletions(-)
delete mode 100644 lib/spork.rb
(limited to 'lib')
diff --git a/lib/authorization.rb b/lib/authorization.rb
index d447f88..1938814 100644
--- a/lib/authorization.rb
+++ b/lib/authorization.rb
@@ -41,8 +41,8 @@ module OpenTox
xml = get_xml(uri)
ret = false
ret = Authorization.create_policy(xml, @subjectid)
- LOGGER.debug "Policy send with subjectid: #{@subjectid}"
- LOGGER.warn "Not created Policy is: #{xml}" if !ret
+ @@logger.debug "Policy send with subjectid: #{@subjectid}"
+ @@logger.warn "Not created Policy is: #{xml}" if !ret
ret
end
@@ -200,7 +200,7 @@ module OpenTox
def self.create_policy(policy, subjectid)
begin
resource = RestClient::Resource.new("#{AA_SERVER}/Pol/opensso-pol")
- LOGGER.debug "OpenTox::Authorization.create_policy policy: #{policy[168,43]} with token:" + subjectid.to_s + " length: " + subjectid.length.to_s
+ @@logger.debug "OpenTox::Authorization.create_policy policy: #{policy[168,43]} with token:" + subjectid.to_s + " length: " + subjectid.length.to_s
return true if resource.post(policy, :subjectid => subjectid, :content_type => "application/xml")
rescue
return false
@@ -213,7 +213,7 @@ module OpenTox
def self.delete_policy(policy, subjectid)
begin
resource = RestClient::Resource.new("#{AA_SERVER}/pol")
- LOGGER.debug "OpenTox::Authorization.delete_policy policy: #{policy} with token: #{subjectid}"
+ @@logger.debug "OpenTox::Authorization.delete_policy policy: #{policy} with token: #{subjectid}"
return true if resource.delete(:subjectid => subjectid, :id => policy)
rescue
return nil
@@ -279,7 +279,7 @@ module OpenTox
return true if !AA_SERVER
aa = Authorization::AA.new(subjectid)
ret = aa.send(uri)
- LOGGER.debug "OpenTox::Authorization send policy for URI: #{uri} | subjectid: #{subjectid} - policy created: #{ret}"
+ @@logger.debug "OpenTox::Authorization send policy for URI: #{uri} | subjectid: #{subjectid} - policy created: #{ret}"
ret
end
@@ -291,7 +291,7 @@ module OpenTox
if policies
policies.each do |policy|
ret = delete_policy(policy, subjectid)
- LOGGER.debug "OpenTox::Authorization delete policy: #{policy} - with result: #{ret}"
+ @@logger.debug "OpenTox::Authorization delete policy: #{policy} - with result: #{ret}"
end
end
return true
@@ -304,11 +304,11 @@ module OpenTox
def self.check_policy(uri, subjectid)
return true unless uri and subjectid
token_valid = OpenTox::Authorization.is_token_valid(subjectid)
- LOGGER.debug "OpenTox::Authorization.check_policy with uri: #{uri}, subjectid: #{subjectid} is valid: #{token_valid}"
+ @@logger.debug "OpenTox::Authorization.check_policy with uri: #{uri}, subjectid: #{subjectid} is valid: #{token_valid}"
# check if subjectid is valid
unless token_valid
# abort if invalid
- LOGGER.error "OpenTox::Authorization.check_policy, subjectid NOT valid: #{subjectid}"
+ @@logger.error "OpenTox::Authorization.check_policy, subjectid NOT valid: #{subjectid}"
return false
end
@@ -320,7 +320,7 @@ module OpenTox
if authorize(uri, "POST", subjectid)
true
else
- LOGGER.error "OpenTox::Authorization.check_policy, already exists, but no POST-authorization with subjectid: #{subjectid}"
+ @@logger.error "OpenTox::Authorization.check_policy, already exists, but no POST-authorization with subjectid: #{subjectid}"
false
end
end
@@ -338,25 +338,25 @@ module OpenTox
# @return [Boolean] true if access granted, else otherwise
def self.authorized?(uri, request_method, subjectid)
if CONFIG[:authorization][:free_request].include?(request_method)
- #LOGGER.debug "authorized? >>true<< (request is free), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}"
+ #@@logger.debug "authorized? >>true<< (request is free), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}"
true
elsif OpenTox::Authorization.free_uri?(uri, request_method)
- #LOGGER.debug "authorized? >>true<< (uris is free_uri), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}"
+ #@@logger.debug "authorized? >>true<< (uris is free_uri), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}"
true
elsif CONFIG[:authorization][:authenticate_request].include?(request_method)
ret = OpenTox::Authorization.is_token_valid(subjectid)
- LOGGER.debug "authorized? >>#{ret}<< (token is in/valid), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}" unless ret
+ @@logger.debug "authorized? >>#{ret}<< (token is in/valid), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}" unless ret
ret
elsif OpenTox::Authorization.authorize_exception?(uri, request_method)
ret = OpenTox::Authorization.is_token_valid(subjectid)
- LOGGER.debug "authorized? >>#{ret}<< (uris is authorize exception, token is in/valid), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}" unless ret
+ @@logger.debug "authorized? >>#{ret}<< (uris is authorize exception, token is in/valid), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}" unless ret
ret
elsif CONFIG[:authorization][:authorize_request].include?(request_method)
ret = OpenTox::Authorization.authorize(uri, request_method, subjectid)
- LOGGER.debug "authorized? >>#{ret}<< (uri (not) authorized), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}" unless ret
+ @@logger.debug "authorized? >>#{ret}<< (uri (not) authorized), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}" unless ret
ret
else
- LOGGER.error "invalid request/uri method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}"
+ @@logger.error "invalid request/uri method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}"
false
end
end
diff --git a/lib/error.rb b/lib/error.rb
index b92f2a4..64cc4eb 100644
--- a/lib/error.rb
+++ b/lib/error.rb
@@ -1,4 +1,3 @@
-
# adding additional fields to Exception class to format errors according to OT-API
class Exception
attr_accessor :errorCause
@@ -50,7 +49,7 @@ module OpenTox
# @param [String] actor, URI of the call that cause the error
def self.create( error, actor )
rest_params = error.rest_params if error.is_a?(OpenTox::RestCallError) and error.rest_params
- backtrace = error.backtrace.short_backtrace if CONFIG[:backtrace]
+ backtrace = error.backtrace.short_backtrace #if CONFIG[:backtrace]
ErrorReport.new( error.http_code, error.class.to_s, error.message, actor, error.errorCause, rest_params, backtrace )
end
diff --git a/lib/opentox-client.rb b/lib/opentox-client.rb
index 0bd048c..c5c701b 100644
--- a/lib/opentox-client.rb
+++ b/lib/opentox-client.rb
@@ -1,9 +1,12 @@
-require "opentox-client/version"
require 'rubygems'
require "bundler/setup"
require 'rdf'
require 'rdf/raptor'
require "rest-client"
+require 'uri'
+require 'yaml'
+require File.join(File.dirname(__FILE__),"error.rb")
+require File.join(File.dirname(__FILE__),"logger.rb")
require File.join(File.dirname(__FILE__),"opentox.rb")
require File.join(File.dirname(__FILE__),"task.rb")
require File.join(File.dirname(__FILE__),"compound.rb")
diff --git a/lib/opentox.rb b/lib/opentox.rb
index 51bc17a..ab5c95f 100644
--- a/lib/opentox.rb
+++ b/lib/opentox.rb
@@ -1,5 +1,4 @@
#TODO: switch services to 1.2
-#TODO: error handling
RDF::OT = RDF::Vocabulary.new 'http://www.opentox.org/api/1.2#'
RDF::OT1 = RDF::Vocabulary.new 'http://www.opentox.org/api/1.1#'
RDF::OTA = RDF::Vocabulary.new 'http://www.opentox.org/algorithmTypes.owl#'
@@ -11,83 +10,62 @@ RestClient.add_before_execution_proc do |req, params|
end
class String
- def to_object
- # TODO: fix, this is unsafe
- self =~ /dataset/ ? uri = File.join(self.chomp,"metadata") : uri = self.chomp
- raise "#{uri} is not a valid URI." unless RDF::URI.new(uri).uri?
- RDF::Reader.open(uri) do |reader|
- reader.each_statement do |statement|
- if statement.predicate == RDF.type and statement.subject == uri
- klass = "OpenTox::#{statement.object.to_s.split("#").last}"
- object = eval "#{klass}.new \"#{uri}\""
- end
- end
- end
- # fallback: guess class from uri
- # TODO: fix services and remove
- unless object
- case uri
- when /compound/
- object = OpenTox::Compound.new uri
- when /feature/
- object = OpenTox::Feature.new uri
- when /dataset/
- object = OpenTox::Dataset.new uri.sub(/\/metadata/,'')
- when /algorithm/
- object = OpenTox::Algorithm.new uri
- when /model/
- object = OpenTox::Model.new uri
- when /validation/
- object = OpenTox::Validation.new uri
- when /task/
- object = OpenTox::Task.new uri
- else
- raise "Class for #{uri} not found."
- end
- end
- if object.class == Task # wait for tasks
- object.wait_for_completion
- object = object.result_uri.to_s.to_object
- end
- object
- end
-
-=begin
- def object_from_uri
+ def to_object
# TODO: fix, this is unsafe
self =~ /dataset/ ? uri = File.join(self.chomp,"metadata") : uri = self.chomp
+ raise "#{uri} is not a valid URI." unless RDF::URI.new(uri).uri?
RDF::Reader.open(uri) do |reader|
reader.each_statement do |statement|
if statement.predicate == RDF.type and statement.subject == uri
klass = "OpenTox::#{statement.object.to_s.split("#").last}"
- return eval "#{klass}.new \"#{uri}\""
+ object = eval "#{klass}.new \"#{uri}\""
end
end
end
- # guess class from uri
+ # fallback: guess class from uri
# TODO: fix services and remove
- case uri
- when /compound/
- return OpenTox::Compound.new uri
- when /feature/
- return OpenTox::Feature.new uri
- when /dataset/
- return OpenTox::Dataset.new uri.sub(/\/metadata/,'')
- when /algorithm/
- return OpenTox::Algorithm.new uri
- when /model/
- return OpenTox::Model.new uri
- when /validation/
- return OpenTox::Validation.new uri
- when /task/
- return OpenTox::Task.new uri
- else
- raise "Class for #{uri} not found."
+ unless object
+ case uri
+ when /compound/
+ object = OpenTox::Compound.new uri
+ when /feature/
+ object = OpenTox::Feature.new uri
+ when /dataset/
+ object = OpenTox::Dataset.new uri.sub(/\/metadata/,'')
+ when /algorithm/
+ object = OpenTox::Algorithm.new uri
+ when /model/
+ object = OpenTox::Model.new uri
+ when /validation/
+ object = OpenTox::Validation.new uri
+ when /task/
+ object = OpenTox::Task.new uri
+ else
+ raise "Class for #{uri} not found."
+ end
+ end
+ if object.class == Task # wait for tasks
+ object.wait_for_completion
+ object = object.result_uri.to_s.to_object
+ end
+ object
+ end
+
+ def uri?
+ begin
+ Net::HTTP.get_response(URI.parse(self))
+ true
+ rescue
+ false
end
end
-=end
end
+
+# defaults to stderr, may be changed to file output
+$logger = OTLogger.new(STDERR) # no rotation
+$logger.level = Logger::DEBUG
+
module OpenTox
attr_accessor :subjectid, :uri, :response
@@ -103,10 +81,15 @@ module OpenTox
def metadata reload=true
if reload
@metadata = {}
- RDF::Reader.open(@uri) do |reader|
- reader.each_statement do |statement|
- @metadata[statement.predicate] = statement.object if statement.subject == @uri
+ begin
+ RDF::Reader.open(@uri) do |reader|
+ reader.each_statement do |statement|
+ @metadata[statement.predicate] = statement.object if statement.subject == @uri
+ end
end
+ rescue
+ $logger.error "Cannot read RDF metadata from #{@uri}: #{$!}.\n#{$!.backtrace.join("\n")}"
+ raise
end
end
@metadata
diff --git a/lib/spork.rb b/lib/spork.rb
deleted file mode 100644
index c77b5b5..0000000
--- a/lib/spork.rb
+++ /dev/null
@@ -1,83 +0,0 @@
-# A way to cleanly handle process forking in Sinatra when using Passenger, aka "sporking some code".
-# This will allow you to properly execute some code asynchronously, which otherwise does not work correctly.
-#
-# Written by Ron Evans
-# More info at http://deadprogrammersociety.com
-#
-# Mostly lifted from the Spawn plugin for Rails (http://github.com/tra/spawn)
-# but with all of the Rails stuff removed.... cause you are using Sinatra. If you are using Rails, Spawn is
-# what you need. If you are using something else besides Sinatra that is Rack-based under Passenger, and you are having trouble with
-# asynch processing, let me know if spork helped you.
-#
-module Spork
- # things to close in child process
- @@resources = []
- def self.resources
- @@resources
- end
-
- # set the resource to disconnect from in the child process (when forking)
- def self.resource_to_close(resource)
- @@resources << resource
- end
-
- # close all the resources added by calls to resource_to_close
- def self.close_resources
- @@resources.each do |resource|
- resource.close if resource && resource.respond_to?(:close) && !resource.closed?
- end
- @@resources = []
- end
-
- # actually perform the fork... er, spork
- # valid options are:
- # :priority => to set the process priority of the child
- # :logger => a logger object to use from the child
- # :no_detach => true if you want to keep the child process under the parent control. usually you do NOT want this
- def self.spork(options={})
- logger = options[:logger]
- logger.debug "spork> parent PID = #{Process.pid}" if logger
-
- child = fork do
- begin
- start = Time.now
- logger.debug "spork> child PID = #{Process.pid}" if logger
-
- # set the nice priority if needed
- Process.setpriority(Process::PRIO_PROCESS, 0, options[:priority]) if options[:priority]
-
- # disconnect from the rack
- Spork.close_resources
-
- # run the block of code that takes so long
- yield
-
- rescue => ex
- #raise ex
- logger.error "spork> Exception in child[#{Process.pid}] - #{ex.class}: #{ex.message}" if logger
- ensure
- logger.info "spork> child[#{Process.pid}] took #{Time.now - start} sec" if logger
- # this form of exit doesn't call at_exit handlers
- exit!(0)
- end
- end
-
- # detach from child process (parent may still wait for detached process if they wish)
- Process.detach(child) unless options[:no_detach]
-
- return child
- end
-
-end
-
-# Patch to work with passenger
-if defined? Passenger::Rack::RequestHandler
- class Passenger::Rack::RequestHandler
- alias_method :orig_process_request, :process_request
- def process_request(env, input, output)
- Spork.resource_to_close(input)
- Spork.resource_to_close(output)
- orig_process_request(env, input, output)
- end
- end
-end
diff --git a/lib/task.rb b/lib/task.rb
index 50616d7..52d4a30 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -1,28 +1,47 @@
-require File.join(File.dirname(__FILE__),'spork')
+require File.join(File.dirname(__FILE__),'error')
DEFAULT_TASK_MAX_DURATION = 36000
module OpenTox
# Class for handling asynchronous tasks
class Task
+ attr_accessor :pid
def self.create service_uri, params={}
task = Task.new RestClient.post(service_uri,params).chomp
- pid = Spork.spork do
+ pid = fork do
begin
- task.completed yield
- rescue => error
- task.error error
+ result_uri = yield
+ if result_uri.uri?
+ task.completed result_uri
+ else
+ raise "#{result_uri} is not a valid URI"
+ end
+ rescue
+ # TODO add service URI to Kernel.raise
+ # serialize error and send to task service
+ #task.error $!
+ task.error $!
+ raise
end
end
+ Process.detach(pid)
task.pid = pid
task
end
+ def kill
+ begin
+ Process.kill(9,pid)
+ rescue
+ end
+ end
+
def description
metadata[RDF::DC.description]
end
def cancel
+ kill
RestClient.put(File.join(@uri,'Cancelled'),{})
end
@@ -30,19 +49,24 @@ module OpenTox
RestClient.put(File.join(@uri,'Completed'),{:resultURI => uri})
end
- def error(error)
- RestClient.put(File.join(@uri,'Error'),{:errorReport => OpenTox::Error.new(error)})
+ def error error
+ $logger.error self if $logger
+ kill
+ report = ErrorReport.create(error,"http://localhost")
+ RestClient.put(File.join(@uri,'Error'),{:errorReport => report})
+ #RestClient.put(File.join(@uri,'Error'),{:message => error, :backtrace => error.backtrace})
end
# waits for a task, unless time exceeds or state is no longer running
- # @param [optional,Numeric] dur seconds pausing before cheking again for completion
+ # @param [optional,Numeric] dur seconds pausing before checking again for completion
def wait_for_completion(dur=0.3)
due_to_time = Time.new + DEFAULT_TASK_MAX_DURATION
- while self.running?
+ while running?
sleep dur
raise "max wait time exceeded ("+DEFAULT_TASK_MAX_DURATION.to_s+"sec), task: '"+@uri.to_s+"'" if (Time.new > due_to_time)
end
end
+
end
def method_missing(method,*args)
@@ -55,13 +79,37 @@ module OpenTox
when /\?/
return hasStatus == method.sub(/\?/,'').capitalize
else
- return metadata[RDF::OT[method]].to_s
+ response = metadata[RDF::OT[method]].to_s
+ response = metadata[RDF::OT1[method]].to_s #if response.empty? # API 1.1 compatibility
+ if response.empty?
+ $logger.error "No #{method} metadata for #{@uri} "
+ raise "No #{method} metadata for #{@uri} "
+ end
+ return response
end
rescue
+ $logger.error "Unknown #{self.class} method #{method}"
super
end
end
+ # override to read all error codes
+ def metadata reload=true
+ if reload
+ @metadata = {}
+ # ignore error codes from Task services (may contain eg 500 which causes exceptions in RestClient and RDF::Reader
+ RestClient.get(@uri) do |response, request, result, &block|
+ $logger.warn "#{@uri} returned #{result}" unless response.code == 200 or response.code == 202
+ RDF::Reader.for(:rdfxml).new(response) do |reader|
+ reader.each_statement do |statement|
+ @metadata[statement.predicate] = statement.object if statement.subject == @uri
+ end
+ end
+ end
+ end
+ @metadata
+ end
+
#TODO: subtasks
end
--
cgit v1.2.3
From 64135ae320998a836725786f95a4efd3b63f585c Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Sun, 19 Feb 2012 16:06:46 +0000
Subject: logger.rb added
---
lib/logger.rb | 46 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 46 insertions(+)
create mode 100644 lib/logger.rb
(limited to 'lib')
diff --git a/lib/logger.rb b/lib/logger.rb
new file mode 100644
index 0000000..c98f1ca
--- /dev/null
+++ b/lib/logger.rb
@@ -0,0 +1,46 @@
+require 'logger'
+class OTLogger < Logger
+
+ def pwd
+ path = Dir.pwd.to_s
+ index = path.rindex(/\//)
+ return path if index==nil
+ path[(index+1)..-1]
+ end
+
+ def trace()
+ lines = caller(0)
+ n = 2
+ line = lines[n]
+
+ while (line =~ /spork.rb/ or line =~ /create/ or line =~ /overwrite.rb/)
+ n += 1
+ line = lines[n]
+ end
+
+ index = line.rindex(/\/.*\.rb/)
+ return line if index==nil
+ line[index..-1]
+ end
+
+ def format(msg)
+ pwd.ljust(18)+" :: "+msg.to_s+" :: "+trace
+ end
+
+ def debug(msg)
+ super format(msg)
+ end
+
+ def info(msg)
+ super format(msg)
+ end
+
+ def warn(msg)
+ super format(msg)
+ end
+
+ def error(msg)
+ super format(msg)
+ end
+
+end
--
cgit v1.2.3
From b6134b992fde8784c3556fbca32925e721700d32 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Mon, 20 Feb 2012 16:16:56 +0000
Subject: task catches and reports errors (some dataset tests still fail)
---
lib/error.rb | 9 +++++++++
lib/logger.rb | 46 ----------------------------------------------
lib/opentox-client.rb | 5 +++--
lib/opentox.rb | 13 ++++++-------
lib/otlogger.rb | 45 +++++++++++++++++++++++++++++++++++++++++++++
lib/task.rb | 2 +-
6 files changed, 64 insertions(+), 56 deletions(-)
delete mode 100644 lib/logger.rb
create mode 100644 lib/otlogger.rb
(limited to 'lib')
diff --git a/lib/error.rb b/lib/error.rb
index 64cc4eb..6987f35 100644
--- a/lib/error.rb
+++ b/lib/error.rb
@@ -17,16 +17,22 @@ module OpenTox
class NotFoundError < RuntimeError
def http_code; 404; end
end
+
+ class LockedError < RuntimeError
+ def http_code; 423; end
+ end
class ServiceUnavailableError < RuntimeError
def http_code; 503; end
end
+ # TODO: add to RestClientCalls
class RestCallError < RuntimeError
attr_accessor :rest_params
def http_code; 502; end
end
+ # TODO: add to Exception class??
class ErrorReport
# TODO replace params with URIs (errorCause -> OT.errorCause)
@@ -78,11 +84,14 @@ module OpenTox
c
end
+ # TODO: use rdf.rb
def to_rdfxml
s = Serializer::Owl.new
s.add_resource(CONFIG[:services]["opentox-task"]+"/tmpId/ErrorReport/tmpId", OT.errorReport, rdf_content)
s.to_rdfxml
end
+=begin
+=end
end
end
diff --git a/lib/logger.rb b/lib/logger.rb
deleted file mode 100644
index c98f1ca..0000000
--- a/lib/logger.rb
+++ /dev/null
@@ -1,46 +0,0 @@
-require 'logger'
-class OTLogger < Logger
-
- def pwd
- path = Dir.pwd.to_s
- index = path.rindex(/\//)
- return path if index==nil
- path[(index+1)..-1]
- end
-
- def trace()
- lines = caller(0)
- n = 2
- line = lines[n]
-
- while (line =~ /spork.rb/ or line =~ /create/ or line =~ /overwrite.rb/)
- n += 1
- line = lines[n]
- end
-
- index = line.rindex(/\/.*\.rb/)
- return line if index==nil
- line[index..-1]
- end
-
- def format(msg)
- pwd.ljust(18)+" :: "+msg.to_s+" :: "+trace
- end
-
- def debug(msg)
- super format(msg)
- end
-
- def info(msg)
- super format(msg)
- end
-
- def warn(msg)
- super format(msg)
- end
-
- def error(msg)
- super format(msg)
- end
-
-end
diff --git a/lib/opentox-client.rb b/lib/opentox-client.rb
index c5c701b..fc6cbd1 100644
--- a/lib/opentox-client.rb
+++ b/lib/opentox-client.rb
@@ -5,9 +5,10 @@ require 'rdf/raptor'
require "rest-client"
require 'uri'
require 'yaml'
+require 'logger'
require File.join(File.dirname(__FILE__),"error.rb")
-require File.join(File.dirname(__FILE__),"logger.rb")
+require File.join(File.dirname(__FILE__),"otlogger.rb") # avoid require conflicts with logger
require File.join(File.dirname(__FILE__),"opentox.rb")
require File.join(File.dirname(__FILE__),"task.rb")
require File.join(File.dirname(__FILE__),"compound.rb")
-require File.join(File.dirname(__FILE__),"dataset.rb")
+#require File.join(File.dirname(__FILE__),"dataset.rb")
diff --git a/lib/opentox.rb b/lib/opentox.rb
index ab5c95f..01de3e7 100644
--- a/lib/opentox.rb
+++ b/lib/opentox.rb
@@ -13,7 +13,8 @@ class String
def to_object
# TODO: fix, this is unsafe
self =~ /dataset/ ? uri = File.join(self.chomp,"metadata") : uri = self.chomp
- raise "#{uri} is not a valid URI." unless RDF::URI.new(uri).uri?
+ #raise "#{uri} is not a valid URI." unless RDF::URI.new(uri).uri?
+ raise "#{uri} is not a valid URI." unless uri.uri?
RDF::Reader.open(uri) do |reader|
reader.each_statement do |statement|
if statement.predicate == RDF.type and statement.subject == uri
@@ -82,7 +83,10 @@ module OpenTox
if reload
@metadata = {}
begin
- RDF::Reader.open(@uri) do |reader|
+ #puts self.class
+ #self.kind_of?(OpenTox::Dataset) ? uri = URI.join(@uri,"metadata") : uri = @uri
+ #$logger.debug uri
+ RDF::Reader.open(uri) do |reader|
reader.each_statement do |statement|
@metadata[statement.predicate] = statement.object if statement.subject == @uri
end
@@ -151,9 +155,6 @@ module OpenTox
end
- class FromUri
- end
-
# create default classes
SERVICES.each do |s|
eval "class #{s}
@@ -162,7 +163,5 @@ module OpenTox
end"
end
- private
-
end
diff --git a/lib/otlogger.rb b/lib/otlogger.rb
new file mode 100644
index 0000000..295d0c1
--- /dev/null
+++ b/lib/otlogger.rb
@@ -0,0 +1,45 @@
+class OTLogger < Logger
+
+ def pwd
+ path = Dir.pwd.to_s
+ index = path.rindex(/\//)
+ return path if index==nil
+ path[(index+1)..-1]
+ end
+
+ def trace()
+ lines = caller(0)
+ n = 2
+ line = lines[n]
+
+ while (line =~ /spork.rb/ or line =~ /create/ or line =~ /overwrite.rb/)
+ n += 1
+ line = lines[n]
+ end
+
+ index = line.rindex(/\/.*\.rb/)
+ return line if index==nil
+ line[index..-1]
+ end
+
+ def format(msg)
+ pwd.ljust(18)+" :: "+msg.to_s+" :: "+trace
+ end
+
+ def debug(msg)
+ super format(msg)
+ end
+
+ def info(msg)
+ super format(msg)
+ end
+
+ def warn(msg)
+ super format(msg)
+ end
+
+ def error(msg)
+ super format(msg)
+ end
+
+end
diff --git a/lib/task.rb b/lib/task.rb
index 52d4a30..582f592 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -89,7 +89,7 @@ module OpenTox
end
rescue
$logger.error "Unknown #{self.class} method #{method}"
- super
+ #super
end
end
--
cgit v1.2.3
From b651c4d199a7b4d6a06cdefb281601bddd2fc885 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Thu, 23 Feb 2012 16:20:39 +0000
Subject: integrated features and tests from feature/typhoeus, tests pass
reliably (as opposed to feature/typhoeus)
---
lib/opentox.rb | 100 ++++++++++++++++++++++----------------------------------
lib/otlogger.rb | 2 +-
lib/task.rb | 67 ++++++++++++++++++++++---------------
3 files changed, 80 insertions(+), 89 deletions(-)
(limited to 'lib')
diff --git a/lib/opentox.rb b/lib/opentox.rb
index 01de3e7..2fbf9dc 100644
--- a/lib/opentox.rb
+++ b/lib/opentox.rb
@@ -2,66 +2,46 @@
RDF::OT = RDF::Vocabulary.new 'http://www.opentox.org/api/1.2#'
RDF::OT1 = RDF::Vocabulary.new 'http://www.opentox.org/api/1.1#'
RDF::OTA = RDF::Vocabulary.new 'http://www.opentox.org/algorithmTypes.owl#'
-SERVICES = ["Compound", "Feature", "Dataset", "Algorithm", "Model", "Validation", "Task"]
+SERVICES = ["Compound", "Feature", "Dataset", "Algorithm", "Model", "Validation", "Task", "Investigation"]
-# not working
-RestClient.add_before_execution_proc do |req, params|
- params[:subjectid] = @subjectid
+class String
+ def underscore
+ self.gsub(/::/, '/').
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
+ tr("-", "_").
+ downcase
+ end
end
-class String
- def to_object
- # TODO: fix, this is unsafe
- self =~ /dataset/ ? uri = File.join(self.chomp,"metadata") : uri = self.chomp
- #raise "#{uri} is not a valid URI." unless RDF::URI.new(uri).uri?
- raise "#{uri} is not a valid URI." unless uri.uri?
- RDF::Reader.open(uri) do |reader|
- reader.each_statement do |statement|
- if statement.predicate == RDF.type and statement.subject == uri
- klass = "OpenTox::#{statement.object.to_s.split("#").last}"
- object = eval "#{klass}.new \"#{uri}\""
- end
- end
- end
- # fallback: guess class from uri
- # TODO: fix services and remove
- unless object
- case uri
- when /compound/
- object = OpenTox::Compound.new uri
- when /feature/
- object = OpenTox::Feature.new uri
- when /dataset/
- object = OpenTox::Dataset.new uri.sub(/\/metadata/,'')
- when /algorithm/
- object = OpenTox::Algorithm.new uri
- when /model/
- object = OpenTox::Model.new uri
- when /validation/
- object = OpenTox::Validation.new uri
- when /task/
- object = OpenTox::Task.new uri
- else
- raise "Class for #{uri} not found."
- end
- end
- if object.class == Task # wait for tasks
- object.wait_for_completion
- object = object.result_uri.to_s.to_object
- end
- object
+module URI
+
+ def self.task? uri
+ uri =~ /task/ and URI.valid? uri
+ end
+
+ def self.dataset? uri, subjectid=nil
+ uri =~ /dataset/ and URI.accessible? uri, subjectid=nil
+ end
+
+ def self.model? uri, subjectid=nil
+ uri =~ /model/ and URI.accessible? uri, subjectid=nil
end
- def uri?
- begin
- Net::HTTP.get_response(URI.parse(self))
- true
- rescue
- false
- end
+ def self.accessible? uri, subjectid=nil
+ Net::HTTP.get_response(URI.parse(uri))
+ true
+ rescue
+ false
end
-end
+ def self.valid? uri
+ u = URI::parse(uri)
+ u.scheme!=nil and u.host!=nil
+ rescue URI::InvalidURIError
+ false
+ end
+end
# defaults to stderr, may be changed to file output
$logger = OTLogger.new(STDERR) # no rotation
@@ -79,21 +59,19 @@ module OpenTox
# Ruby interface
+
+ # override to read all error codes
def metadata reload=true
if reload
@metadata = {}
- begin
- #puts self.class
- #self.kind_of?(OpenTox::Dataset) ? uri = URI.join(@uri,"metadata") : uri = @uri
- #$logger.debug uri
- RDF::Reader.open(uri) do |reader|
+ # ignore error codes from Task services (may contain eg 500 which causes exceptions in RestClient and RDF::Reader
+ RestClient.get(@uri) do |response, request, result, &block|
+ $logger.warn "#{@uri} returned #{result}" unless response.code == 200 or response.code == 202 or URI.task? @uri
+ RDF::Reader.for(:rdfxml).new(response) do |reader|
reader.each_statement do |statement|
@metadata[statement.predicate] = statement.object if statement.subject == @uri
end
end
- rescue
- $logger.error "Cannot read RDF metadata from #{@uri}: #{$!}.\n#{$!.backtrace.join("\n")}"
- raise
end
end
@metadata
diff --git a/lib/otlogger.rb b/lib/otlogger.rb
index 295d0c1..e9fbc4d 100644
--- a/lib/otlogger.rb
+++ b/lib/otlogger.rb
@@ -12,7 +12,7 @@ class OTLogger < Logger
n = 2
line = lines[n]
- while (line =~ /spork.rb/ or line =~ /create/ or line =~ /overwrite.rb/)
+ while (line =~ /spork.rb/ or line =~ /create/ or line =~ /#{File.basename(__FILE__)}/)
n += 1
line = lines[n]
end
diff --git a/lib/task.rb b/lib/task.rb
index 582f592..9aaee04 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -5,13 +5,13 @@ module OpenTox
# Class for handling asynchronous tasks
class Task
- attr_accessor :pid
+ attr_accessor :pid, :observer_pid
def self.create service_uri, params={}
task = Task.new RestClient.post(service_uri,params).chomp
pid = fork do
begin
result_uri = yield
- if result_uri.uri?
+ if URI.accessible?(result_uri)
task.completed result_uri
else
raise "#{result_uri} is not a valid URI"
@@ -26,14 +26,25 @@ module OpenTox
end
Process.detach(pid)
task.pid = pid
+
+ # watch if task has been cancelled
+ observer_pid = fork do
+ task.wait_for_completion
+ begin
+ Process.kill(9,task.pid) if task.cancelled?
+ rescue
+ $logger.warn "Could not kill process of task #{task.uri}, pid: #{task.pid}"
+ end
+ end
+ Process.detach(observer_pid)
+ task.observer_pid = observer_pid
task
end
def kill
- begin
- Process.kill(9,pid)
- rescue
- end
+ Process.kill(9,@pid)
+ Process.kill(9,@observer_pid)
+ rescue # no need to raise an aexeption if processes are not running
end
def description
@@ -46,15 +57,17 @@ module OpenTox
end
def completed(uri)
+ #TODO: subjectid?
+ #TODO: error code
+ raise "\"#{uri}\" does not exist." unless URI.accessible? uri
RestClient.put(File.join(@uri,'Completed'),{:resultURI => uri})
end
def error error
$logger.error self if $logger
- kill
report = ErrorReport.create(error,"http://localhost")
RestClient.put(File.join(@uri,'Error'),{:errorReport => report})
- #RestClient.put(File.join(@uri,'Error'),{:message => error, :backtrace => error.backtrace})
+ kill
end
# waits for a task, unless time exceeds or state is no longer running
@@ -69,6 +82,23 @@ module OpenTox
end
+ # get only header for ststus requests
+ def running?
+ RestClient.head(@uri){ |response, request, result| result.code.to_i == 202 }
+ end
+
+ def cancelled?
+ RestClient.head(@uri){ |response, request, result| result.code.to_i == 503 }
+ end
+
+ def completed?
+ RestClient.head(@uri){ |response, request, result| result.code.to_i == 200 }
+ end
+
+ def error?
+ RestClient.head(@uri){ |response, request, result| result.code.to_i == 500 }
+ end
+
def method_missing(method,*args)
method = method.to_s
begin
@@ -76,8 +106,8 @@ module OpenTox
when /=/
res = RestClient.put(File.join(@uri,method.sub(/=/,'')),{})
super unless res.code == 200
- when /\?/
- return hasStatus == method.sub(/\?/,'').capitalize
+ #when /\?/
+ #return hasStatus == method.sub(/\?/,'').capitalize
else
response = metadata[RDF::OT[method]].to_s
response = metadata[RDF::OT1[method]].to_s #if response.empty? # API 1.1 compatibility
@@ -93,23 +123,6 @@ module OpenTox
end
end
- # override to read all error codes
- def metadata reload=true
- if reload
- @metadata = {}
- # ignore error codes from Task services (may contain eg 500 which causes exceptions in RestClient and RDF::Reader
- RestClient.get(@uri) do |response, request, result, &block|
- $logger.warn "#{@uri} returned #{result}" unless response.code == 200 or response.code == 202
- RDF::Reader.for(:rdfxml).new(response) do |reader|
- reader.each_statement do |statement|
- @metadata[statement.predicate] = statement.object if statement.subject == @uri
- end
- end
- end
- end
- @metadata
- end
-
#TODO: subtasks
end
--
cgit v1.2.3
From fa9069e13fb6b1c8bb4ebcdf82f1cf1c04ad71ca Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Thu, 23 Feb 2012 17:56:46 +0000
Subject: (partially) switched back to RestClientWrapper
---
lib/compound.rb | 8 +-
lib/opentox-client.rb | 2 +
lib/opentox.rb | 67 ++++-------------
lib/overwrite.rb | 39 ++++++++++
lib/rest_client_wrapper.rb | 182 +++++++++++++++++++++++++++++++++++++++++++++
lib/task.rb | 10 +--
6 files changed, 245 insertions(+), 63 deletions(-)
create mode 100644 lib/overwrite.rb
create mode 100644 lib/rest_client_wrapper.rb
(limited to 'lib')
diff --git a/lib/compound.rb b/lib/compound.rb
index 8761d50..ce0fdbf 100644
--- a/lib/compound.rb
+++ b/lib/compound.rb
@@ -11,21 +11,21 @@ module OpenTox
# @param [String] smiles Smiles string
# @return [OpenTox::Compound] Compound
def self.from_smiles service_uri, smiles, subjectid=nil
- Compound.new RestClient.post(service_uri, smiles, {:content_type => 'chemical/x-daylight-smiles', :subjectid => subjectid})
+ Compound.new RestClientWrapper.post(service_uri, smiles, {:content_type => 'chemical/x-daylight-smiles', :subjectid => subjectid})
end
# Create a compound from inchi string
# @param [String] smiles InChI string
# @return [OpenTox::Compound] Compound
def self.from_inchi service_uri, inchi, subjectid=nil
- Compound.new RestClient.post(service_uri, inchi, {:content_type => 'chemical/x-inchi', :subjectid => subjectid})
+ Compound.new RestClientWrapper.post(service_uri, inchi, {:content_type => 'chemical/x-inchi', :subjectid => subjectid})
end
# Create a compound from sdf string
# @param [String] smiles SDF string
# @return [OpenTox::Compound] Compound
def self.from_sdf service_uri, sdf, subjectid=nil
- Compound.new RestClient.post(service_uri, sdf, {:content_type => 'chemical/x-mdl-sdfile', :subjectid => subjectid})
+ Compound.new RestClientWrapper.post(service_uri, sdf, {:content_type => 'chemical/x-mdl-sdfile', :subjectid => subjectid})
end
# Create a compound from name. Relies on an external service for name lookups.
@@ -34,7 +34,7 @@ module OpenTox
# @param [String] name name can be also an InChI/InChiKey, CAS number, etc
# @return [OpenTox::Compound] Compound
def self.from_name service_uri, name, subjectid=nil
- Compound.new RestClient.post(service_uri, name, {:content_type => 'text/plain', :subjectid => subjectid})
+ Compound.new RestClientWrapper.post(service_uri, name, {:content_type => 'text/plain', :subjectid => subjectid})
end
# Get InChI
diff --git a/lib/opentox-client.rb b/lib/opentox-client.rb
index fc6cbd1..1a5e7c3 100644
--- a/lib/opentox-client.rb
+++ b/lib/opentox-client.rb
@@ -6,7 +6,9 @@ require "rest-client"
require 'uri'
require 'yaml'
require 'logger'
+require File.join(File.dirname(__FILE__),"overwrite.rb")
require File.join(File.dirname(__FILE__),"error.rb")
+require File.join(File.dirname(__FILE__),"rest_client_wrapper.rb")
require File.join(File.dirname(__FILE__),"otlogger.rb") # avoid require conflicts with logger
require File.join(File.dirname(__FILE__),"opentox.rb")
require File.join(File.dirname(__FILE__),"task.rb")
diff --git a/lib/opentox.rb b/lib/opentox.rb
index 2fbf9dc..f81ae10 100644
--- a/lib/opentox.rb
+++ b/lib/opentox.rb
@@ -4,45 +4,6 @@ RDF::OT1 = RDF::Vocabulary.new 'http://www.opentox.org/api/1.1#'
RDF::OTA = RDF::Vocabulary.new 'http://www.opentox.org/algorithmTypes.owl#'
SERVICES = ["Compound", "Feature", "Dataset", "Algorithm", "Model", "Validation", "Task", "Investigation"]
-class String
- def underscore
- self.gsub(/::/, '/').
- gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
- gsub(/([a-z\d])([A-Z])/,'\1_\2').
- tr("-", "_").
- downcase
- end
-end
-
-module URI
-
- def self.task? uri
- uri =~ /task/ and URI.valid? uri
- end
-
- def self.dataset? uri, subjectid=nil
- uri =~ /dataset/ and URI.accessible? uri, subjectid=nil
- end
-
- def self.model? uri, subjectid=nil
- uri =~ /model/ and URI.accessible? uri, subjectid=nil
- end
-
- def self.accessible? uri, subjectid=nil
- Net::HTTP.get_response(URI.parse(uri))
- true
- rescue
- false
- end
-
- def self.valid? uri
- u = URI::parse(uri)
- u.scheme!=nil and u.host!=nil
- rescue URI::InvalidURIError
- false
- end
-end
-
# defaults to stderr, may be changed to file output
$logger = OTLogger.new(STDERR) # no rotation
$logger.level = Logger::DEBUG
@@ -59,13 +20,15 @@ module OpenTox
# Ruby interface
-
# override to read all error codes
def metadata reload=true
- if reload
+ if reload or @metadata.empty?
@metadata = {}
# ignore error codes from Task services (may contain eg 500 which causes exceptions in RestClient and RDF::Reader
- RestClient.get(@uri) do |response, request, result, &block|
+ # TODO: convert to RestClientWrapper
+ kind_of?(OpenTox::Dataset) ? uri = File.join(@uri,"metadata") : uri = @uri
+ RestClient.get(uri) do |response, request, result|
+ #response = RestClientWrapper.get(@uri) #do |response, request, result|
$logger.warn "#{@uri} returned #{result}" unless response.code == 200 or response.code == 202 or URI.task? @uri
RDF::Reader.for(:rdfxml).new(response) do |reader|
reader.each_statement do |statement|
@@ -74,6 +37,7 @@ module OpenTox
end
end
end
+ #puts @metadata.inspect
@metadata
end
@@ -88,46 +52,41 @@ module OpenTox
def get params={}
params[:subjectid] ||= @subjectid
params[:accept] ||= 'application/rdf+xml'
- @response = RestClient.get @uri, params
+ @response = RestClientWrapper.get @uri, params
end
def post payload={}, params={}
params[:subjectid] ||= @subjectid
params[:accept] ||= 'application/rdf+xml'
- @response = RestClient.post(@uri.to_s, payload, params)
- begin
- @response.to_s.to_object
- rescue
- @response
- end
+ @response = RestClientWrapper.post(@uri.to_s, payload, params)
end
def put payload={}, params={}
params[:subjectid] ||= @subjectid
params[:accept] ||= 'application/rdf+xml'
- @response = RestClient.put(@uri.to_s, payload, params)
+ @response = RestClientWrapper.put(@uri.to_s, payload, params)
end
def delete params={}
params[:subjectid] ||= @subjectid
params[:accept] ||= 'application/rdf+xml'
- @response = RestClient.delete(@uri.to_s,:subjectid => @subjectid)
+ @response = RestClientWrapper.delete(@uri.to_s,:subjectid => @subjectid)
end
# class methods
module ClassMethods
def create service_uri, subjectid=nil
- uri = RestClient.post(service_uri, {}, :subjectid => subjectid).chomp
+ uri = RestClientWrapper.post(service_uri, {}, :subjectid => subjectid).chomp
subjectid ? eval("#{self}.new(\"#{uri}\", #{subjectid})") : eval("#{self}.new(\"#{uri}\")")
end
def from_file service_uri, file, subjectid=nil
- RestClient.post(service_uri, :file => File.new(file), :subjectid => subjectid).chomp.to_object
+ RestClientWrapper.post(service_uri, :file => File.new(file), :subjectid => subjectid).chomp.to_object
end
def all service_uri, subjectid=nil
- uris = RestClient.get(service_uri, {:accept => 'text/uri-list'}).split("\n").compact
+ uris = RestClientWrapper.get(service_uri, {:accept => 'text/uri-list'}).split("\n").compact
uris.collect{|uri| subjectid ? eval("#{self}.new(\"#{uri}\", #{subjectid})") : eval("#{self}.new(\"#{uri}\")")}
end
diff --git a/lib/overwrite.rb b/lib/overwrite.rb
new file mode 100644
index 0000000..e883d45
--- /dev/null
+++ b/lib/overwrite.rb
@@ -0,0 +1,39 @@
+class String
+ def underscore
+ self.gsub(/::/, '/').
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
+ tr("-", "_").
+ downcase
+ end
+end
+
+module URI
+
+ def self.task? uri
+ uri =~ /task/ and URI.valid? uri
+ end
+
+ def self.dataset? uri, subjectid=nil
+ uri =~ /dataset/ and URI.accessible? uri, subjectid=nil
+ end
+
+ def self.model? uri, subjectid=nil
+ uri =~ /model/ and URI.accessible? uri, subjectid=nil
+ end
+
+ def self.accessible? uri, subjectid=nil
+ Net::HTTP.get_response(URI.parse(uri))
+ true
+ rescue
+ false
+ end
+
+ def self.valid? uri
+ u = URI::parse(uri)
+ u.scheme!=nil and u.host!=nil
+ rescue URI::InvalidURIError
+ false
+ end
+end
+
diff --git a/lib/rest_client_wrapper.rb b/lib/rest_client_wrapper.rb
new file mode 100644
index 0000000..89de277
--- /dev/null
+++ b/lib/rest_client_wrapper.rb
@@ -0,0 +1,182 @@
+module OpenTox
+
+ class WrapperResult < String
+ attr_accessor :content_type, :code
+ end
+
+ class RestClientWrapper
+
+ # performs a GET REST call
+ # raises OpenTox::Error if call fails (rescued in overwrite.rb -> halt 502)
+ # per default: waits for Task to finish and returns result URI of Task
+ # @param [String] uri destination URI
+ # @param [optional,Hash] headers contains params like accept-header
+ # @param [optional,OpenTox::Task] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
+ # @param [wait,Boolean] wait set to false to NOT wait for task if result is task
+ # @return [OpenTox::WrapperResult] a String containing the result-body of the REST call
+ def self.get(uri, headers={}, waiting_task=nil, wait=true )
+ execute( "get", uri, nil, headers, waiting_task, wait)
+ end
+
+ # performs a POST REST call
+ # raises OpenTox::Error if call fails (rescued in overwrite.rb -> halt 502)
+ # per default: waits for Task to finish and returns result URI of Task
+ # @param [String] uri destination URI
+ # @param [optional,String] payload data posted to the service
+ # @param [optional,Hash] headers contains params like accept-header
+ # @param [optional,OpenTox::Task] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
+ # @param [wait,Boolean] wait set to false to NOT wait for task if result is task
+ # @return [OpenTox::WrapperResult] a String containing the result-body of the REST call
+ def self.post(uri, payload=nil, headers={}, waiting_task=nil, wait=true )
+ execute( "post", uri, payload, headers, waiting_task, wait )
+ end
+
+ # performs a PUT REST call
+ # raises OpenTox::Error if call fails (rescued in overwrite.rb -> halt 502)
+ # @param [String] uri destination URI
+ # @param [optional,Hash] headers contains params like accept-header
+ # @param [optional,String] payload data put to the service
+ # @return [OpenTox::WrapperResult] a String containing the result-body of the REST call
+ def self.put(uri, payload=nil, headers={} )
+ execute( "put", uri, payload, headers )
+ end
+
+ # performs a DELETE REST call
+ # raises OpenTox::Error if call fails (rescued in overwrite.rb -> halt 502)
+ # @param [String] uri destination URI
+ # @param [optional,Hash] headers contains params like accept-header
+ # @return [OpenTox::WrapperResult] a String containing the result-body of the REST call
+ def self.delete(uri, headers=nil )
+ execute( "delete", uri, nil, headers)
+ end
+
+ private
+ def self.execute( rest_call, uri, payload=nil, headers={}, waiting_task=nil, wait=true )
+
+ raise OpenTox::BadRequestError.new "uri is null" unless uri
+ raise OpenTox::BadRequestError.new "not a uri: "+uri.to_s unless URI.valid? uri.to_s
+ raise "headers are no hash: "+headers.inspect unless headers==nil or headers.is_a?(Hash)
+ raise OpenTox::BadRequestError.new "accept should go into the headers" if payload and payload.is_a?(Hash) and payload[:accept]
+ raise OpenTox::BadRequestError.new "content_type should go into the headers" if payload and payload.is_a?(Hash) and payload[:content_type]
+ raise "__waiting_task__ must be 'nil' or '(sub)task', is "+waiting_task.class.to_s if
+ waiting_task!=nil and !(waiting_task.is_a?(Task) || waiting_task.is_a?(SubTask))
+ headers.each{ |k,v| headers.delete(k) if v==nil } if headers #remove keys with empty values, as this can cause problems
+ ## PENDING partner services accept subjectid only in header
+ headers = {} unless headers
+ headers[:subjectid] = payload.delete(:subjectid) if payload and payload.is_a?(Hash) and payload.has_key?(:subjectid)
+
+ # PENDING needed for NUTA, until we finally agree on how to send subjectid
+ headers[:subjectid] = payload.delete(:subjectid) if uri=~/ntua/ and payload and payload.is_a?(Hash) and payload.has_key?(:subjectid)
+
+ begin
+ #LOGGER.debug "RestCall: "+rest_call.to_s+" "+uri.to_s+" "+headers.inspect+" "+payload.inspect
+ resource = RestClient::Resource.new(uri,{:timeout => 600})
+ if rest_call=="post" || rest_call=="put"
+ result = resource.send(rest_call, payload, headers){|response, request, result| response }
+ else
+ result = resource.send(rest_call, headers){|response, request, result| response }
+ end
+ #LOGGER.debug "result body size: #{result.body.size}"
+
+ # PENDING NTUA does return errors with 200
+ raise RestClient::ExceptionWithResponse.new(result) if uri=~/ntua/ and result.body =~ /about.*http:\/\/anonymous.org\/error/
+
+ # result is a string, with the additional fields content_type and code
+ res = WrapperResult.new(result.body)
+ res.content_type = result.headers[:content_type]
+ raise "content-type not set" unless res.content_type
+ res.code = result.code
+
+ # TODO: Ambit returns task representation with 200 instead of result URI
+ return res if res.code==200 || !wait
+
+ while (res.code==201 || res.code==202)
+ res = wait_for_task(res, uri, waiting_task)
+ end
+ raise "illegal status code: '"+res.code.to_s+"'" unless res.code==200
+ return res
+
+ rescue RestClient::RequestTimeout => ex
+ received_error ex.message, 408, nil, {:rest_uri => uri, :headers => headers, :payload => payload}
+ rescue Errno::ETIMEDOUT => ex
+ received_error ex.message, 408, nil, {:rest_uri => uri, :headers => headers, :payload => payload}
+ rescue Errno::ECONNREFUSED => ex
+ received_error ex.message, 500, nil, {:rest_uri => uri, :headers => headers, :payload => payload}
+ rescue RestClient::ExceptionWithResponse => ex
+ # error comming from a different webservice,
+ received_error ex.http_body, ex.http_code, ex.response.net_http_res.content_type, {:rest_uri => uri, :headers => headers, :payload => payload}
+ rescue OpenTox::RestCallError => ex
+ # already a rest-error, probably comes from wait_for_task, just pass through
+ raise ex
+ rescue => ex
+ # some internal error occuring in rest_client_wrapper, just pass through
+ raise ex
+ end
+ end
+
+ def self.wait_for_task( res, base_uri, waiting_task=nil )
+ #TODO remove TUM hack
+ res.content_type = "text/uri-list" if base_uri =~/tu-muenchen/ and res.content_type == "application/x-www-form-urlencoded;charset=UTF-8"
+
+ task = nil
+ case res.content_type
+ when /application\/rdf\+xml/
+ task = OpenTox::Task.from_rdfxml(res)
+ when /yaml/
+ task = OpenTox::Task.from_yaml(res)
+ when /text\//
+ raise "uri list has more than one entry, should be a task" if res.content_type=~/text\/uri-list/ and res.split("\n").size > 1 #if uri list contains more then one uri, its not a task
+ task = OpenTox::Task.find(res.to_s.chomp) if res.to_s.uri?
+ else
+ raise "unknown content-type for task : '"+res.content_type.to_s+"'"+" base-uri: "+base_uri.to_s+" content: "+res[0..200].to_s
+ end
+
+ #LOGGER.debug "result is a task '"+task.uri.to_s+"', wait for completion"
+ task.wait_for_completion waiting_task
+ unless task.completed? # maybe task was cancelled / error
+ if task.errorReport
+ received_error task.errorReport, task.http_code, nil, {:rest_uri => task.uri, :rest_code => task.http_code}
+ else
+ raise "status of task '"+task.uri.to_s+"' is no longer running (hasStatus is '"+task.status+
+ "'), but it is neither completed nor has an errorReport"
+ end
+ end
+
+ res = WrapperResult.new task.result_uri
+ res.code = task.http_code
+ res.content_type = "text/uri-list"
+ return res
+ end
+
+ def self.received_error( body, code, content_type=nil, params=nil )
+
+ # try to parse body
+ report = nil
+ if body.is_a?(OpenTox::ErrorReport)
+ report = body
+ else
+ case content_type
+ when /yaml/
+ report = YAML.load(body)
+ when /rdf/
+ report = OpenTox::ErrorReport.from_rdf(body)
+ end
+ end
+
+ unless report
+ # parsing was not successfull
+ # raise 'plain' RestCallError
+ err = OpenTox::RestCallError.new("REST call returned error: '"+body.to_s+"'")
+ err.rest_params = params
+ raise err
+ else
+ # parsing sucessfull
+ # raise RestCallError with parsed report as error cause
+ err = OpenTox::RestCallError.new("REST call subsequent error")
+ err.errorCause = report
+ err.rest_params = params
+ raise err
+ end
+ end
+ end
+end
diff --git a/lib/task.rb b/lib/task.rb
index 9aaee04..286e998 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -7,7 +7,7 @@ module OpenTox
attr_accessor :pid, :observer_pid
def self.create service_uri, params={}
- task = Task.new RestClient.post(service_uri,params).chomp
+ task = Task.new RestClientWrapper.post(service_uri,params).chomp
pid = fork do
begin
result_uri = yield
@@ -53,20 +53,20 @@ module OpenTox
def cancel
kill
- RestClient.put(File.join(@uri,'Cancelled'),{})
+ RestClientWrapper.put(File.join(@uri,'Cancelled'),{})
end
def completed(uri)
#TODO: subjectid?
#TODO: error code
raise "\"#{uri}\" does not exist." unless URI.accessible? uri
- RestClient.put(File.join(@uri,'Completed'),{:resultURI => uri})
+ RestClientWrapper.put(File.join(@uri,'Completed'),{:resultURI => uri})
end
def error error
$logger.error self if $logger
report = ErrorReport.create(error,"http://localhost")
- RestClient.put(File.join(@uri,'Error'),{:errorReport => report})
+ RestClientWrapper.put(File.join(@uri,'Error'),{:errorReport => report})
kill
end
@@ -104,7 +104,7 @@ module OpenTox
begin
case method
when /=/
- res = RestClient.put(File.join(@uri,method.sub(/=/,'')),{})
+ res = RestClientWrapper.put(File.join(@uri,method.sub(/=/,'')),{})
super unless res.code == 200
#when /\?/
#return hasStatus == method.sub(/\?/,'').capitalize
--
cgit v1.2.3
From f40871b9b60ae706c0668c9ac4cfbfff866ce5dc Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Tue, 28 Feb 2012 17:13:20 +0000
Subject: generic rest-client calls ignoring http errors from task services
---
lib/error.rb | 2 +-
lib/opentox-client.rb | 2 +-
lib/opentox.rb | 16 +--
lib/rest-client-wrapper.rb | 280 +++++++++++++++++++++++++++++++++++++++++++++
lib/rest_client_wrapper.rb | 182 -----------------------------
lib/task.rb | 32 +++---
6 files changed, 303 insertions(+), 211 deletions(-)
create mode 100644 lib/rest-client-wrapper.rb
delete mode 100644 lib/rest_client_wrapper.rb
(limited to 'lib')
diff --git a/lib/error.rb b/lib/error.rb
index 6987f35..1866585 100644
--- a/lib/error.rb
+++ b/lib/error.rb
@@ -1,6 +1,6 @@
# adding additional fields to Exception class to format errors according to OT-API
class Exception
- attr_accessor :errorCause
+ attr_accessor :errorCause # is errorReport
def http_code; 500; end
end
diff --git a/lib/opentox-client.rb b/lib/opentox-client.rb
index 1a5e7c3..a587aa5 100644
--- a/lib/opentox-client.rb
+++ b/lib/opentox-client.rb
@@ -8,7 +8,7 @@ require 'yaml'
require 'logger'
require File.join(File.dirname(__FILE__),"overwrite.rb")
require File.join(File.dirname(__FILE__),"error.rb")
-require File.join(File.dirname(__FILE__),"rest_client_wrapper.rb")
+require File.join(File.dirname(__FILE__),"rest-client-wrapper.rb")
require File.join(File.dirname(__FILE__),"otlogger.rb") # avoid require conflicts with logger
require File.join(File.dirname(__FILE__),"opentox.rb")
require File.join(File.dirname(__FILE__),"task.rb")
diff --git a/lib/opentox.rb b/lib/opentox.rb
index f81ae10..145aeb6 100644
--- a/lib/opentox.rb
+++ b/lib/opentox.rb
@@ -20,24 +20,16 @@ module OpenTox
# Ruby interface
- # override to read all error codes
def metadata reload=true
if reload or @metadata.empty?
@metadata = {}
- # ignore error codes from Task services (may contain eg 500 which causes exceptions in RestClient and RDF::Reader
- # TODO: convert to RestClientWrapper
kind_of?(OpenTox::Dataset) ? uri = File.join(@uri,"metadata") : uri = @uri
- RestClient.get(uri) do |response, request, result|
- #response = RestClientWrapper.get(@uri) #do |response, request, result|
- $logger.warn "#{@uri} returned #{result}" unless response.code == 200 or response.code == 202 or URI.task? @uri
- RDF::Reader.for(:rdfxml).new(response) do |reader|
- reader.each_statement do |statement|
- @metadata[statement.predicate] = statement.object if statement.subject == @uri
- end
+ RDF::Reader.for(:rdfxml).new( RestClientWrapper.get(@uri) ) do |reader|
+ reader.each_statement do |statement|
+ @metadata[statement.predicate] = statement.object if statement.subject == @uri
end
end
end
- #puts @metadata.inspect
@metadata
end
@@ -52,7 +44,7 @@ module OpenTox
def get params={}
params[:subjectid] ||= @subjectid
params[:accept] ||= 'application/rdf+xml'
- @response = RestClientWrapper.get @uri, params
+ @response = RestClientWrapper.get @uri, {}, params
end
def post payload={}, params={}
diff --git a/lib/rest-client-wrapper.rb b/lib/rest-client-wrapper.rb
new file mode 100644
index 0000000..95aee8e
--- /dev/null
+++ b/lib/rest-client-wrapper.rb
@@ -0,0 +1,280 @@
+module OpenTox
+
+ class WrapperResult < String
+ attr_accessor :content_type, :code
+ end
+
+ class RestClientWrapper
+
+ # create REST class methods
+ [:head,:get,:post,:put,:dealete].each do |method|
+
+ #define_singleton_method method do |uri,args={},headers={},waiting_task=nil, wait=true|
+ define_singleton_method method do |uri,payload={},headers={},waiting_task=nil, wait=true|
+
+ args={}
+ args[:method] = method
+ args[:url] = uri
+ args[:timeout] = 600
+ args[:payload] = payload
+ args[:headers] = headers
+ #raise OpenTox::BadRequestError.new "Empty URI." unless uri # error raised at method call
+ raise OpenTox::BadRequestError.new "Invalid URI: '#{uri}'" unless URI.valid? uri
+ raise OpenTox::BadRequestError.new "Unreachable URI: '#{uri}'" unless URI.accessible? uri
+=begin
+ raise "headers are no hash: "+headers.inspect unless headers==nil or headers.is_a?(Hash)
+ # TODO: loop over accept, contant_type, subjectid
+ raise OpenTox::BadRequestError.new "accept should go into the headers" if payload and payload.is_a?(Hash) and payload[:accept]
+ raise OpenTox::BadRequestError.new "content_type should go into the headers" if payload and payload.is_a?(Hash) and payload[:content_type]
+ raise OpenTox::BadRequestError.new "subjectid should go into the headers" if payload and payload.is_a?(Hash) and payload[:subjectid]
+ raise "__waiting_task__ must be 'nil' or '(sub)task', is "+waiting_task.class.to_s if
+ waiting_task!=nil and !(waiting_task.is_a?(Task) || waiting_task.is_a?(SubTask))
+ headers.each{ |k,v| headers.delete(k) if v==nil } if headers #remove keys with empty values, as this can cause problems
+ ## PENDING partner services accept subjectid only in header
+ headers = {} unless headers
+ #headers[:subjectid] = payload.delete(:subjectid) if payload and payload.is_a?(Hash) and payload.has_key?(:subjectid)
+
+ # PENDING needed for NUTA, until we finally agree on how to send subjectid
+ #headers[:subjectid] = payload.delete(:subjectid) if uri=~/ntua/ and payload and payload.is_a?(Hash) and payload.has_key?(:subjectid)
+=end
+
+ begin
+ #$logger.debug "RestCall: "+method.to_s+" "+uri.to_s+" "+headers.inspect+" "+args.inspect
+ request = RestClient::Request.new(args)
+ result = request.execute do |response, request, result|
+ unless response.code < 400 or URI.task? uri
+ $logger.error "#{uri} returned #{result.inspect}"
+ raise OpenTox::RestCallError result.inspect
+ end
+ return response
+ end
+ # ignore error codes from Task services (may contain eg 500 which causes exceptions in RestClient and RDF::Reader
+ #LOGGER.debug "result body size: #{result.body.size}"
+
+ # PENDING NTUA does return errors with 200
+ raise RestClient::ExceptionWithResponse.new(result) if uri=~/ntua/ and result.body =~ /about.*http:\/\/anonymous.org\/error/
+
+ # result is a string, with the additional fields content_type and code
+ res = WrapperResult.new(result.body)
+ res.content_type = result.headers[:content_type]
+ raise "content-type not set" unless res.content_type
+ res.code = result.code
+
+ # TODO: Ambit returns task representation with 200 instead of result URI
+ return res if res.code==200 || !wait
+
+ while (res.code==201 || res.code==202)
+ res = wait_for_task(res, uri, waiting_task)
+ end
+ raise "illegal status code: '"+res.code.to_s+"'" unless res.code==200
+ return res
+
+ rescue RestClient::RequestTimeout => ex
+ received_error ex.message, 408, nil, {:rest_uri => uri, :headers => headers, :payload => payload}
+ rescue Errno::ETIMEDOUT => ex
+ received_error ex.message, 408, nil, {:rest_uri => uri, :headers => headers, :payload => payload}
+ rescue Errno::ECONNREFUSED => ex
+ received_error ex.message, 500, nil, {:rest_uri => uri, :headers => headers, :payload => payload}
+ rescue RestClient::ExceptionWithResponse => ex
+ # error comming from a different webservice,
+ received_error ex.http_body, ex.http_code, ex.response.net_http_res.content_type, {:rest_uri => uri, :headers => headers, :payload => payload}
+ rescue OpenTox::RestCallError => ex
+ # already a rest-error, probably comes from wait_for_task, just pass through
+ raise ex
+ rescue => ex
+ # some internal error occuring in rest-client-wrapper, just pass through
+ raise ex
+ end
+ end
+ end
+
+=begin
+ # performs a GET REST call
+ # raises OpenTox::Error if call fails (rescued in overwrite.rb -> halt 502)
+ # per default: waits for Task to finish and returns result URI of Task
+ # @param [String] uri destination URI
+ # @param [optional,Hash] headers contains params like accept-header
+ # @param [optional,OpenTox::Task] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
+ # @param [wait,Boolean] wait set to false to NOT wait for task if result is task
+ # @return [OpenTox::WrapperResult] a String containing the result-body of the REST call
+ def self.get(uri, headers={}, waiting_task=nil, wait=true )
+ execute( "get", uri, nil, headers, waiting_task, wait)
+ end
+
+ # performs a POST REST call
+ # raises OpenTox::Error if call fails (rescued in overwrite.rb -> halt 502)
+ # per default: waits for Task to finish and returns result URI of Task
+ # @param [String] uri destination URI
+ # @param [optional,String] payload data posted to the service
+ # @param [optional,Hash] headers contains params like accept-header
+ # @param [optional,OpenTox::Task] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
+ # @param [wait,Boolean] wait set to false to NOT wait for task if result is task
+ # @return [OpenTox::WrapperResult] a String containing the result-body of the REST call
+ def self.post(uri, payload=nil, headers={}, waiting_task=nil, wait=true )
+ execute( "post", uri, payload, headers, waiting_task, wait )
+ end
+
+ # performs a PUT REST call
+ # raises OpenTox::Error if call fails (rescued in overwrite.rb -> halt 502)
+ # @param [String] uri destination URI
+ # @param [optional,Hash] headers contains params like accept-header
+ # @param [optional,String] payload data put to the service
+ # @return [OpenTox::WrapperResult] a String containing the result-body of the REST call
+ def self.put(uri, payload=nil, headers={} )
+ execute( "put", uri, payload, headers )
+ end
+
+ # performs a DELETE REST call
+ # raises OpenTox::Error if call fails (rescued in overwrite.rb -> halt 502)
+ # @param [String] uri destination URI
+ # @param [optional,Hash] headers contains params like accept-header
+ # @return [OpenTox::WrapperResult] a String containing the result-body of the REST call
+ def self.delete(uri, headers=nil )
+ execute( "delete", uri, nil, headers)
+ end
+
+ def self.head(uri)
+ execute("head",uri)
+ end
+
+ private
+ def self.execute( rest_call, uri, payload=nil, headers={}, waiting_task=nil, wait=true )
+
+ raise OpenTox::BadRequestError.new "Empty URI." unless uri
+ raise OpenTox::BadRequestError.new "Invalid URI: '#{uri}'" unless URI.valid? uri
+ raise OpenTox::BadRequestError.new "Unreachable URI: '#{uri}'" unless URI.accessible? uri
+ raise "headers are no hash: "+headers.inspect unless headers==nil or headers.is_a?(Hash)
+ # TODO: loop over accept, contant_type, subjectid
+ raise OpenTox::BadRequestError.new "accept should go into the headers" if payload and payload.is_a?(Hash) and payload[:accept]
+ raise OpenTox::BadRequestError.new "content_type should go into the headers" if payload and payload.is_a?(Hash) and payload[:content_type]
+ raise OpenTox::BadRequestError.new "subjectid should go into the headers" if payload and payload.is_a?(Hash) and payload[:subjectid]
+ raise "__waiting_task__ must be 'nil' or '(sub)task', is "+waiting_task.class.to_s if
+ waiting_task!=nil and !(waiting_task.is_a?(Task) || waiting_task.is_a?(SubTask))
+ headers.each{ |k,v| headers.delete(k) if v==nil } if headers #remove keys with empty values, as this can cause problems
+ ## PENDING partner services accept subjectid only in header
+ headers = {} unless headers
+ #headers[:subjectid] = payload.delete(:subjectid) if payload and payload.is_a?(Hash) and payload.has_key?(:subjectid)
+
+ # PENDING needed for NUTA, until we finally agree on how to send subjectid
+ #headers[:subjectid] = payload.delete(:subjectid) if uri=~/ntua/ and payload and payload.is_a?(Hash) and payload.has_key?(:subjectid)
+
+ begin
+ #LOGGER.debug "RestCall: "+rest_call.to_s+" "+uri.to_s+" "+headers.inspect+" "+payload.inspect
+ resource = RestClient::Resource.new(uri,{:timeout => 600})
+ if rest_call=="post" || rest_call=="put"
+ result = resource.send(rest_call, payload, headers){|response, request, result| return response }
+ elsif rest_call == "head"
+ result = resource.send(rest_call){ |response, request, result| return response }
+ else
+ result = resource.send(rest_call, headers){|response, request, result| return response }
+ end
+ # ignore error codes from Task services (may contain eg 500 which causes exceptions in RestClient and RDF::Reader
+ unless result.code < 400 or URI.task? @uri
+ $logger.error "#{@uri} returned #{result}"
+ raise OpenTox::RestCallError result
+ end
+ #LOGGER.debug "result body size: #{result.body.size}"
+
+ # PENDING NTUA does return errors with 200
+ raise RestClient::ExceptionWithResponse.new(result) if uri=~/ntua/ and result.body =~ /about.*http:\/\/anonymous.org\/error/
+
+ # result is a string, with the additional fields content_type and code
+ res = WrapperResult.new(result.body)
+ res.content_type = result.headers[:content_type]
+ raise "content-type not set" unless res.content_type
+ res.code = result.code
+
+ # TODO: Ambit returns task representation with 200 instead of result URI
+ return res if res.code==200 || !wait
+
+ while (res.code==201 || res.code==202)
+ res = wait_for_task(res, uri, waiting_task)
+ end
+ raise "illegal status code: '"+res.code.to_s+"'" unless res.code==200
+ return res
+
+ rescue RestClient::RequestTimeout => ex
+ received_error ex.message, 408, nil, {:rest_uri => uri, :headers => headers, :payload => payload}
+ rescue Errno::ETIMEDOUT => ex
+ received_error ex.message, 408, nil, {:rest_uri => uri, :headers => headers, :payload => payload}
+ rescue Errno::ECONNREFUSED => ex
+ received_error ex.message, 500, nil, {:rest_uri => uri, :headers => headers, :payload => payload}
+ rescue RestClient::ExceptionWithResponse => ex
+ # error comming from a different webservice,
+ received_error ex.http_body, ex.http_code, ex.response.net_http_res.content_type, {:rest_uri => uri, :headers => headers, :payload => payload}
+ rescue OpenTox::RestCallError => ex
+ # already a rest-error, probably comes from wait_for_task, just pass through
+ raise ex
+ rescue => ex
+ # some internal error occuring in rest-client-wrapper, just pass through
+ raise ex
+ end
+ end
+=end
+
+ def self.wait_for_task( res, base_uri, waiting_task=nil )
+ #TODO remove TUM hack
+ res.content_type = "text/uri-list" if base_uri =~/tu-muenchen/ and res.content_type == "application/x-www-form-urlencoded;charset=UTF-8"
+
+ task = nil
+ case res.content_type
+ when /application\/rdf\+xml/
+ task = OpenTox::Task.from_rdfxml(res)
+ when /yaml/
+ task = OpenTox::Task.from_yaml(res)
+ when /text\//
+ raise "uri list has more than one entry, should be a task" if res.content_type=~/text\/uri-list/ and res.split("\n").size > 1 #if uri list contains more then one uri, its not a task
+ task = OpenTox::Task.find(res.to_s.chomp) if res.to_s.uri?
+ else
+ raise "unknown content-type for task : '"+res.content_type.to_s+"'"+" base-uri: "+base_uri.to_s+" content: "+res[0..200].to_s
+ end
+
+ #LOGGER.debug "result is a task '"+task.uri.to_s+"', wait for completion"
+ task.wait waiting_task
+ unless task.completed? # maybe task was cancelled / error
+ if task.errorReport
+ received_error task.errorReport, task.http_code, nil, {:rest_uri => task.uri, :rest_code => task.http_code}
+ else
+ raise "status of task '"+task.uri.to_s+"' is no longer running (hasStatus is '"+task.status+
+ "'), but it is neither completed nor has an errorReport"
+ end
+ end
+
+ res = WrapperResult.new task.result_uri
+ res.code = task.http_code
+ res.content_type ="text/uri-list"
+ return res
+ end
+
+ def self.received_error( body, code, content_type=nil, params=nil )
+
+ # try to parse body
+ report = nil
+ if body.is_a?(OpenTox::ErrorReport)
+ report = body
+ else
+ case content_type
+ when /yaml/
+ report = YAML.load(body)
+ when /rdf/
+ report = OpenTox::ErrorReport.from_rdf(body)
+ end
+ end
+
+ unless report
+ # parsing was not successfull
+ # raise 'plain' RestCallError
+ err = OpenTox::RestCallError.new("REST call returned error: '"+body.to_s+"'")
+ err.rest_params = params
+ raise err
+ else
+ # parsing sucessfull
+ # raise RestCallError with parsed report as error cause
+ err = OpenTox::RestCallError.new("REST call subsequent error")
+ err.errorCause = report
+ err.rest_params = params
+ raise err
+ end
+ end
+ end
+end
diff --git a/lib/rest_client_wrapper.rb b/lib/rest_client_wrapper.rb
deleted file mode 100644
index 89de277..0000000
--- a/lib/rest_client_wrapper.rb
+++ /dev/null
@@ -1,182 +0,0 @@
-module OpenTox
-
- class WrapperResult < String
- attr_accessor :content_type, :code
- end
-
- class RestClientWrapper
-
- # performs a GET REST call
- # raises OpenTox::Error if call fails (rescued in overwrite.rb -> halt 502)
- # per default: waits for Task to finish and returns result URI of Task
- # @param [String] uri destination URI
- # @param [optional,Hash] headers contains params like accept-header
- # @param [optional,OpenTox::Task] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
- # @param [wait,Boolean] wait set to false to NOT wait for task if result is task
- # @return [OpenTox::WrapperResult] a String containing the result-body of the REST call
- def self.get(uri, headers={}, waiting_task=nil, wait=true )
- execute( "get", uri, nil, headers, waiting_task, wait)
- end
-
- # performs a POST REST call
- # raises OpenTox::Error if call fails (rescued in overwrite.rb -> halt 502)
- # per default: waits for Task to finish and returns result URI of Task
- # @param [String] uri destination URI
- # @param [optional,String] payload data posted to the service
- # @param [optional,Hash] headers contains params like accept-header
- # @param [optional,OpenTox::Task] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
- # @param [wait,Boolean] wait set to false to NOT wait for task if result is task
- # @return [OpenTox::WrapperResult] a String containing the result-body of the REST call
- def self.post(uri, payload=nil, headers={}, waiting_task=nil, wait=true )
- execute( "post", uri, payload, headers, waiting_task, wait )
- end
-
- # performs a PUT REST call
- # raises OpenTox::Error if call fails (rescued in overwrite.rb -> halt 502)
- # @param [String] uri destination URI
- # @param [optional,Hash] headers contains params like accept-header
- # @param [optional,String] payload data put to the service
- # @return [OpenTox::WrapperResult] a String containing the result-body of the REST call
- def self.put(uri, payload=nil, headers={} )
- execute( "put", uri, payload, headers )
- end
-
- # performs a DELETE REST call
- # raises OpenTox::Error if call fails (rescued in overwrite.rb -> halt 502)
- # @param [String] uri destination URI
- # @param [optional,Hash] headers contains params like accept-header
- # @return [OpenTox::WrapperResult] a String containing the result-body of the REST call
- def self.delete(uri, headers=nil )
- execute( "delete", uri, nil, headers)
- end
-
- private
- def self.execute( rest_call, uri, payload=nil, headers={}, waiting_task=nil, wait=true )
-
- raise OpenTox::BadRequestError.new "uri is null" unless uri
- raise OpenTox::BadRequestError.new "not a uri: "+uri.to_s unless URI.valid? uri.to_s
- raise "headers are no hash: "+headers.inspect unless headers==nil or headers.is_a?(Hash)
- raise OpenTox::BadRequestError.new "accept should go into the headers" if payload and payload.is_a?(Hash) and payload[:accept]
- raise OpenTox::BadRequestError.new "content_type should go into the headers" if payload and payload.is_a?(Hash) and payload[:content_type]
- raise "__waiting_task__ must be 'nil' or '(sub)task', is "+waiting_task.class.to_s if
- waiting_task!=nil and !(waiting_task.is_a?(Task) || waiting_task.is_a?(SubTask))
- headers.each{ |k,v| headers.delete(k) if v==nil } if headers #remove keys with empty values, as this can cause problems
- ## PENDING partner services accept subjectid only in header
- headers = {} unless headers
- headers[:subjectid] = payload.delete(:subjectid) if payload and payload.is_a?(Hash) and payload.has_key?(:subjectid)
-
- # PENDING needed for NUTA, until we finally agree on how to send subjectid
- headers[:subjectid] = payload.delete(:subjectid) if uri=~/ntua/ and payload and payload.is_a?(Hash) and payload.has_key?(:subjectid)
-
- begin
- #LOGGER.debug "RestCall: "+rest_call.to_s+" "+uri.to_s+" "+headers.inspect+" "+payload.inspect
- resource = RestClient::Resource.new(uri,{:timeout => 600})
- if rest_call=="post" || rest_call=="put"
- result = resource.send(rest_call, payload, headers){|response, request, result| response }
- else
- result = resource.send(rest_call, headers){|response, request, result| response }
- end
- #LOGGER.debug "result body size: #{result.body.size}"
-
- # PENDING NTUA does return errors with 200
- raise RestClient::ExceptionWithResponse.new(result) if uri=~/ntua/ and result.body =~ /about.*http:\/\/anonymous.org\/error/
-
- # result is a string, with the additional fields content_type and code
- res = WrapperResult.new(result.body)
- res.content_type = result.headers[:content_type]
- raise "content-type not set" unless res.content_type
- res.code = result.code
-
- # TODO: Ambit returns task representation with 200 instead of result URI
- return res if res.code==200 || !wait
-
- while (res.code==201 || res.code==202)
- res = wait_for_task(res, uri, waiting_task)
- end
- raise "illegal status code: '"+res.code.to_s+"'" unless res.code==200
- return res
-
- rescue RestClient::RequestTimeout => ex
- received_error ex.message, 408, nil, {:rest_uri => uri, :headers => headers, :payload => payload}
- rescue Errno::ETIMEDOUT => ex
- received_error ex.message, 408, nil, {:rest_uri => uri, :headers => headers, :payload => payload}
- rescue Errno::ECONNREFUSED => ex
- received_error ex.message, 500, nil, {:rest_uri => uri, :headers => headers, :payload => payload}
- rescue RestClient::ExceptionWithResponse => ex
- # error comming from a different webservice,
- received_error ex.http_body, ex.http_code, ex.response.net_http_res.content_type, {:rest_uri => uri, :headers => headers, :payload => payload}
- rescue OpenTox::RestCallError => ex
- # already a rest-error, probably comes from wait_for_task, just pass through
- raise ex
- rescue => ex
- # some internal error occuring in rest_client_wrapper, just pass through
- raise ex
- end
- end
-
- def self.wait_for_task( res, base_uri, waiting_task=nil )
- #TODO remove TUM hack
- res.content_type = "text/uri-list" if base_uri =~/tu-muenchen/ and res.content_type == "application/x-www-form-urlencoded;charset=UTF-8"
-
- task = nil
- case res.content_type
- when /application\/rdf\+xml/
- task = OpenTox::Task.from_rdfxml(res)
- when /yaml/
- task = OpenTox::Task.from_yaml(res)
- when /text\//
- raise "uri list has more than one entry, should be a task" if res.content_type=~/text\/uri-list/ and res.split("\n").size > 1 #if uri list contains more then one uri, its not a task
- task = OpenTox::Task.find(res.to_s.chomp) if res.to_s.uri?
- else
- raise "unknown content-type for task : '"+res.content_type.to_s+"'"+" base-uri: "+base_uri.to_s+" content: "+res[0..200].to_s
- end
-
- #LOGGER.debug "result is a task '"+task.uri.to_s+"', wait for completion"
- task.wait_for_completion waiting_task
- unless task.completed? # maybe task was cancelled / error
- if task.errorReport
- received_error task.errorReport, task.http_code, nil, {:rest_uri => task.uri, :rest_code => task.http_code}
- else
- raise "status of task '"+task.uri.to_s+"' is no longer running (hasStatus is '"+task.status+
- "'), but it is neither completed nor has an errorReport"
- end
- end
-
- res = WrapperResult.new task.result_uri
- res.code = task.http_code
- res.content_type = "text/uri-list"
- return res
- end
-
- def self.received_error( body, code, content_type=nil, params=nil )
-
- # try to parse body
- report = nil
- if body.is_a?(OpenTox::ErrorReport)
- report = body
- else
- case content_type
- when /yaml/
- report = YAML.load(body)
- when /rdf/
- report = OpenTox::ErrorReport.from_rdf(body)
- end
- end
-
- unless report
- # parsing was not successfull
- # raise 'plain' RestCallError
- err = OpenTox::RestCallError.new("REST call returned error: '"+body.to_s+"'")
- err.rest_params = params
- raise err
- else
- # parsing sucessfull
- # raise RestCallError with parsed report as error cause
- err = OpenTox::RestCallError.new("REST call subsequent error")
- err.errorCause = report
- err.rest_params = params
- raise err
- end
- end
- end
-end
diff --git a/lib/task.rb b/lib/task.rb
index 286e998..635584f 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -6,7 +6,9 @@ module OpenTox
class Task
attr_accessor :pid, :observer_pid
+
def self.create service_uri, params={}
+
task = Task.new RestClientWrapper.post(service_uri,params).chomp
pid = fork do
begin
@@ -17,19 +19,15 @@ module OpenTox
raise "#{result_uri} is not a valid URI"
end
rescue
- # TODO add service URI to Kernel.raise
- # serialize error and send to task service
- #task.error $!
task.error $!
- raise
end
end
Process.detach(pid)
task.pid = pid
- # watch if task has been cancelled
+ # watch if task has been cancelled
observer_pid = fork do
- task.wait_for_completion
+ task.wait
begin
Process.kill(9,task.pid) if task.cancelled?
rescue
@@ -39,6 +37,7 @@ module OpenTox
Process.detach(observer_pid)
task.observer_pid = observer_pid
task
+
end
def kill
@@ -50,6 +49,10 @@ module OpenTox
def description
metadata[RDF::DC.description]
end
+
+ def creator
+ metadata[RDF::DC.creator]
+ end
def cancel
kill
@@ -64,15 +67,16 @@ module OpenTox
end
def error error
- $logger.error self if $logger
- report = ErrorReport.create(error,"http://localhost")
+ $logger.error self
+ report = ErrorReport.create(error,self.creator)
RestClientWrapper.put(File.join(@uri,'Error'),{:errorReport => report})
kill
+ raise error
end
# waits for a task, unless time exceeds or state is no longer running
# @param [optional,Numeric] dur seconds pausing before checking again for completion
- def wait_for_completion(dur=0.3)
+ def wait(dur=0.3)
due_to_time = Time.new + DEFAULT_TASK_MAX_DURATION
while running?
sleep dur
@@ -84,19 +88,19 @@ module OpenTox
# get only header for ststus requests
def running?
- RestClient.head(@uri){ |response, request, result| result.code.to_i == 202 }
+ RestClientWrapper.head(@uri).code == 202
end
def cancelled?
- RestClient.head(@uri){ |response, request, result| result.code.to_i == 503 }
+ RestClientWrapper.head(@uri).code == 503
end
def completed?
- RestClient.head(@uri){ |response, request, result| result.code.to_i == 200 }
+ RestClientWrapper.head(@uri).code == 200
end
def error?
- RestClient.head(@uri){ |response, request, result| result.code.to_i == 500 }
+ RestClientWrapper.head(@uri).code == 500
end
def method_missing(method,*args)
@@ -106,8 +110,6 @@ module OpenTox
when /=/
res = RestClientWrapper.put(File.join(@uri,method.sub(/=/,'')),{})
super unless res.code == 200
- #when /\?/
- #return hasStatus == method.sub(/\?/,'').capitalize
else
response = metadata[RDF::OT[method]].to_s
response = metadata[RDF::OT1[method]].to_s #if response.empty? # API 1.1 compatibility
--
cgit v1.2.3
From f0d38b06cbdcfd59494c220e6f4685f2e5aa38fd Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Wed, 29 Feb 2012 15:06:27 +0000
Subject: logging in error.rb, dynamic class methods in rest-client-wrapper.rb
---
lib/error.rb | 17 +++-
lib/opentox.rb | 32 +++----
lib/rest-client-wrapper.rb | 232 +++++++++------------------------------------
3 files changed, 75 insertions(+), 206 deletions(-)
(limited to 'lib')
diff --git a/lib/error.rb b/lib/error.rb
index 1866585..b832ef4 100644
--- a/lib/error.rb
+++ b/lib/error.rb
@@ -1,6 +1,15 @@
# adding additional fields to Exception class to format errors according to OT-API
+=begin
class Exception
+end
+=end
+
+class RuntimeError
attr_accessor :errorCause # is errorReport
+ def initialize msg=nil
+ $logger.error msg
+ super msg
+ end
def http_code; 500; end
end
@@ -26,13 +35,15 @@ module OpenTox
def http_code; 503; end
end
- # TODO: add to RestClientCalls
class RestCallError < RuntimeError
- attr_accessor :rest_params
+ def initialize request, response, expectation=nil
+ msg = "REST request: #{request.inspect}\nREST response: #{response.inspect}"
+ msg += "\n"+expectation if expectation
+ super msg
+ end
def http_code; 502; end
end
- # TODO: add to Exception class??
class ErrorReport
# TODO replace params with URIs (errorCause -> OT.errorCause)
diff --git a/lib/opentox.rb b/lib/opentox.rb
index 145aeb6..4c2a668 100644
--- a/lib/opentox.rb
+++ b/lib/opentox.rb
@@ -41,27 +41,27 @@ module OpenTox
end
# REST API
- def get params={}
- params[:subjectid] ||= @subjectid
- params[:accept] ||= 'application/rdf+xml'
- @response = RestClientWrapper.get @uri, {}, params
+ def get headers={}
+ headers[:subjectid] ||= @subjectid
+ headers[:accept] ||= 'application/rdf+xml'
+ @response = RestClientWrapper.get @uri, {}, headers
end
- def post payload={}, params={}
- params[:subjectid] ||= @subjectid
- params[:accept] ||= 'application/rdf+xml'
- @response = RestClientWrapper.post(@uri.to_s, payload, params)
+ def post payload={}, headers={}
+ headers[:subjectid] ||= @subjectid
+ headers[:accept] ||= 'application/rdf+xml'
+ @response = RestClientWrapper.post(@uri.to_s, payload, headers)
end
- def put payload={}, params={}
- params[:subjectid] ||= @subjectid
- params[:accept] ||= 'application/rdf+xml'
- @response = RestClientWrapper.put(@uri.to_s, payload, params)
+ def put payload={}, headers={}
+ headers[:subjectid] ||= @subjectid
+ headers[:accept] ||= 'application/rdf+xml'
+ @response = RestClientWrapper.put(@uri.to_s, payload, headers)
end
- def delete params={}
- params[:subjectid] ||= @subjectid
- params[:accept] ||= 'application/rdf+xml'
+ def delete headers={}
+ headers[:subjectid] ||= @subjectid
+ headers[:accept] ||= 'application/rdf+xml'
@response = RestClientWrapper.delete(@uri.to_s,:subjectid => @subjectid)
end
@@ -78,7 +78,7 @@ module OpenTox
end
def all service_uri, subjectid=nil
- uris = RestClientWrapper.get(service_uri, {:accept => 'text/uri-list'}).split("\n").compact
+ uris = RestClientWrapper.get(service_uri, nil, {:accept => 'text/uri-list'}).split("\n").compact
uris.collect{|uri| subjectid ? eval("#{self}.new(\"#{uri}\", #{subjectid})") : eval("#{self}.new(\"#{uri}\")")}
end
diff --git a/lib/rest-client-wrapper.rb b/lib/rest-client-wrapper.rb
index 95aee8e..27538e4 100644
--- a/lib/rest-client-wrapper.rb
+++ b/lib/rest-client-wrapper.rb
@@ -1,73 +1,57 @@
module OpenTox
- class WrapperResult < String
- attr_accessor :content_type, :code
- end
-
class RestClientWrapper
- # create REST class methods
+ # REST methods
+ # Raises OpenTox::Error if call fails (rescued in overwrite.rb -> halt 502)
+ # Waits for Task to finish and returns result URI of Task per default
+ # @param [String] destination URI
+ # @param [optional,Hash|String] Payload data posted to the service
+ # @param [optional,Hash] Headers with params like :accept, :content_type, :subjectid
+ # @param [optional,OpenTox::Task] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
+ # @param [wait,Boolean] Set to false to NOT wait for task if result is a task
+ # @return [RestClient::Response] REST call response
[:head,:get,:post,:put,:dealete].each do |method|
- #define_singleton_method method do |uri,args={},headers={},waiting_task=nil, wait=true|
define_singleton_method method do |uri,payload={},headers={},waiting_task=nil, wait=true|
+ # catch input errors
+ raise OpenTox::BadRequestError.new "Invalid URI: '#{uri}'" unless URI.valid? uri
+ raise OpenTox::BadRequestError.new "Unreachable URI: '#{uri}'" unless URI.accessible? uri
+ raise OpenTox::BadRequestError.new "Headers are not a hash: #{headers.inspect}" unless headers==nil or headers.is_a?(Hash)
+ [:accept,:content_type,:subjectid].each do |header|
+ raise OpenTox::BadRequestError.new "#{header} should be submitted in the headers" if payload and payload.is_a?(Hash) and payload[header]
+ end
+ raise OpenTox::BadRequestError "waiting_task is not 'nil', OpenTox::SubTask or OpenTox::Task: #{waiting_task.class}" unless waiting_task.nil? or waiting_task.is_a?(OpenTox::Task) or waiting_task.is_a?(OpenTox::SubTask)
+
args={}
args[:method] = method
args[:url] = uri
args[:timeout] = 600
args[:payload] = payload
- args[:headers] = headers
- #raise OpenTox::BadRequestError.new "Empty URI." unless uri # error raised at method call
- raise OpenTox::BadRequestError.new "Invalid URI: '#{uri}'" unless URI.valid? uri
- raise OpenTox::BadRequestError.new "Unreachable URI: '#{uri}'" unless URI.accessible? uri
-=begin
- raise "headers are no hash: "+headers.inspect unless headers==nil or headers.is_a?(Hash)
- # TODO: loop over accept, contant_type, subjectid
- raise OpenTox::BadRequestError.new "accept should go into the headers" if payload and payload.is_a?(Hash) and payload[:accept]
- raise OpenTox::BadRequestError.new "content_type should go into the headers" if payload and payload.is_a?(Hash) and payload[:content_type]
- raise OpenTox::BadRequestError.new "subjectid should go into the headers" if payload and payload.is_a?(Hash) and payload[:subjectid]
- raise "__waiting_task__ must be 'nil' or '(sub)task', is "+waiting_task.class.to_s if
- waiting_task!=nil and !(waiting_task.is_a?(Task) || waiting_task.is_a?(SubTask))
headers.each{ |k,v| headers.delete(k) if v==nil } if headers #remove keys with empty values, as this can cause problems
- ## PENDING partner services accept subjectid only in header
- headers = {} unless headers
- #headers[:subjectid] = payload.delete(:subjectid) if payload and payload.is_a?(Hash) and payload.has_key?(:subjectid)
-
- # PENDING needed for NUTA, until we finally agree on how to send subjectid
- #headers[:subjectid] = payload.delete(:subjectid) if uri=~/ntua/ and payload and payload.is_a?(Hash) and payload.has_key?(:subjectid)
-=end
+ args[:headers] = headers
+
begin
- #$logger.debug "RestCall: "+method.to_s+" "+uri.to_s+" "+headers.inspect+" "+args.inspect
request = RestClient::Request.new(args)
- result = request.execute do |response, request, result|
- unless response.code < 400 or URI.task? uri
- $logger.error "#{uri} returned #{result.inspect}"
- raise OpenTox::RestCallError result.inspect
- end
+ response = request.execute do |response, request, result|
+ # ignore error codes from Task services (may contain eg 500 which causes exceptions in RestClient and RDF::Reader
+ raise OpenTox::RestCallError request, response unless response.code < 400 or URI.task? uri
return response
end
- # ignore error codes from Task services (may contain eg 500 which causes exceptions in RestClient and RDF::Reader
- #LOGGER.debug "result body size: #{result.body.size}"
+ # TODO: tests for workarounds
# PENDING NTUA does return errors with 200
- raise RestClient::ExceptionWithResponse.new(result) if uri=~/ntua/ and result.body =~ /about.*http:\/\/anonymous.org\/error/
-
- # result is a string, with the additional fields content_type and code
- res = WrapperResult.new(result.body)
- res.content_type = result.headers[:content_type]
- raise "content-type not set" unless res.content_type
- res.code = result.code
+ #raise RestClient::ExceptionWithResponse.new(response) if uri=~/ntua/ and response.body =~ /about.*http:\/\/anonymous.org\/error/
- # TODO: Ambit returns task representation with 200 instead of result URI
- return res if res.code==200 || !wait
-
- while (res.code==201 || res.code==202)
- res = wait_for_task(res, uri, waiting_task)
+ return response if response.code==200 or wait.false?
+
+ # wait for task
+ while response.code==201 or response.code==202
+ response = wait_for_task(response, uri, waiting_task)
end
- raise "illegal status code: '"+res.code.to_s+"'" unless res.code==200
- return res
+ return response
rescue RestClient::RequestTimeout => ex
received_error ex.message, 408, nil, {:rest_uri => uri, :headers => headers, :payload => payload}
@@ -87,146 +71,24 @@ module OpenTox
end
end
end
-
-=begin
- # performs a GET REST call
- # raises OpenTox::Error if call fails (rescued in overwrite.rb -> halt 502)
- # per default: waits for Task to finish and returns result URI of Task
- # @param [String] uri destination URI
- # @param [optional,Hash] headers contains params like accept-header
- # @param [optional,OpenTox::Task] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
- # @param [wait,Boolean] wait set to false to NOT wait for task if result is task
- # @return [OpenTox::WrapperResult] a String containing the result-body of the REST call
- def self.get(uri, headers={}, waiting_task=nil, wait=true )
- execute( "get", uri, nil, headers, waiting_task, wait)
- end
-
- # performs a POST REST call
- # raises OpenTox::Error if call fails (rescued in overwrite.rb -> halt 502)
- # per default: waits for Task to finish and returns result URI of Task
- # @param [String] uri destination URI
- # @param [optional,String] payload data posted to the service
- # @param [optional,Hash] headers contains params like accept-header
- # @param [optional,OpenTox::Task] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
- # @param [wait,Boolean] wait set to false to NOT wait for task if result is task
- # @return [OpenTox::WrapperResult] a String containing the result-body of the REST call
- def self.post(uri, payload=nil, headers={}, waiting_task=nil, wait=true )
- execute( "post", uri, payload, headers, waiting_task, wait )
- end
-
- # performs a PUT REST call
- # raises OpenTox::Error if call fails (rescued in overwrite.rb -> halt 502)
- # @param [String] uri destination URI
- # @param [optional,Hash] headers contains params like accept-header
- # @param [optional,String] payload data put to the service
- # @return [OpenTox::WrapperResult] a String containing the result-body of the REST call
- def self.put(uri, payload=nil, headers={} )
- execute( "put", uri, payload, headers )
- end
-
- # performs a DELETE REST call
- # raises OpenTox::Error if call fails (rescued in overwrite.rb -> halt 502)
- # @param [String] uri destination URI
- # @param [optional,Hash] headers contains params like accept-header
- # @return [OpenTox::WrapperResult] a String containing the result-body of the REST call
- def self.delete(uri, headers=nil )
- execute( "delete", uri, nil, headers)
- end
-
- def self.head(uri)
- execute("head",uri)
- end
-
- private
- def self.execute( rest_call, uri, payload=nil, headers={}, waiting_task=nil, wait=true )
-
- raise OpenTox::BadRequestError.new "Empty URI." unless uri
- raise OpenTox::BadRequestError.new "Invalid URI: '#{uri}'" unless URI.valid? uri
- raise OpenTox::BadRequestError.new "Unreachable URI: '#{uri}'" unless URI.accessible? uri
- raise "headers are no hash: "+headers.inspect unless headers==nil or headers.is_a?(Hash)
- # TODO: loop over accept, contant_type, subjectid
- raise OpenTox::BadRequestError.new "accept should go into the headers" if payload and payload.is_a?(Hash) and payload[:accept]
- raise OpenTox::BadRequestError.new "content_type should go into the headers" if payload and payload.is_a?(Hash) and payload[:content_type]
- raise OpenTox::BadRequestError.new "subjectid should go into the headers" if payload and payload.is_a?(Hash) and payload[:subjectid]
- raise "__waiting_task__ must be 'nil' or '(sub)task', is "+waiting_task.class.to_s if
- waiting_task!=nil and !(waiting_task.is_a?(Task) || waiting_task.is_a?(SubTask))
- headers.each{ |k,v| headers.delete(k) if v==nil } if headers #remove keys with empty values, as this can cause problems
- ## PENDING partner services accept subjectid only in header
- headers = {} unless headers
- #headers[:subjectid] = payload.delete(:subjectid) if payload and payload.is_a?(Hash) and payload.has_key?(:subjectid)
-
- # PENDING needed for NUTA, until we finally agree on how to send subjectid
- #headers[:subjectid] = payload.delete(:subjectid) if uri=~/ntua/ and payload and payload.is_a?(Hash) and payload.has_key?(:subjectid)
-
- begin
- #LOGGER.debug "RestCall: "+rest_call.to_s+" "+uri.to_s+" "+headers.inspect+" "+payload.inspect
- resource = RestClient::Resource.new(uri,{:timeout => 600})
- if rest_call=="post" || rest_call=="put"
- result = resource.send(rest_call, payload, headers){|response, request, result| return response }
- elsif rest_call == "head"
- result = resource.send(rest_call){ |response, request, result| return response }
- else
- result = resource.send(rest_call, headers){|response, request, result| return response }
- end
- # ignore error codes from Task services (may contain eg 500 which causes exceptions in RestClient and RDF::Reader
- unless result.code < 400 or URI.task? @uri
- $logger.error "#{@uri} returned #{result}"
- raise OpenTox::RestCallError result
- end
- #LOGGER.debug "result body size: #{result.body.size}"
-
- # PENDING NTUA does return errors with 200
- raise RestClient::ExceptionWithResponse.new(result) if uri=~/ntua/ and result.body =~ /about.*http:\/\/anonymous.org\/error/
-
- # result is a string, with the additional fields content_type and code
- res = WrapperResult.new(result.body)
- res.content_type = result.headers[:content_type]
- raise "content-type not set" unless res.content_type
- res.code = result.code
-
- # TODO: Ambit returns task representation with 200 instead of result URI
- return res if res.code==200 || !wait
-
- while (res.code==201 || res.code==202)
- res = wait_for_task(res, uri, waiting_task)
- end
- raise "illegal status code: '"+res.code.to_s+"'" unless res.code==200
- return res
-
- rescue RestClient::RequestTimeout => ex
- received_error ex.message, 408, nil, {:rest_uri => uri, :headers => headers, :payload => payload}
- rescue Errno::ETIMEDOUT => ex
- received_error ex.message, 408, nil, {:rest_uri => uri, :headers => headers, :payload => payload}
- rescue Errno::ECONNREFUSED => ex
- received_error ex.message, 500, nil, {:rest_uri => uri, :headers => headers, :payload => payload}
- rescue RestClient::ExceptionWithResponse => ex
- # error comming from a different webservice,
- received_error ex.http_body, ex.http_code, ex.response.net_http_res.content_type, {:rest_uri => uri, :headers => headers, :payload => payload}
- rescue OpenTox::RestCallError => ex
- # already a rest-error, probably comes from wait_for_task, just pass through
- raise ex
- rescue => ex
- # some internal error occuring in rest-client-wrapper, just pass through
- raise ex
- end
- end
-=end
- def self.wait_for_task( res, base_uri, waiting_task=nil )
+ def self.wait_for_task( response, base_uri, waiting_task=nil )
#TODO remove TUM hack
- res.content_type = "text/uri-list" if base_uri =~/tu-muenchen/ and res.content_type == "application/x-www-form-urlencoded;charset=UTF-8"
+ # response.headers[:content_type] = "text/uri-list" if base_uri =~/tu-muenchen/ and response.headers[:content_type] == "application/x-www-form-urlencoded;charset=UTF-8"
+ puts "TASK"
+ puts response.inspect
task = nil
- case res.content_type
+ case response.headers[:content_type]
when /application\/rdf\+xml/
- task = OpenTox::Task.from_rdfxml(res)
- when /yaml/
- task = OpenTox::Task.from_yaml(res)
- when /text\//
- raise "uri list has more than one entry, should be a task" if res.content_type=~/text\/uri-list/ and res.split("\n").size > 1 #if uri list contains more then one uri, its not a task
- task = OpenTox::Task.find(res.to_s.chomp) if res.to_s.uri?
+ # TODO: task uri from rdf
+ #task = OpenTox::Task.from_rdfxml(response)
+ #task = OpenTox::Task.from_rdfxml(response)
+ when /text\/uri-list/
+ raise OpenTox::RestCallError nil, response, "Uri list has more than one entry, should be a single task" if response.split("\n").size > 1 #if uri list contains more then one uri, its not a task
+ task = OpenTox::Task.new(response.to_s.chomp) if URI.available? response.to_s
else
- raise "unknown content-type for task : '"+res.content_type.to_s+"'"+" base-uri: "+base_uri.to_s+" content: "+res[0..200].to_s
+ raise OpenTox::RestCallError nil, response, "Unknown content-type for task : '"+response.headers[:content_type].to_s+"'"+" base-uri: "+base_uri.to_s+" content: "+response[0..200].to_s
end
#LOGGER.debug "result is a task '"+task.uri.to_s+"', wait for completion"
@@ -235,15 +97,11 @@ module OpenTox
if task.errorReport
received_error task.errorReport, task.http_code, nil, {:rest_uri => task.uri, :rest_code => task.http_code}
else
- raise "status of task '"+task.uri.to_s+"' is no longer running (hasStatus is '"+task.status+
+ raise OpenTox::RestCallError nil, response, "Status of task '"+task.uri.to_s+"' is no longer running (hasStatus is '"+task.status+
"'), but it is neither completed nor has an errorReport"
end
end
-
- res = WrapperResult.new task.result_uri
- res.code = task.http_code
- res.content_type ="text/uri-list"
- return res
+ response
end
def self.received_error( body, code, content_type=nil, params=nil )
--
cgit v1.2.3
From 77a5576782b85f2e3fdaf1b65eda2543eedb6b12 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Wed, 29 Feb 2012 15:17:27 +0000
Subject: request and response as RestClientWrapper instance variables
---
lib/rest-client-wrapper.rb | 42 +++++++++++++++++++++++-------------------
1 file changed, 23 insertions(+), 19 deletions(-)
(limited to 'lib')
diff --git a/lib/rest-client-wrapper.rb b/lib/rest-client-wrapper.rb
index 27538e4..67114fb 100644
--- a/lib/rest-client-wrapper.rb
+++ b/lib/rest-client-wrapper.rb
@@ -2,6 +2,8 @@ module OpenTox
class RestClientWrapper
+ attr_accessor :request, :response
+
# REST methods
# Raises OpenTox::Error if call fails (rescued in overwrite.rb -> halt 502)
# Waits for Task to finish and returns result URI of Task per default
@@ -34,24 +36,24 @@ module OpenTox
begin
- request = RestClient::Request.new(args)
- response = request.execute do |response, request, result|
+ @request = RestClient::Request.new(args)
+ @response = @request.execute do |response, request, result|
# ignore error codes from Task services (may contain eg 500 which causes exceptions in RestClient and RDF::Reader
- raise OpenTox::RestCallError request, response unless response.code < 400 or URI.task? uri
+ rest_call_error unless response.code < 400 or URI.task? uri
return response
end
# TODO: tests for workarounds
# PENDING NTUA does return errors with 200
- #raise RestClient::ExceptionWithResponse.new(response) if uri=~/ntua/ and response.body =~ /about.*http:\/\/anonymous.org\/error/
+ #raise RestClient::ExceptionWithResponse.new(@response) if uri=~/ntua/ and @response.body =~ /about.*http:\/\/anonymous.org\/error/
- return response if response.code==200 or wait.false?
+ return @response if @response.code==200 or wait.false?
# wait for task
- while response.code==201 or response.code==202
- response = wait_for_task(response, uri, waiting_task)
+ while @response.code==201 or @response.code==202
+ @response = wait_for_task(@response, uri, waiting_task)
end
- return response
+ return @response
rescue RestClient::RequestTimeout => ex
received_error ex.message, 408, nil, {:rest_uri => uri, :headers => headers, :payload => payload}
@@ -74,21 +76,19 @@ module OpenTox
def self.wait_for_task( response, base_uri, waiting_task=nil )
#TODO remove TUM hack
- # response.headers[:content_type] = "text/uri-list" if base_uri =~/tu-muenchen/ and response.headers[:content_type] == "application/x-www-form-urlencoded;charset=UTF-8"
+ # @response.headers[:content_type] = "text/uri-list" if base_uri =~/tu-muenchen/ and @response.headers[:content_type] == "application/x-www-form-urlencoded;charset=UTF-8"
- puts "TASK"
- puts response.inspect
task = nil
- case response.headers[:content_type]
+ case @response.headers[:content_type]
when /application\/rdf\+xml/
# TODO: task uri from rdf
- #task = OpenTox::Task.from_rdfxml(response)
- #task = OpenTox::Task.from_rdfxml(response)
+ #task = OpenTox::Task.from_rdfxml(@response)
+ #task = OpenTox::Task.from_rdfxml(@response)
when /text\/uri-list/
- raise OpenTox::RestCallError nil, response, "Uri list has more than one entry, should be a single task" if response.split("\n").size > 1 #if uri list contains more then one uri, its not a task
- task = OpenTox::Task.new(response.to_s.chomp) if URI.available? response.to_s
+ rest_call_error "Uri list has more than one entry, should be a single task" if @response.split("\n").size > 1 #if uri list contains more then one uri, its not a task
+ task = OpenTox::Task.new(@response.to_s.chomp) if URI.available? @response.to_s
else
- raise OpenTox::RestCallError nil, response, "Unknown content-type for task : '"+response.headers[:content_type].to_s+"'"+" base-uri: "+base_uri.to_s+" content: "+response[0..200].to_s
+ rest_call_error @response, "Unknown content-type for task : '"+@response.headers[:content_type].to_s+"'"+" base-uri: "+base_uri.to_s+" content: "+@response[0..200].to_s
end
#LOGGER.debug "result is a task '"+task.uri.to_s+"', wait for completion"
@@ -97,11 +97,15 @@ module OpenTox
if task.errorReport
received_error task.errorReport, task.http_code, nil, {:rest_uri => task.uri, :rest_code => task.http_code}
else
- raise OpenTox::RestCallError nil, response, "Status of task '"+task.uri.to_s+"' is no longer running (hasStatus is '"+task.status+
+ rest_call_error "Status of task '"+task.uri.to_s+"' is no longer running (hasStatus is '"+task.status+
"'), but it is neither completed nor has an errorReport"
end
end
- response
+ @response
+ end
+
+ def rest_call_error message
+ raise OpenTox::RestCallError @request, @response, message
end
def self.received_error( body, code, content_type=nil, params=nil )
--
cgit v1.2.3
From c2986f418ede0ea443df0a1f7690c433b637dc57 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Wed, 29 Feb 2012 18:50:41 +0000
Subject: TaskError implemented, logging still partially redundant
---
lib/error.rb | 72 +++++++++++++++++--------------------
lib/otlogger.rb | 2 +-
lib/rest-client-wrapper.rb | 88 ++++++++++++++++++++++++++++++++--------------
lib/task.rb | 10 +++---
4 files changed, 99 insertions(+), 73 deletions(-)
(limited to 'lib')
diff --git a/lib/error.rb b/lib/error.rb
index b832ef4..0e467d9 100644
--- a/lib/error.rb
+++ b/lib/error.rb
@@ -1,47 +1,38 @@
# adding additional fields to Exception class to format errors according to OT-API
-=begin
-class Exception
-end
-=end
class RuntimeError
- attr_accessor :errorCause # is errorReport
- def initialize msg=nil
- $logger.error msg
- super msg
- end
- def http_code; 500; end
+ attr_accessor :http_code
+ @http_code = 500
end
module OpenTox
-
- class BadRequestError < RuntimeError
- def http_code; 400; end
- end
-
- class NotAuthorizedError < RuntimeError
- def http_code; 401; end
- end
-
- class NotFoundError < RuntimeError
- def http_code; 404; end
- end
-
- class LockedError < RuntimeError
- def http_code; 423; end
- end
- class ServiceUnavailableError < RuntimeError
- def http_code; 503; end
+ # Errors received from RestClientWrapper calls
+ class RestError < RuntimeError
+ attr_accessor :request, :response, :cause
+ def initialize args
+ @request = args[:request]
+ @response = args[:response]
+ args[:http_code] ? @http_code = args[:http_code] : @http_code = @response.code if @response
+ @cause = args[:cause]
+ msg = args.to_yaml
+ $logger.error msg
+ super msg
+ end
end
-
- class RestCallError < RuntimeError
- def initialize request, response, expectation=nil
- msg = "REST request: #{request.inspect}\nREST response: #{response.inspect}"
- msg += "\n"+expectation if expectation
+
+ # Errors rescued from task blocks
+ class TaskError < RuntimeError
+ attr_reader :error, :actor, :report
+ def initialize error, actor=nil
+ @error = error
+ @actor = actor
+ @report = ErrorReport.create error, actor
+ msg = "\nActor: \"#{actor}\"\n"
+ msg += @error.to_yaml
+ #$logger.error msg
super msg
end
- def http_code; 502; end
end
class ErrorReport
@@ -52,7 +43,7 @@ module OpenTox
private
def initialize( http_code, erroType, message, actor, errorCause, rest_params=nil, backtrace=nil )
@http_code = http_code
- @errorType = erroType
+ #@errorType = erroType
@message = message
@actor = actor
@errorCause = errorCause
@@ -65,9 +56,11 @@ module OpenTox
# @param [Exception] error
# @param [String] actor, URI of the call that cause the error
def self.create( error, actor )
- rest_params = error.rest_params if error.is_a?(OpenTox::RestCallError) and error.rest_params
- backtrace = error.backtrace.short_backtrace #if CONFIG[:backtrace]
- ErrorReport.new( error.http_code, error.class.to_s, error.message, actor, error.errorCause, rest_params, backtrace )
+ rest_params = error.request if error.respond_to? :request
+ backtrace = error.backtrace.short_backtrace if error.respond_to? :backtrace and error.backtrace #if CONFIG[:backtrace]
+ error.respond_to?(:http_code) ? http_code = error.http_code : http_code = 500
+ error.respond_to?(:cause) ? cause = error.cause : cause = 'Unknown'
+ ErrorReport.new( http_code, error.class.to_s, error.message, actor, cause, rest_params, backtrace )
end
def self.from_rdf(rdf)
@@ -101,8 +94,7 @@ module OpenTox
s.add_resource(CONFIG[:services]["opentox-task"]+"/tmpId/ErrorReport/tmpId", OT.errorReport, rdf_content)
s.to_rdfxml
end
-=begin
-=end
+
end
end
diff --git a/lib/otlogger.rb b/lib/otlogger.rb
index e9fbc4d..57b8170 100644
--- a/lib/otlogger.rb
+++ b/lib/otlogger.rb
@@ -12,7 +12,7 @@ class OTLogger < Logger
n = 2
line = lines[n]
- while (line =~ /spork.rb/ or line =~ /create/ or line =~ /#{File.basename(__FILE__)}/)
+ while (line =~ /error.rb/ or line =~ /create/ or line =~ /#{File.basename(__FILE__)}/)
n += 1
line = lines[n]
end
diff --git a/lib/rest-client-wrapper.rb b/lib/rest-client-wrapper.rb
index 67114fb..1e871b0 100644
--- a/lib/rest-client-wrapper.rb
+++ b/lib/rest-client-wrapper.rb
@@ -17,15 +17,7 @@ module OpenTox
define_singleton_method method do |uri,payload={},headers={},waiting_task=nil, wait=true|
- # catch input errors
- raise OpenTox::BadRequestError.new "Invalid URI: '#{uri}'" unless URI.valid? uri
- raise OpenTox::BadRequestError.new "Unreachable URI: '#{uri}'" unless URI.accessible? uri
- raise OpenTox::BadRequestError.new "Headers are not a hash: #{headers.inspect}" unless headers==nil or headers.is_a?(Hash)
- [:accept,:content_type,:subjectid].each do |header|
- raise OpenTox::BadRequestError.new "#{header} should be submitted in the headers" if payload and payload.is_a?(Hash) and payload[header]
- end
- raise OpenTox::BadRequestError "waiting_task is not 'nil', OpenTox::SubTask or OpenTox::Task: #{waiting_task.class}" unless waiting_task.nil? or waiting_task.is_a?(OpenTox::Task) or waiting_task.is_a?(OpenTox::SubTask)
-
+ # create request
args={}
args[:method] = method
args[:url] = uri
@@ -33,13 +25,23 @@ module OpenTox
args[:payload] = payload
headers.each{ |k,v| headers.delete(k) if v==nil } if headers #remove keys with empty values, as this can cause problems
args[:headers] = headers
+ @request = RestClient::Request.new(args)
+
+ # catch input errors
+ rest_error "Invalid URI: '#{uri}'" unless URI.valid? uri
+ rest_error "Unreachable URI: '#{uri}'" unless URI.accessible? uri
+ rest_error "Headers are not a hash: #{headers.inspect}" unless headers==nil or headers.is_a?(Hash)
+ # make sure that no header parameters are set in payload
+ [:accept,:content_type,:subjectid].each do |header|
+ rest_error "#{header} should be submitted in the headers" if payload and payload.is_a?(Hash) and payload[header]
+ end
+ rest_error "waiting_task is not 'nil', OpenTox::SubTask or OpenTox::Task: #{waiting_task.class}" unless waiting_task.nil? or waiting_task.is_a?(OpenTox::Task) or waiting_task.is_a?(OpenTox::SubTask)
begin
- @request = RestClient::Request.new(args)
@response = @request.execute do |response, request, result|
# ignore error codes from Task services (may contain eg 500 which causes exceptions in RestClient and RDF::Reader
- rest_call_error unless response.code < 400 or URI.task? uri
+ rest_error unless response.code < 400 or URI.task? uri
return response
end
@@ -55,26 +57,34 @@ module OpenTox
end
return @response
- rescue RestClient::RequestTimeout => ex
- received_error ex.message, 408, nil, {:rest_uri => uri, :headers => headers, :payload => payload}
- rescue Errno::ETIMEDOUT => ex
- received_error ex.message, 408, nil, {:rest_uri => uri, :headers => headers, :payload => payload}
- rescue Errno::ECONNREFUSED => ex
- received_error ex.message, 500, nil, {:rest_uri => uri, :headers => headers, :payload => payload}
- rescue RestClient::ExceptionWithResponse => ex
+ rescue
+ rest_error $!.message
+ end
+=begin
+ rescue RestClient::RequestTimeout
+ raise OpenTox::Error @request, @response, $!.message
+ #received_error ex.message, 408, nil, {:rest_uri => uri, :headers => headers, :payload => payload}
+ rescue Errno::ETIMEDOUT
+ raise OpenTox::Error @request, @response, $!.message
+ #received_error ex.message, 408, nil, {:rest_uri => uri, :headers => headers, :payload => payload}
+ rescue Errno::ECONNREFUSED
+ raise OpenTox::Error $!.message
+ #received_error ex.message, 500, nil, {:rest_uri => uri, :headers => headers, :payload => payload}
+ rescue RestClient::ExceptionWithResponse
# error comming from a different webservice,
received_error ex.http_body, ex.http_code, ex.response.net_http_res.content_type, {:rest_uri => uri, :headers => headers, :payload => payload}
- rescue OpenTox::RestCallError => ex
+ #rescue OpenTox::RestCallError => ex
# already a rest-error, probably comes from wait_for_task, just pass through
- raise ex
- rescue => ex
+ #raise ex
+ #rescue => ex
# some internal error occuring in rest-client-wrapper, just pass through
- raise ex
+ #raise ex
end
+=end
end
end
- def self.wait_for_task( response, base_uri, waiting_task=nil )
+ def wait_for_task( response, base_uri, waiting_task=nil )
#TODO remove TUM hack
# @response.headers[:content_type] = "text/uri-list" if base_uri =~/tu-muenchen/ and @response.headers[:content_type] == "application/x-www-form-urlencoded;charset=UTF-8"
@@ -85,10 +95,10 @@ module OpenTox
#task = OpenTox::Task.from_rdfxml(@response)
#task = OpenTox::Task.from_rdfxml(@response)
when /text\/uri-list/
- rest_call_error "Uri list has more than one entry, should be a single task" if @response.split("\n").size > 1 #if uri list contains more then one uri, its not a task
+ rest_error "Uri list has more than one entry, should be a single task" if @response.split("\n").size > 1 #if uri list contains more then one uri, its not a task
task = OpenTox::Task.new(@response.to_s.chomp) if URI.available? @response.to_s
else
- rest_call_error @response, "Unknown content-type for task : '"+@response.headers[:content_type].to_s+"'"+" base-uri: "+base_uri.to_s+" content: "+@response[0..200].to_s
+ rest_error @response, "Unknown content-type for task : '"+@response.headers[:content_type].to_s+"'"+" base-uri: "+base_uri.to_s+" content: "+@response[0..200].to_s
end
#LOGGER.debug "result is a task '"+task.uri.to_s+"', wait for completion"
@@ -104,14 +114,37 @@ module OpenTox
@response
end
- def rest_call_error message
- raise OpenTox::RestCallError @request, @response, message
+ def self.rest_error message
+ raise OpenTox::RestError.new :request => @request, :response => @response, :cause => message
+ end
+
+=begin
+ def self.bad_request_error message
+ raise OpenTox::Error.new message
+ end
+
+ def self.not_found_error message
+ raise OpenTox::NotFoundError.new message
end
+ def self.received_error( body, code, content_type=nil, params=nil )
+
+ # try to parse body TODO
+ body.is_a?(OpenTox::ErrorReport) ? report = body : report = OpenTox::ErrorReport.from_rdf(body)
+ rest_call_error "REST call returned error: '"+body.to_s+"'" unless report
+ # parsing sucessfull
+ # raise RestCallError with parsed report as error cause
+ err = OpenTox::RestCallError.new(@request, @response, "REST call subsequent error")
+ err.errorCause = report
+ raise err
+ end
+=end
+=begin
def self.received_error( body, code, content_type=nil, params=nil )
# try to parse body
report = nil
+ #report = OpenTox::ErrorReport.from_rdf(body)
if body.is_a?(OpenTox::ErrorReport)
report = body
else
@@ -138,5 +171,6 @@ module OpenTox
raise err
end
end
+=end
end
end
diff --git a/lib/task.rb b/lib/task.rb
index 635584f..a28a0aa 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -9,6 +9,7 @@ module OpenTox
def self.create service_uri, params={}
+ # TODO set request uri
task = Task.new RestClientWrapper.post(service_uri,params).chomp
pid = fork do
begin
@@ -16,7 +17,7 @@ module OpenTox
if URI.accessible?(result_uri)
task.completed result_uri
else
- raise "#{result_uri} is not a valid URI"
+ task.error OpenTox::RestError.new :http_code => 404, :cause => "#{result_uri} is not a valid URI", :actor => params[:creator]
end
rescue
task.error $!
@@ -62,14 +63,13 @@ module OpenTox
def completed(uri)
#TODO: subjectid?
#TODO: error code
- raise "\"#{uri}\" does not exist." unless URI.accessible? uri
+ error OpenTox::RestError.new :http_code => 404, :cause => "\"#{uri}\" does not exist.", :actor => creator unless URI.accessible? uri
RestClientWrapper.put(File.join(@uri,'Completed'),{:resultURI => uri})
end
def error error
- $logger.error self
- report = ErrorReport.create(error,self.creator)
- RestClientWrapper.put(File.join(@uri,'Error'),{:errorReport => report})
+ error = OpenTox::TaskError.new error, self.creator
+ RestClientWrapper.put(File.join(@uri,'Error'),{:errorReport => error.report})
kill
raise error
end
--
cgit v1.2.3
From dd39ae3a5479eed32d57d1d3934d907a82048486 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Wed, 29 Feb 2012 19:45:15 +0000
Subject: duplicated error logs not yet solved
---
lib/error.rb | 9 ++++++---
lib/task.rb | 14 +++++++-------
2 files changed, 13 insertions(+), 10 deletions(-)
(limited to 'lib')
diff --git a/lib/error.rb b/lib/error.rb
index 0e467d9..88c8be8 100644
--- a/lib/error.rb
+++ b/lib/error.rb
@@ -28,9 +28,12 @@ module OpenTox
@error = error
@actor = actor
@report = ErrorReport.create error, actor
+ # TODO avoid error log duplication, improve output
msg = "\nActor: \"#{actor}\"\n"
- msg += @error.to_yaml
- #$logger.error msg
+ msg += "\nCode: #{@report.http_code}"
+ msg += "\nerrorCause: #{@report.errorCause}\n"
+ msg += @report.message
+ $logger.error msg
super msg
end
end
@@ -43,7 +46,7 @@ module OpenTox
private
def initialize( http_code, erroType, message, actor, errorCause, rest_params=nil, backtrace=nil )
@http_code = http_code
- #@errorType = erroType
+ @errorType = erroType
@message = message
@actor = actor
@errorCause = errorCause
diff --git a/lib/task.rb b/lib/task.rb
index a28a0aa..d3b6312 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -9,7 +9,7 @@ module OpenTox
def self.create service_uri, params={}
- # TODO set request uri
+ # TODO set/enforce request uri
task = Task.new RestClientWrapper.post(service_uri,params).chomp
pid = fork do
begin
@@ -17,7 +17,8 @@ module OpenTox
if URI.accessible?(result_uri)
task.completed result_uri
else
- task.error OpenTox::RestError.new :http_code => 404, :cause => "#{result_uri} is not a valid URI", :actor => params[:creator]
+ raise "\"#{result_uri}\" is not a valid result URI"
+ #task.error OpenTox::RestError.new :http_code => 404, :cause => "#{result_uri} is not a valid URI", :actor => params[:creator]
end
rescue
task.error $!
@@ -44,7 +45,7 @@ module OpenTox
def kill
Process.kill(9,@pid)
Process.kill(9,@observer_pid)
- rescue # no need to raise an aexeption if processes are not running
+ rescue # no need to raise an exeption if processes are not running
end
def description
@@ -61,14 +62,13 @@ module OpenTox
end
def completed(uri)
- #TODO: subjectid?
- #TODO: error code
- error OpenTox::RestError.new :http_code => 404, :cause => "\"#{uri}\" does not exist.", :actor => creator unless URI.accessible? uri
+ #error OpenTox::RestError.new :http_code => 404, :cause => "\"#{uri}\" does not exist.", :actor => creator unless URI.accessible? uri
+ raise "Result URI \"#{uri}\" does not exist." unless URI.accessible? uri
RestClientWrapper.put(File.join(@uri,'Completed'),{:resultURI => uri})
end
def error error
- error = OpenTox::TaskError.new error, self.creator
+ error = OpenTox::TaskError.new error, creator
RestClientWrapper.put(File.join(@uri,'Error'),{:errorReport => error.report})
kill
raise error
--
cgit v1.2.3
From cbc5f08e92c92601009f0c11c8ec67ede2894858 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Fri, 2 Mar 2012 09:33:44 +0000
Subject: error report fixed for old task services
---
lib/error.rb | 160 +++++++++++++++++++++++----------------------
lib/opentox.rb | 8 ++-
lib/rest-client-wrapper.rb | 28 ++++----
lib/task.rb | 25 ++++---
4 files changed, 116 insertions(+), 105 deletions(-)
(limited to 'lib')
diff --git a/lib/error.rb b/lib/error.rb
index 88c8be8..8368404 100644
--- a/lib/error.rb
+++ b/lib/error.rb
@@ -1,101 +1,107 @@
# adding additional fields to Exception class to format errors according to OT-API
class RuntimeError
- attr_accessor :http_code
- @http_code = 500
+ attr_accessor :report, :http_code
+ def initialize message
+ super message
+ @http_code ||= 500
+ @report = OpenTox::ErrorReport.create self
+ $logger.error "\n"+@report.to_ntriples
+ end
end
module OpenTox
- # Errors received from RestClientWrapper calls
- class RestError < RuntimeError
- attr_accessor :request, :response, :cause
- def initialize args
- @request = args[:request]
- @response = args[:response]
- args[:http_code] ? @http_code = args[:http_code] : @http_code = @response.code if @response
- @cause = args[:cause]
- msg = args.to_yaml
- $logger.error msg
- super msg
+ class Error < RuntimeError
+ def initialize code, message
+ @http_code = code
+ super message
end
end
- # Errors rescued from task blocks
- class TaskError < RuntimeError
- attr_reader :error, :actor, :report
- def initialize error, actor=nil
- @error = error
- @actor = actor
- @report = ErrorReport.create error, actor
- # TODO avoid error log duplication, improve output
- msg = "\nActor: \"#{actor}\"\n"
- msg += "\nCode: #{@report.http_code}"
- msg += "\nerrorCause: #{@report.errorCause}\n"
- msg += @report.message
- $logger.error msg
- super msg
+ # create error classes dynamically
+ {
+ "BadRequestError" => 400,
+ "NotAuthorizedError" => 401,
+ "NotFoundError" => 404,
+ "ServiceUnavailableError" => 503,
+ "TimeOutError" => 504,
+ }.each do |klass,code|
+ c = Class.new Error do
+ define_method :initialize do |message|
+ super code, message
+ end
+ end
+ OpenTox.const_set klass,c
+ end
+
+ # Errors received from RestClientWrapper calls
+ class RestCallError < Error
+ attr_accessor :request, :response
+ def initialize request, response, message
+ @request = request
+ @response = response
+ super 502, message
end
end
class ErrorReport
- # TODO replace params with URIs (errorCause -> OT.errorCause)
- attr_reader :message, :actor, :errorCause, :http_code, :errorDetails, :errorType
+ attr_accessor :rdf # RDF Graph
+ attr_accessor :http_code # TODO: remove when task service is fixed
- private
- def initialize( http_code, erroType, message, actor, errorCause, rest_params=nil, backtrace=nil )
- @http_code = http_code
- @errorType = erroType
- @message = message
- @actor = actor
- @errorCause = errorCause
- @rest_params = rest_params
- @backtrace = backtrace
+ def initialize
+ @rdf = RDF::Graph.new
end
-
- public
+
# creates a error report object, from an ruby-exception object
# @param [Exception] error
- # @param [String] actor, URI of the call that cause the error
- def self.create( error, actor )
- rest_params = error.request if error.respond_to? :request
- backtrace = error.backtrace.short_backtrace if error.respond_to? :backtrace and error.backtrace #if CONFIG[:backtrace]
- error.respond_to?(:http_code) ? http_code = error.http_code : http_code = 500
- error.respond_to?(:cause) ? cause = error.cause : cause = 'Unknown'
- ErrorReport.new( http_code, error.class.to_s, error.message, actor, cause, rest_params, backtrace )
- end
-
- def self.from_rdf(rdf)
- metadata = OpenTox::Parser::Owl.from_rdf( rdf, OT.ErrorReport ).metadata
- ErrorReport.new(metadata[OT.statusCode], metadata[OT.errorCode], metadata[OT.message], metadata[OT.actor], metadata[OT.errorCause])
- end
-
- # overwrite sorting to make easier readable
- def to_yaml_properties
- p = super
- p = ( p - ["@backtrace"]) + ["@backtrace"] if @backtrace
- p = ( p - ["@errorCause"]) + ["@errorCause"] if @errorCause
- p
- end
-
- def rdf_content()
- c = {
- RDF.type => [OT.ErrorReport],
- OT.statusCode => @http_code,
- OT.message => @message,
- OT.actor => @actor,
- OT.errorCode => @errorType,
- }
- c[OT.errorCause] = @errorCause.rdf_content if @errorCause
- c
+ def self.create error
+ report = ErrorReport.new
+ subject = RDF::Node.new
+ report.rdf << [subject, RDF.type, RDF::OT.ErrorReport]
+ message = error.message
+ errorDetails = ""
+ if error.respond_to? :request
+ report.rdf << [subject, RDF::OT.actor, error.request.url ]
+ errorDetails += "REST paramenters:\n#{error.request.args.inspect}"
+ end
+ error.respond_to?(:http_code) ? statusCode = error.http_code : statusCode = 500
+ if error.respond_to? :response
+ statusCode = error.response.code
+ message = error.body
+ end
+ statusCode = error.http_code if error.respond_to? :http_code
+ report.rdf << [subject, RDF::OT.statusCode, statusCode ]
+ report.rdf << [subject, RDF::OT.errorCode, error.class.to_s ]
+ # TODO: remove kludge for old task services
+ report.http_code = statusCode
+ report.rdf << [subject, RDF::OT.message , message ]
+
+ errorDetails += "\nBacktrace:\n" + error.backtrace.short_backtrace if error.respond_to?(:backtrace) and error.backtrace
+ report.rdf << [subject, RDF::OT.errorDetails, errorDetails ]
+ # TODO Error cause
+ #report.rdf << [subject, OT.errorCause, error.report] if error.respond_to?(:report) and !error.report.empty?
+ report
end
- # TODO: use rdf.rb
- def to_rdfxml
- s = Serializer::Owl.new
- s.add_resource(CONFIG[:services]["opentox-task"]+"/tmpId/ErrorReport/tmpId", OT.errorReport, rdf_content)
- s.to_rdfxml
+ # define to_ and self.from_ methods for various rdf formats
+ [:rdfxml,:ntriples].each do |format|
+
+ define_singleton_method ("from_#{format}").to_sym do |rdf|
+ report = ErrorReport.new
+ RDF::Reader.for(format).new(rdf) do |reader|
+ reader.each_statement{ |statement| report.rdf << statement }
+ end
+ report
+ end
+
+ send :define_method, ("to_#{format}").to_sym do
+ rdfxml = RDF::Writer.for(format).buffer do |writer|
+ @rdf.each{|statement| writer << statement}
+ end
+ rdfxml
+ end
end
end
diff --git a/lib/opentox.rb b/lib/opentox.rb
index 4c2a668..10c7895 100644
--- a/lib/opentox.rb
+++ b/lib/opentox.rb
@@ -24,7 +24,7 @@ module OpenTox
if reload or @metadata.empty?
@metadata = {}
kind_of?(OpenTox::Dataset) ? uri = File.join(@uri,"metadata") : uri = @uri
- RDF::Reader.for(:rdfxml).new( RestClientWrapper.get(@uri) ) do |reader|
+ RDF::Reader.for(:rdfxml).new( RestClientWrapper.get(uri) ) do |reader|
reader.each_statement do |statement|
@metadata[statement.predicate] = statement.object if statement.subject == @uri
end
@@ -34,10 +34,14 @@ module OpenTox
end
def save
+ post self.to_rdfxml, { :content_type => 'application/rdf+xml'}
+ end
+
+ def to_rdfxml
rdf = RDF::Writer.for(:rdfxml).buffer do |writer|
@metadata.each { |p,o| writer << RDF::Statement.new(RDF::URI.new(@uri), p, o) }
end
- post rdf, { :content_type => 'application/rdf+xml'}
+ rdf
end
# REST API
diff --git a/lib/rest-client-wrapper.rb b/lib/rest-client-wrapper.rb
index 1e871b0..0780dd5 100644
--- a/lib/rest-client-wrapper.rb
+++ b/lib/rest-client-wrapper.rb
@@ -27,29 +27,25 @@ module OpenTox
args[:headers] = headers
@request = RestClient::Request.new(args)
- # catch input errors
- rest_error "Invalid URI: '#{uri}'" unless URI.valid? uri
- rest_error "Unreachable URI: '#{uri}'" unless URI.accessible? uri
- rest_error "Headers are not a hash: #{headers.inspect}" unless headers==nil or headers.is_a?(Hash)
- # make sure that no header parameters are set in payload
+ # check input
+ raise OpenTox::Error.new 400, "Invalid URI: '#{uri}'" unless URI.valid? uri
+ raise OpenTox::Error.new 400, "Unreachable URI: '#{uri}'" unless URI.accessible? uri
+ raise OpenTox::Error.new 400, "Headers are not a hash: #{headers.inspect}" unless headers==nil or headers.is_a?(Hash)
+ # make sure that no header parameters are set in the payload
[:accept,:content_type,:subjectid].each do |header|
- rest_error "#{header} should be submitted in the headers" if payload and payload.is_a?(Hash) and payload[header]
+ raise OpenTox::Error.new 400, "#{header} should be submitted in the headers" if payload and payload.is_a?(Hash) and payload[header]
end
- rest_error "waiting_task is not 'nil', OpenTox::SubTask or OpenTox::Task: #{waiting_task.class}" unless waiting_task.nil? or waiting_task.is_a?(OpenTox::Task) or waiting_task.is_a?(OpenTox::SubTask)
+ raise OpenTox::Error.new 400, "waiting_task is not 'nil', OpenTox::SubTask or OpenTox::Task: #{waiting_task.class}" unless waiting_task.nil? or waiting_task.is_a?(OpenTox::Task) or waiting_task.is_a?(OpenTox::SubTask)
begin
@response = @request.execute do |response, request, result|
# ignore error codes from Task services (may contain eg 500 which causes exceptions in RestClient and RDF::Reader
- rest_error unless response.code < 400 or URI.task? uri
+ rest_error "Response code is #{response.code}" unless response.code < 400 or URI.task? uri
return response
end
-
- # TODO: tests for workarounds
- # PENDING NTUA does return errors with 200
- #raise RestClient::ExceptionWithResponse.new(@response) if uri=~/ntua/ and @response.body =~ /about.*http:\/\/anonymous.org\/error/
- return @response if @response.code==200 or wait.false?
+ return @response if @response.code==200 or !wait
# wait for task
while @response.code==201 or @response.code==202
@@ -98,7 +94,7 @@ module OpenTox
rest_error "Uri list has more than one entry, should be a single task" if @response.split("\n").size > 1 #if uri list contains more then one uri, its not a task
task = OpenTox::Task.new(@response.to_s.chomp) if URI.available? @response.to_s
else
- rest_error @response, "Unknown content-type for task : '"+@response.headers[:content_type].to_s+"'"+" base-uri: "+base_uri.to_s+" content: "+@response[0..200].to_s
+ rest_error "Unknown content-type for task : '"+@response.headers[:content_type].to_s+"'"+" base-uri: "+base_uri.to_s+" content: "+@response[0..200].to_s
end
#LOGGER.debug "result is a task '"+task.uri.to_s+"', wait for completion"
@@ -107,7 +103,7 @@ module OpenTox
if task.errorReport
received_error task.errorReport, task.http_code, nil, {:rest_uri => task.uri, :rest_code => task.http_code}
else
- rest_call_error "Status of task '"+task.uri.to_s+"' is no longer running (hasStatus is '"+task.status+
+ rest_error "Status of task '"+task.uri.to_s+"' is no longer running (hasStatus is '"+task.status+
"'), but it is neither completed nor has an errorReport"
end
end
@@ -115,7 +111,7 @@ module OpenTox
end
def self.rest_error message
- raise OpenTox::RestError.new :request => @request, :response => @response, :cause => message
+ raise OpenTox::RestCallError.new @request, @response, message
end
=begin
diff --git a/lib/task.rb b/lib/task.rb
index d3b6312..f75f87d 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -17,7 +17,7 @@ module OpenTox
if URI.accessible?(result_uri)
task.completed result_uri
else
- raise "\"#{result_uri}\" is not a valid result URI"
+ raise NotFoundError.new "\"#{result_uri}\" is not a valid result URI"
#task.error OpenTox::RestError.new :http_code => 404, :cause => "#{result_uri} is not a valid URI", :actor => params[:creator]
end
rescue
@@ -53,7 +53,7 @@ module OpenTox
end
def creator
- metadata[RDF::DC.creator]
+ metadata[RDF::DC.creator]
end
def cancel
@@ -63,13 +63,16 @@ module OpenTox
def completed(uri)
#error OpenTox::RestError.new :http_code => 404, :cause => "\"#{uri}\" does not exist.", :actor => creator unless URI.accessible? uri
- raise "Result URI \"#{uri}\" does not exist." unless URI.accessible? uri
+ raise NotFoundError.new "Result URI \"#{uri}\" does not exist." unless URI.accessible? uri
RestClientWrapper.put(File.join(@uri,'Completed'),{:resultURI => uri})
end
def error error
- error = OpenTox::TaskError.new error, creator
- RestClientWrapper.put(File.join(@uri,'Error'),{:errorReport => error.report})
+ # TODO: switch task service to rdf
+ #RestClientWrapper.put(File.join(@uri,'Error'),{:errorReport => error.report.to_rdfxml})
+ # create report for non-runtime errors
+ error.respond_to?(:reporti) ? report = error.report : report = OpenTox::ErrorReport.create(error)
+ RestClientWrapper.put(File.join(@uri,'Error'),{:errorReport => report.to_yaml})
kill
raise error
end
@@ -80,7 +83,7 @@ module OpenTox
due_to_time = Time.new + DEFAULT_TASK_MAX_DURATION
while running?
sleep dur
- raise "max wait time exceeded ("+DEFAULT_TASK_MAX_DURATION.to_s+"sec), task: '"+@uri.to_s+"'" if (Time.new > due_to_time)
+ raise TimeOutError.new "max wait time exceeded ("+DEFAULT_TASK_MAX_DURATION.to_s+"sec), task: '"+@uri.to_s+"'" if (Time.new > due_to_time)
end
end
@@ -100,7 +103,8 @@ module OpenTox
end
def error?
- RestClientWrapper.head(@uri).code == 500
+ code = RestClientWrapper.head(@uri).code
+ code >= 400 and code != 503
end
def method_missing(method,*args)
@@ -114,14 +118,15 @@ module OpenTox
response = metadata[RDF::OT[method]].to_s
response = metadata[RDF::OT1[method]].to_s #if response.empty? # API 1.1 compatibility
if response.empty?
- $logger.error "No #{method} metadata for #{@uri} "
- raise "No #{method} metadata for #{@uri} "
+ raise NotFoundError.new "No #{method} metadata for #{@uri} "
end
return response
end
+ rescue OpenTox::Error
+ raise $!
rescue
$logger.error "Unknown #{self.class} method #{method}"
- #super
+ super
end
end
--
cgit v1.2.3
From 53fe462b9c310bc84df50d058500772b7f3cbc3c Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Fri, 2 Mar 2012 09:40:08 +0000
Subject: error test fixed
---
lib/rest-client-wrapper.rb | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
(limited to 'lib')
diff --git a/lib/rest-client-wrapper.rb b/lib/rest-client-wrapper.rb
index 0780dd5..17e1cd0 100644
--- a/lib/rest-client-wrapper.rb
+++ b/lib/rest-client-wrapper.rb
@@ -28,14 +28,14 @@ module OpenTox
@request = RestClient::Request.new(args)
# check input
- raise OpenTox::Error.new 400, "Invalid URI: '#{uri}'" unless URI.valid? uri
- raise OpenTox::Error.new 400, "Unreachable URI: '#{uri}'" unless URI.accessible? uri
- raise OpenTox::Error.new 400, "Headers are not a hash: #{headers.inspect}" unless headers==nil or headers.is_a?(Hash)
+ raise OpenTox::BadRequestError.new "Invalid URI: '#{uri}'" unless URI.valid? uri
+ raise OpenTox::BadRequestError.new "Unreachable URI: '#{uri}'" unless URI.accessible? uri
+ raise OpenTox::BadRequestError.new "Headers are not a hash: #{headers.inspect}" unless headers==nil or headers.is_a?(Hash)
# make sure that no header parameters are set in the payload
[:accept,:content_type,:subjectid].each do |header|
- raise OpenTox::Error.new 400, "#{header} should be submitted in the headers" if payload and payload.is_a?(Hash) and payload[header]
+ raise OpenTox::BadRequestError.new "#{header} should be submitted in the headers" if payload and payload.is_a?(Hash) and payload[header]
end
- raise OpenTox::Error.new 400, "waiting_task is not 'nil', OpenTox::SubTask or OpenTox::Task: #{waiting_task.class}" unless waiting_task.nil? or waiting_task.is_a?(OpenTox::Task) or waiting_task.is_a?(OpenTox::SubTask)
+ raise OpenTox::BadRequestError.new "waiting_task is not 'nil', OpenTox::SubTask or OpenTox::Task: #{waiting_task.class}" unless waiting_task.nil? or waiting_task.is_a?(OpenTox::Task) or waiting_task.is_a?(OpenTox::SubTask)
begin
--
cgit v1.2.3
From a5f8c658ba87a00950766182966b65c65d5e2b66 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Fri, 2 Mar 2012 19:04:02 +0000
Subject: additional OpenTox errors, *_error methods in rest-client-wrapper
---
lib/error.rb | 14 +++++++++++---
lib/rest-client-wrapper.rb | 10 +++++-----
lib/task.rb | 12 +++++-------
3 files changed, 21 insertions(+), 15 deletions(-)
(limited to 'lib')
diff --git a/lib/error.rb b/lib/error.rb
index 8368404..29f4234 100644
--- a/lib/error.rb
+++ b/lib/error.rb
@@ -19,20 +19,28 @@ module OpenTox
end
end
- # create error classes dynamically
+ # OpenTox errors
{
"BadRequestError" => 400,
"NotAuthorizedError" => 401,
"NotFoundError" => 404,
"ServiceUnavailableError" => 503,
"TimeOutError" => 504,
+ "LockedError" => 423,
+ "NotImplementedError" => 501,
}.each do |klass,code|
+ # create error classes
c = Class.new Error do
define_method :initialize do |message|
super code, message
end
end
OpenTox.const_set klass,c
+
+ # define global methods for raising errors, eg. bad_request_error
+ Object.send(:define_method, klass.underscore.to_sym) do |message|
+ raise c.new message
+ end
end
# Errors received from RestClientWrapper calls
@@ -88,7 +96,7 @@ module OpenTox
# define to_ and self.from_ methods for various rdf formats
[:rdfxml,:ntriples].each do |format|
- define_singleton_method ("from_#{format}").to_sym do |rdf|
+ define_singleton_method "from_#{format}".to_sym do |rdf|
report = ErrorReport.new
RDF::Reader.for(format).new(rdf) do |reader|
reader.each_statement{ |statement| report.rdf << statement }
@@ -96,7 +104,7 @@ module OpenTox
report
end
- send :define_method, ("to_#{format}").to_sym do
+ send :define_method, "to_#{format}".to_sym do
rdfxml = RDF::Writer.for(format).buffer do |writer|
@rdf.each{|statement| writer << statement}
end
diff --git a/lib/rest-client-wrapper.rb b/lib/rest-client-wrapper.rb
index 17e1cd0..64c7d7e 100644
--- a/lib/rest-client-wrapper.rb
+++ b/lib/rest-client-wrapper.rb
@@ -28,14 +28,14 @@ module OpenTox
@request = RestClient::Request.new(args)
# check input
- raise OpenTox::BadRequestError.new "Invalid URI: '#{uri}'" unless URI.valid? uri
- raise OpenTox::BadRequestError.new "Unreachable URI: '#{uri}'" unless URI.accessible? uri
- raise OpenTox::BadRequestError.new "Headers are not a hash: #{headers.inspect}" unless headers==nil or headers.is_a?(Hash)
+ bad_request_error "Invalid URI: '#{uri}'" unless URI.valid? uri
+ bad_request_error "Unreachable URI: '#{uri}'" unless URI.accessible? uri
+ bad_request_error "Headers are not a hash: #{headers.inspect}" unless headers==nil or headers.is_a?(Hash)
# make sure that no header parameters are set in the payload
[:accept,:content_type,:subjectid].each do |header|
- raise OpenTox::BadRequestError.new "#{header} should be submitted in the headers" if payload and payload.is_a?(Hash) and payload[header]
+ bad_request_error "#{header} should be submitted in the headers" if payload and payload.is_a?(Hash) and payload[header]
end
- raise OpenTox::BadRequestError.new "waiting_task is not 'nil', OpenTox::SubTask or OpenTox::Task: #{waiting_task.class}" unless waiting_task.nil? or waiting_task.is_a?(OpenTox::Task) or waiting_task.is_a?(OpenTox::SubTask)
+ bad_request_error "waiting_task is not 'nil', OpenTox::SubTask or OpenTox::Task: #{waiting_task.class}" unless waiting_task.nil? or waiting_task.is_a?(OpenTox::Task) or waiting_task.is_a?(OpenTox::SubTask)
begin
diff --git a/lib/task.rb b/lib/task.rb
index f75f87d..d7ad539 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -17,8 +17,7 @@ module OpenTox
if URI.accessible?(result_uri)
task.completed result_uri
else
- raise NotFoundError.new "\"#{result_uri}\" is not a valid result URI"
- #task.error OpenTox::RestError.new :http_code => 404, :cause => "#{result_uri} is not a valid URI", :actor => params[:creator]
+ not_found_error "\"#{result_uri}\" is not a valid result URI"
end
rescue
task.error $!
@@ -62,8 +61,7 @@ module OpenTox
end
def completed(uri)
- #error OpenTox::RestError.new :http_code => 404, :cause => "\"#{uri}\" does not exist.", :actor => creator unless URI.accessible? uri
- raise NotFoundError.new "Result URI \"#{uri}\" does not exist." unless URI.accessible? uri
+ not_found_error "Result URI \"#{uri}\" does not exist." unless URI.accessible? uri
RestClientWrapper.put(File.join(@uri,'Completed'),{:resultURI => uri})
end
@@ -83,7 +81,7 @@ module OpenTox
due_to_time = Time.new + DEFAULT_TASK_MAX_DURATION
while running?
sleep dur
- raise TimeOutError.new "max wait time exceeded ("+DEFAULT_TASK_MAX_DURATION.to_s+"sec), task: '"+@uri.to_s+"'" if (Time.new > due_to_time)
+ time_out_error "max wait time exceeded ("+DEFAULT_TASK_MAX_DURATION.to_s+"sec), task: '"+@uri.to_s+"'" if (Time.new > due_to_time)
end
end
@@ -116,9 +114,9 @@ module OpenTox
super unless res.code == 200
else
response = metadata[RDF::OT[method]].to_s
- response = metadata[RDF::OT1[method]].to_s #if response.empty? # API 1.1 compatibility
+ response = metadata[RDF::OT1[method]].to_s if response.empty? # API 1.1 compatibility
if response.empty?
- raise NotFoundError.new "No #{method} metadata for #{@uri} "
+ not_found_error "No #{method} metadata for #{@uri} "
end
return response
end
--
cgit v1.2.3
From 7588adffdbd48a73d8b22be2379a5afee79e5bea Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Tue, 6 Mar 2012 10:59:11 +0000
Subject: backtick operator overwrite to catch system call errors
---
lib/error.rb | 16 ++++++++++++++--
lib/task.rb | 1 +
2 files changed, 15 insertions(+), 2 deletions(-)
(limited to 'lib')
diff --git a/lib/error.rb b/lib/error.rb
index 29f4234..81ec979 100644
--- a/lib/error.rb
+++ b/lib/error.rb
@@ -24,10 +24,11 @@ module OpenTox
"BadRequestError" => 400,
"NotAuthorizedError" => 401,
"NotFoundError" => 404,
- "ServiceUnavailableError" => 503,
- "TimeOutError" => 504,
"LockedError" => 423,
+ "InternalServerError" => 500,
"NotImplementedError" => 501,
+ "ServiceUnavailableError" => 503,
+ "TimeOutError" => 504,
}.each do |klass,code|
# create error classes
c = Class.new Error do
@@ -115,6 +116,17 @@ module OpenTox
end
end
+ # overwrite backtick operator to catch system errors
+class Object
+ def `(code)
+ msg = super("#{code} 2>&1").chomp
+ internal_server_error msg unless $?.to_i == 0
+ msg
+ rescue Errno::ENOENT => e
+ internal_server_error e
+ end
+end
+
class Array
def short_backtrace
short = []
diff --git a/lib/task.rb b/lib/task.rb
index d7ad539..3a52dee 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -10,6 +10,7 @@ module OpenTox
def self.create service_uri, params={}
# TODO set/enforce request uri
+ # TODO: run observer in same process?
task = Task.new RestClientWrapper.post(service_uri,params).chomp
pid = fork do
begin
--
cgit v1.2.3
From 2e3db6f6532ded28dfada22d4445038b79271814 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Wed, 7 Mar 2012 13:51:45 +0100
Subject: actor for error reports, turtle output for error reports
---
lib/error.rb | 13 +++++++++++--
lib/opentox.rb | 9 +++++++--
lib/overwrite.rb | 1 +
3 files changed, 19 insertions(+), 4 deletions(-)
(limited to 'lib')
diff --git a/lib/error.rb b/lib/error.rb
index 81ec979..90b55e3 100644
--- a/lib/error.rb
+++ b/lib/error.rb
@@ -93,9 +93,18 @@ module OpenTox
#report.rdf << [subject, OT.errorCause, error.report] if error.respond_to?(:report) and !error.report.empty?
report
end
+
+ def actor=(uri)
+ # TODO: test actor assignement (in opentox-server)
+ subject = RDF::Query.execute(@rdf) do
+ pattern [:subject, RDF.type, RDF::OT.ErrorReport]
+ end.limit(1).select(:subject)
+ })
+ @rdf << [subject, RDF::OT.actor, uri]
+ end
# define to_ and self.from_ methods for various rdf formats
- [:rdfxml,:ntriples].each do |format|
+ [:rdfxml,:ntriples,:turtle].each do |format|
define_singleton_method "from_#{format}".to_sym do |rdf|
report = ErrorReport.new
@@ -116,7 +125,7 @@ module OpenTox
end
end
- # overwrite backtick operator to catch system errors
+# overwrite backtick operator to catch system errors
class Object
def `(code)
msg = super("#{code} 2>&1").chomp
diff --git a/lib/opentox.rb b/lib/opentox.rb
index 10c7895..566c458 100644
--- a/lib/opentox.rb
+++ b/lib/opentox.rb
@@ -2,10 +2,15 @@
RDF::OT = RDF::Vocabulary.new 'http://www.opentox.org/api/1.2#'
RDF::OT1 = RDF::Vocabulary.new 'http://www.opentox.org/api/1.1#'
RDF::OTA = RDF::Vocabulary.new 'http://www.opentox.org/algorithmTypes.owl#'
+
SERVICES = ["Compound", "Feature", "Dataset", "Algorithm", "Model", "Validation", "Task", "Investigation"]
-# defaults to stderr, may be changed to file output
-$logger = OTLogger.new(STDERR) # no rotation
+# Regular expressions for parsing classification data
+TRUE_REGEXP = /^(true|active|1|1.0|tox|activating|carcinogen|mutagenic)$/i
+FALSE_REGEXP = /^(false|inactive|0|0.0|low tox|deactivating|non-carcinogen|non-mutagenic)$/i
+
+# defaults to stderr, may be changed to file output (e.g in opentox-service)
+$logger = OTLogger.new(STDERR)
$logger.level = Logger::DEBUG
module OpenTox
diff --git a/lib/overwrite.rb b/lib/overwrite.rb
index e883d45..f0dcda9 100644
--- a/lib/overwrite.rb
+++ b/lib/overwrite.rb
@@ -35,5 +35,6 @@ module URI
rescue URI::InvalidURIError
false
end
+
end
--
cgit v1.2.3
From 8fc11578aadcf1e7d152764c926e12e553bd8d65 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Wed, 7 Mar 2012 13:28:51 +0000
Subject: fixed stdout, stderr in overwritten backtick operator, error report
in turtle
---
lib/error.rb | 34 ++++++++++++++++++++++++----------
1 file changed, 24 insertions(+), 10 deletions(-)
(limited to 'lib')
diff --git a/lib/error.rb b/lib/error.rb
index 90b55e3..b65651f 100644
--- a/lib/error.rb
+++ b/lib/error.rb
@@ -1,12 +1,13 @@
-# adding additional fields to Exception class to format errors according to OT-API
+require 'open4'
+# adding additional fields to Exception class to format errors according to OT-API
class RuntimeError
attr_accessor :report, :http_code
def initialize message
super message
@http_code ||= 500
@report = OpenTox::ErrorReport.create self
- $logger.error "\n"+@report.to_ntriples
+ $logger.error "\n"+@report.to_turtle
end
end
@@ -99,7 +100,6 @@ module OpenTox
subject = RDF::Query.execute(@rdf) do
pattern [:subject, RDF.type, RDF::OT.ErrorReport]
end.limit(1).select(:subject)
- })
@rdf << [subject, RDF::OT.actor, uri]
end
@@ -126,13 +126,27 @@ module OpenTox
end
# overwrite backtick operator to catch system errors
-class Object
- def `(code)
- msg = super("#{code} 2>&1").chomp
- internal_server_error msg unless $?.to_i == 0
- msg
- rescue Errno::ENOENT => e
- internal_server_error e
+module Kernel
+
+ # Override raises an error if _cmd_ returns a non-zero exit status.
+ # Returns stdout if _cmd_ succeeds. Note that these are simply concatenated; STDERR is not inline.
+ def ` cmd
+ stdout, stderr = ''
+ status = Open4::popen4(cmd) do |pid, stdin_stream, stdout_stream, stderr_stream|
+ stdout = stdout_stream.read
+ stderr = stderr_stream.read
+ end
+ raise stderr.strip if !status.success?
+ return stdout
+ rescue Exception
+ internal_server_error "'#{cmd}' failed with: '#{$!.message}'"
+ end
+
+ alias_method :system!, :system
+
+ def system cmd
+ `#{cmd}`
+ return true
end
end
--
cgit v1.2.3
From 2f6d5c75fc1fece5fc10cc7c45ad59cf6b820d64 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Wed, 7 Mar 2012 17:13:48 +0000
Subject: error and dataset tests added, wait_for_task moved to URI.to_object
---
lib/error.rb | 10 ++++---
lib/opentox.rb | 20 +++++++------
lib/overwrite.rb | 27 +++++++++++++++--
lib/rest-client-wrapper.rb | 73 +++++++++++++---------------------------------
4 files changed, 62 insertions(+), 68 deletions(-)
(limited to 'lib')
diff --git a/lib/error.rb b/lib/error.rb
index b65651f..2033c1e 100644
--- a/lib/error.rb
+++ b/lib/error.rb
@@ -5,7 +5,9 @@ class RuntimeError
attr_accessor :report, :http_code
def initialize message
super message
+ self.set_backtrace message.backtrace if message.is_a? Exception
@http_code ||= 500
+ puts self.class
@report = OpenTox::ErrorReport.create self
$logger.error "\n"+@report.to_turtle
end
@@ -77,9 +79,10 @@ module OpenTox
errorDetails += "REST paramenters:\n#{error.request.args.inspect}"
end
error.respond_to?(:http_code) ? statusCode = error.http_code : statusCode = 500
+ puts error.inspect
if error.respond_to? :response
- statusCode = error.response.code
- message = error.body
+ statusCode = error.response.code if error.response
+ message = error.response.body
end
statusCode = error.http_code if error.respond_to? :http_code
report.rdf << [subject, RDF::OT.statusCode, statusCode ]
@@ -87,7 +90,6 @@ module OpenTox
# TODO: remove kludge for old task services
report.http_code = statusCode
report.rdf << [subject, RDF::OT.message , message ]
-
errorDetails += "\nBacktrace:\n" + error.backtrace.short_backtrace if error.respond_to?(:backtrace) and error.backtrace
report.rdf << [subject, RDF::OT.errorDetails, errorDetails ]
# TODO Error cause
@@ -139,7 +141,7 @@ module Kernel
raise stderr.strip if !status.success?
return stdout
rescue Exception
- internal_server_error "'#{cmd}' failed with: '#{$!.message}'"
+ internal_server_error $!
end
alias_method :system!, :system
diff --git a/lib/opentox.rb b/lib/opentox.rb
index 566c458..9ba64bd 100644
--- a/lib/opentox.rb
+++ b/lib/opentox.rb
@@ -70,8 +70,7 @@ module OpenTox
def delete headers={}
headers[:subjectid] ||= @subjectid
- headers[:accept] ||= 'application/rdf+xml'
- @response = RestClientWrapper.delete(@uri.to_s,:subjectid => @subjectid)
+ @response = RestClientWrapper.delete(@uri.to_s,nil,nil,headers)
end
# class methods
@@ -82,23 +81,26 @@ module OpenTox
subjectid ? eval("#{self}.new(\"#{uri}\", #{subjectid})") : eval("#{self}.new(\"#{uri}\")")
end
- def from_file service_uri, file, subjectid=nil
- RestClientWrapper.post(service_uri, :file => File.new(file), :subjectid => subjectid).chomp.to_object
+ def from_file service_uri, filename, subjectid=nil
+ file = File.new filename
+ uri = RestClientWrapper.post(service_uri, {:file => file}, {:subjectid => subjectid, :content_type => file.mime_type, :accept => "text/uri-list"})
+ puts uri
end
def all service_uri, subjectid=nil
- uris = RestClientWrapper.get(service_uri, nil, {:accept => 'text/uri-list'}).split("\n").compact
+ uris = RestClientWrapper.get(service_uri, {}, :accept => 'text/uri-list').split("\n").compact
uris.collect{|uri| subjectid ? eval("#{self}.new(\"#{uri}\", #{subjectid})") : eval("#{self}.new(\"#{uri}\")")}
end
end
- # create default classes
- SERVICES.each do |s|
- eval "class #{s}
+ # create default OpenTox classes
+ SERVICES.each do |klass|
+ c = Class.new do
include OpenTox
extend OpenTox::ClassMethods
- end"
+ end
+ OpenTox.const_set klass,c
end
end
diff --git a/lib/overwrite.rb b/lib/overwrite.rb
index f0dcda9..c7a1d43 100644
--- a/lib/overwrite.rb
+++ b/lib/overwrite.rb
@@ -23,8 +23,13 @@ module URI
end
def self.accessible? uri, subjectid=nil
- Net::HTTP.get_response(URI.parse(uri))
- true
+ if URI.task? uri
+ # just ry to get a response, valid tasks may return codes > 400
+ Net::HTTP.get_response(URI.parse(uri))
+ true
+ else
+ Net::HTTP.get_response(URI.parse(uri)).code.to_i < 400
+ end
rescue
false
end
@@ -36,5 +41,23 @@ module URI
false
end
+ def self.to_object uri, wait=true
+
+ # TODO add waiting task
+ if task? uri and wait
+ t = OpenTox::Task.new(uri)
+ t.wait
+ uri = t.resultURI
+ end
+
+ klass =
+ subjectid ? eval("#{self}.new(\"#{uri}\", #{subjectid})") : eval("#{self}.new(\"#{uri}\")")
+ end
+
end
+class File
+ def mime_type
+ `file -ib #{self.path}`.chomp
+ end
+end
diff --git a/lib/rest-client-wrapper.rb b/lib/rest-client-wrapper.rb
index 64c7d7e..e594729 100644
--- a/lib/rest-client-wrapper.rb
+++ b/lib/rest-client-wrapper.rb
@@ -13,7 +13,7 @@ module OpenTox
# @param [optional,OpenTox::Task] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
# @param [wait,Boolean] Set to false to NOT wait for task if result is a task
# @return [RestClient::Response] REST call response
- [:head,:get,:post,:put,:dealete].each do |method|
+ [:head,:get,:post,:put,:delete].each do |method|
define_singleton_method method do |uri,payload={},headers={},waiting_task=nil, wait=true|
@@ -25,64 +25,40 @@ module OpenTox
args[:payload] = payload
headers.each{ |k,v| headers.delete(k) if v==nil } if headers #remove keys with empty values, as this can cause problems
args[:headers] = headers
- @request = RestClient::Request.new(args)
# check input
bad_request_error "Invalid URI: '#{uri}'" unless URI.valid? uri
- bad_request_error "Unreachable URI: '#{uri}'" unless URI.accessible? uri
+ not_found_error "URI '#{uri}' not found." unless URI.accessible? uri
bad_request_error "Headers are not a hash: #{headers.inspect}" unless headers==nil or headers.is_a?(Hash)
# make sure that no header parameters are set in the payload
[:accept,:content_type,:subjectid].each do |header|
bad_request_error "#{header} should be submitted in the headers" if payload and payload.is_a?(Hash) and payload[header]
end
- bad_request_error "waiting_task is not 'nil', OpenTox::SubTask or OpenTox::Task: #{waiting_task.class}" unless waiting_task.nil? or waiting_task.is_a?(OpenTox::Task) or waiting_task.is_a?(OpenTox::SubTask)
+ #bad_request_error "waiting_task is not 'nil', OpenTox::SubTask or OpenTox::Task: #{waiting_task.class}" unless waiting_task.nil? or waiting_task.is_a?(OpenTox::Task) or waiting_task.is_a?(OpenTox::SubTask)
-
- begin
- @response = @request.execute do |response, request, result|
- # ignore error codes from Task services (may contain eg 500 which causes exceptions in RestClient and RDF::Reader
- rest_error "Response code is #{response.code}" unless response.code < 400 or URI.task? uri
- return response
- end
-
- return @response if @response.code==200 or !wait
+ # perform request
+ @request = RestClient::Request.new(args)
+ #begin
+ # do not throw RestClient exceptions in order to create a @response object (needed for error reports) in every case
+ @response = @request.execute { |response, request, result| return response }
+ # ignore error codes from Task services (may return error codes >= 400 according to API, which causes exceptions in RestClient and RDF::Reader)
+ raise OpenTox::RestCallError.new @request, @response, "Response code is #{@response.code}." unless @response.code < 400 or URI.task? uri
+ #return @response if @response.code==200 or !wait
# wait for task
- while @response.code==201 or @response.code==202
- @response = wait_for_task(@response, uri, waiting_task)
- end
- return @response
+ #while @response.code==201 or @response.code==202
+ #@response = wait_for_task(@response, uri, waiting_task)
+ #end
+ @response
- rescue
- rest_error $!.message
- end
-=begin
- rescue RestClient::RequestTimeout
- raise OpenTox::Error @request, @response, $!.message
- #received_error ex.message, 408, nil, {:rest_uri => uri, :headers => headers, :payload => payload}
- rescue Errno::ETIMEDOUT
- raise OpenTox::Error @request, @response, $!.message
- #received_error ex.message, 408, nil, {:rest_uri => uri, :headers => headers, :payload => payload}
- rescue Errno::ECONNREFUSED
- raise OpenTox::Error $!.message
- #received_error ex.message, 500, nil, {:rest_uri => uri, :headers => headers, :payload => payload}
- rescue RestClient::ExceptionWithResponse
- # error comming from a different webservice,
- received_error ex.http_body, ex.http_code, ex.response.net_http_res.content_type, {:rest_uri => uri, :headers => headers, :payload => payload}
- #rescue OpenTox::RestCallError => ex
- # already a rest-error, probably comes from wait_for_task, just pass through
- #raise ex
- #rescue => ex
- # some internal error occuring in rest-client-wrapper, just pass through
- #raise ex
- end
-=end
+ #rescue
+ #rest_error $!.message
+ #end
end
end
+=begin
def wait_for_task( response, base_uri, waiting_task=nil )
- #TODO remove TUM hack
- # @response.headers[:content_type] = "text/uri-list" if base_uri =~/tu-muenchen/ and @response.headers[:content_type] == "application/x-www-form-urlencoded;charset=UTF-8"
task = nil
case @response.headers[:content_type]
@@ -97,7 +73,6 @@ module OpenTox
rest_error "Unknown content-type for task : '"+@response.headers[:content_type].to_s+"'"+" base-uri: "+base_uri.to_s+" content: "+@response[0..200].to_s
end
- #LOGGER.debug "result is a task '"+task.uri.to_s+"', wait for completion"
task.wait waiting_task
unless task.completed? # maybe task was cancelled / error
if task.errorReport
@@ -111,18 +86,10 @@ module OpenTox
end
def self.rest_error message
+ puts message
raise OpenTox::RestCallError.new @request, @response, message
end
-=begin
- def self.bad_request_error message
- raise OpenTox::Error.new message
- end
-
- def self.not_found_error message
- raise OpenTox::NotFoundError.new message
- end
-
def self.received_error( body, code, content_type=nil, params=nil )
# try to parse body TODO
--
cgit v1.2.3
From 63fcd8f8feed58af4b1e1ff0e5fdaa09791c9596 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Thu, 8 Mar 2012 15:23:43 +0000
Subject: improved integration of error reports, call stack added as
errorDetails
---
lib/error.rb | 147 ++++++++++++++-------------------------------
lib/opentox-client.rb | 16 +++++
lib/opentox.rb | 118 ++++++++++++++++++++++++------------
lib/overwrite.rb | 55 ++++++++++++-----
lib/rest-client-wrapper.rb | 122 +++++--------------------------------
lib/task.rb | 37 ++++--------
6 files changed, 207 insertions(+), 288 deletions(-)
(limited to 'lib')
diff --git a/lib/error.rb b/lib/error.rb
index 2033c1e..0ab2c73 100644
--- a/lib/error.rb
+++ b/lib/error.rb
@@ -1,24 +1,27 @@
require 'open4'
-# adding additional fields to Exception class to format errors according to OT-API
+# add additional fields to Exception class to format errors according to OT-API
class RuntimeError
- attr_accessor :report, :http_code
- def initialize message
+ attr_accessor :http_code, :uri
+ def initialize message, uri=nil
super message
- self.set_backtrace message.backtrace if message.is_a? Exception
+ @uri = uri
@http_code ||= 500
- puts self.class
- @report = OpenTox::ErrorReport.create self
- $logger.error "\n"+@report.to_turtle
+ $logger.error "\n"+self.report.to_turtle
+ end
+
+ def report
+ # TODO: remove kludge for old task services
+ OpenTox::ErrorReport.new(@http_code, self)
end
end
module OpenTox
class Error < RuntimeError
- def initialize code, message
+ def initialize code, message, uri=nil
@http_code = code
- super message
+ super message, uri
end
end
@@ -35,15 +38,16 @@ module OpenTox
}.each do |klass,code|
# create error classes
c = Class.new Error do
- define_method :initialize do |message|
- super code, message
+ define_method :initialize do |message, uri=nil|
+ super code, message, uri
end
end
OpenTox.const_set klass,c
# define global methods for raising errors, eg. bad_request_error
Object.send(:define_method, klass.underscore.to_sym) do |message|
- raise c.new message
+ defined?(@uri) ? uri = @uri : uri=nil
+ raise c, message, uri
end
end
@@ -53,61 +57,41 @@ module OpenTox
def initialize request, response, message
@request = request
@response = response
- super 502, message
+ super 502, message, request.url
end
end
+ # TODO: create reports directly from errors, requires modified task service
class ErrorReport
-
- attr_accessor :rdf # RDF Graph
- attr_accessor :http_code # TODO: remove when task service is fixed
-
- def initialize
- @rdf = RDF::Graph.new
- end
-
- # creates a error report object, from an ruby-exception object
- # @param [Exception] error
- def self.create error
- report = ErrorReport.new
- subject = RDF::Node.new
- report.rdf << [subject, RDF.type, RDF::OT.ErrorReport]
- message = error.message
- errorDetails = ""
- if error.respond_to? :request
- report.rdf << [subject, RDF::OT.actor, error.request.url ]
- errorDetails += "REST paramenters:\n#{error.request.args.inspect}"
- end
- error.respond_to?(:http_code) ? statusCode = error.http_code : statusCode = 500
- puts error.inspect
- if error.respond_to? :response
- statusCode = error.response.code if error.response
- message = error.response.body
- end
- statusCode = error.http_code if error.respond_to? :http_code
- report.rdf << [subject, RDF::OT.statusCode, statusCode ]
- report.rdf << [subject, RDF::OT.errorCode, error.class.to_s ]
- # TODO: remove kludge for old task services
- report.http_code = statusCode
- report.rdf << [subject, RDF::OT.message , message ]
- errorDetails += "\nBacktrace:\n" + error.backtrace.short_backtrace if error.respond_to?(:backtrace) and error.backtrace
- report.rdf << [subject, RDF::OT.errorDetails, errorDetails ]
- # TODO Error cause
- #report.rdf << [subject, OT.errorCause, error.report] if error.respond_to?(:report) and !error.report.empty?
- report
+ def initialize http_code, error
+ @http_code = http_code
+ #@report = report#.to_yaml
+ @report = {}
+ @report[RDF::OT.actor] = error.uri
+ @report[RDF::OT.message] = error.message
+ @report[RDF::OT.statusCode] = @http_code
+ @report[RDF::OT.errorCode] = error.class.to_s
+ @report[RDF::OT.errorDetails] = caller.collect{|line| line unless line =~ /#{File.dirname(__FILE__)}/}.compact.join("\n")
+ @report[RDF::OT.errorDetails] += "REST paramenters:\n#{error.request.args.inspect}" if defined? error.request
+ @report[RDF::OT.message] += "\n" + error.response.body if defined? error.response
+ # TODO fix Error cause
+ #report[RDF::OT.errorCause] = @report if defined?(@report)
end
- def actor=(uri)
- # TODO: test actor assignement (in opentox-server)
- subject = RDF::Query.execute(@rdf) do
- pattern [:subject, RDF.type, RDF::OT.ErrorReport]
- end.limit(1).select(:subject)
- @rdf << [subject, RDF::OT.actor, uri]
- end
-
# define to_ and self.from_ methods for various rdf formats
- [:rdfxml,:ntriples,:turtle].each do |format|
+ RDF_FORMATS.each do |format|
+
+ send :define_method, "to_#{format}".to_sym do
+ rdf = RDF::Writer.for(format).buffer do |writer|
+ subject = RDF::Node.new
+ @report.each do |predicate,object|
+ writer << [subject, predicate, object] if object
+ end
+ end
+ rdf
+ end
+=begin
define_singleton_method "from_#{format}".to_sym do |rdf|
report = ErrorReport.new
RDF::Reader.for(format).new(rdf) do |reader|
@@ -115,50 +99,7 @@ module OpenTox
end
report
end
-
- send :define_method, "to_#{format}".to_sym do
- rdfxml = RDF::Writer.for(format).buffer do |writer|
- @rdf.each{|statement| writer << statement}
- end
- rdfxml
- end
- end
-
- end
-end
-
-# overwrite backtick operator to catch system errors
-module Kernel
-
- # Override raises an error if _cmd_ returns a non-zero exit status.
- # Returns stdout if _cmd_ succeeds. Note that these are simply concatenated; STDERR is not inline.
- def ` cmd
- stdout, stderr = ''
- status = Open4::popen4(cmd) do |pid, stdin_stream, stdout_stream, stderr_stream|
- stdout = stdout_stream.read
- stderr = stderr_stream.read
- end
- raise stderr.strip if !status.success?
- return stdout
- rescue Exception
- internal_server_error $!
- end
-
- alias_method :system!, :system
-
- def system cmd
- `#{cmd}`
- return true
- end
-end
-
-class Array
- def short_backtrace
- short = []
- each do |c|
- break if c =~ /sinatra\/base/
- short << c
+=end
end
- short.join("\n")
end
end
diff --git a/lib/opentox-client.rb b/lib/opentox-client.rb
index a587aa5..7d9329d 100644
--- a/lib/opentox-client.rb
+++ b/lib/opentox-client.rb
@@ -6,6 +6,22 @@ require "rest-client"
require 'uri'
require 'yaml'
require 'logger'
+
+# define constants and global variables
+#TODO: switch services to 1.2
+RDF::OT = RDF::Vocabulary.new 'http://www.opentox.org/api/1.2#'
+RDF::OT1 = RDF::Vocabulary.new 'http://www.opentox.org/api/1.1#'
+RDF::OTA = RDF::Vocabulary.new 'http://www.opentox.org/algorithmTypes.owl#'
+
+#CLASSES = ["Compound", "Feature", "Dataset", "Algorithm", "Model", "Validation", "Task", "ErrorReport", "Investigation"]
+CLASSES = ["Compound", "Feature", "Dataset", "Algorithm", "Model", "Validation", "Task", "Investigation"]
+RDF_FORMATS = [:rdfxml,:ntriples,:turtle]
+$default_rdf = "application/rdf+xml"
+
+# Regular expressions for parsing classification data
+TRUE_REGEXP = /^(true|active|1|1.0|tox|activating|carcinogen|mutagenic)$/i
+FALSE_REGEXP = /^(false|inactive|0|0.0|low tox|deactivating|non-carcinogen|non-mutagenic)$/i
+
require File.join(File.dirname(__FILE__),"overwrite.rb")
require File.join(File.dirname(__FILE__),"error.rb")
require File.join(File.dirname(__FILE__),"rest-client-wrapper.rb")
diff --git a/lib/opentox.rb b/lib/opentox.rb
index 9ba64bd..342b04e 100644
--- a/lib/opentox.rb
+++ b/lib/opentox.rb
@@ -1,52 +1,73 @@
-#TODO: switch services to 1.2
-RDF::OT = RDF::Vocabulary.new 'http://www.opentox.org/api/1.2#'
-RDF::OT1 = RDF::Vocabulary.new 'http://www.opentox.org/api/1.1#'
-RDF::OTA = RDF::Vocabulary.new 'http://www.opentox.org/algorithmTypes.owl#'
-
-SERVICES = ["Compound", "Feature", "Dataset", "Algorithm", "Model", "Validation", "Task", "Investigation"]
-
-# Regular expressions for parsing classification data
-TRUE_REGEXP = /^(true|active|1|1.0|tox|activating|carcinogen|mutagenic)$/i
-FALSE_REGEXP = /^(false|inactive|0|0.0|low tox|deactivating|non-carcinogen|non-mutagenic)$/i
-
# defaults to stderr, may be changed to file output (e.g in opentox-service)
$logger = OTLogger.new(STDERR)
$logger.level = Logger::DEBUG
module OpenTox
- attr_accessor :subjectid, :uri, :response
- attr_writer :metadata
+ attr_accessor :uri, :subjectid, :rdf, :response
+ # Ruby interface
+
+ # Create a new OpenTox object (does not load data from service)
+ # @param [optional,String] URI
+ # @param [optional,String] subjectid
+ # @return [OpenTox] OpenTox object
def initialize uri=nil, subjectid=nil
- @uri = uri.chomp
+ @uri = uri.to_s.chomp
@subjectid = subjectid
+ @rdf = RDF::Graph.new
end
- # Ruby interface
+ # Load metadata from service
+ def pull
+ kind_of?(OpenTox::Dataset) ? uri = File.join(@uri,"metadata") : uri = @uri
+ # TODO generic method for all formats
+ parse_rdfxml RestClientWrapper.get(uri,{},{:accept => $default_rdf, :subjectid => @subjectid})
+ end
- def metadata reload=true
- if reload or @metadata.empty?
- @metadata = {}
- kind_of?(OpenTox::Dataset) ? uri = File.join(@uri,"metadata") : uri = @uri
- RDF::Reader.for(:rdfxml).new( RestClientWrapper.get(uri) ) do |reader|
- reader.each_statement do |statement|
- @metadata[statement.predicate] = statement.object if statement.subject == @uri
- end
- end
+ # Get object metadata
+ # @return [Hash] Metadata
+ def metadata
+ pull if @rdf.empty?
+ metadata = {}
+ @rdf.query([RDF::URI.new(@uri),nil,nil]).collect do |statement|
+ metadata[statement.predicate] ||= []
+ metadata[statement.predicate] << statement.object
end
- @metadata
+ metadata
+ end
+
+ # Get metadata values
+ # @param [RDF] Key from RDF Vocabularies
+ # @return [Array] Values for supplied key
+ def [](key)
+ pull if @rdf.empty?
+ @rdf.query([RDF::URI.new(@uri),key,nil]).collect{|statement| statement.object}
end
+ # Save object at service
def save
- post self.to_rdfxml, { :content_type => 'application/rdf+xml'}
+ #TODO: dynamic assignment
+ post self.to_rdfxml, { :content_type => $default_rdf}
end
- def to_rdfxml
- rdf = RDF::Writer.for(:rdfxml).buffer do |writer|
- @metadata.each { |p,o| writer << RDF::Statement.new(RDF::URI.new(@uri), p, o) }
+ RDF_FORMATS.each do |format|
+
+ # rdf parse methods for all formats e.g. parse_rdfxml
+ send :define_method, "parse_#{format}".to_sym do |rdf|
+ @rdf = RDF::Graph.new
+ RDF::Reader.for(format).new(rdf) do |reader|
+ reader.each_statement{ |statement| @rdf << statement }
+ end
+ end
+
+ # rdf serialization methods for all formats e.g. to_rdfxml
+ send :define_method, "to_#{format}".to_sym do
+ rdf = RDF::Writer.for(format).buffer do |writer|
+ @rdf.each{|statement| writer << statement}
+ end
+ rdf
end
- rdf
end
# REST API
@@ -70,32 +91,49 @@ module OpenTox
def delete headers={}
headers[:subjectid] ||= @subjectid
- @response = RestClientWrapper.delete(@uri.to_s,nil,nil,headers)
+ @response = RestClientWrapper.delete(@uri.to_s,nil,headers)
end
# class methods
module ClassMethods
+ def all service_uri, subjectid=nil
+ uris = RestClientWrapper.get(service_uri, {}, :accept => 'text/uri-list').split("\n").compact
+ uris.collect{|uri| URI.task?(service_uri) ? from_uri(uri, subjectid, false) : from_uri(uri, subjectid)}
+ end
+
def create service_uri, subjectid=nil
- uri = RestClientWrapper.post(service_uri, {}, :subjectid => subjectid).chomp
- subjectid ? eval("#{self}.new(\"#{uri}\", #{subjectid})") : eval("#{self}.new(\"#{uri}\")")
+ uri = RestClientWrapper.post(service_uri, {}, {:accept => 'text/uri-list', :subjectid => subjectid})
+ URI.task?(service_uri) ? from_uri(uri, subjectid, false) : from_uri(uri, subjectid)
end
def from_file service_uri, filename, subjectid=nil
file = File.new filename
- uri = RestClientWrapper.post(service_uri, {:file => file}, {:subjectid => subjectid, :content_type => file.mime_type, :accept => "text/uri-list"})
- puts uri
+ from_uri RestClientWrapper.post(service_uri, {:file => file}, {:subjectid => subjectid, :content_type => file.mime_type, :accept => "text/uri-list"}), subjectid
end
- def all service_uri, subjectid=nil
- uris = RestClientWrapper.get(service_uri, {}, :accept => 'text/uri-list').split("\n").compact
- uris.collect{|uri| subjectid ? eval("#{self}.new(\"#{uri}\", #{subjectid})") : eval("#{self}.new(\"#{uri}\")")}
- end
+ private
+ def from_uri uri, subjectid=nil, wait=true
+
+ uri.chomp!
+ # TODO add waiting task
+ if URI.task? uri and wait
+ t = OpenTox::Task.new(uri)
+ t.wait
+ uri = t.resultURI
+ end
+ # guess class from uri, this is potentially unsafe, but polling metadata from large uri lists is way too slow (and not all service provide RDF.type in their metadata)
+ result = CLASSES.collect{|s| s if uri =~ /#{s.downcase}/}.compact
+ internal_server_error "Cannot determine class from URI: '#{uri}.\nCandidate classes are #{result.inspect}" unless result.size == 1
+ klass = result.first
+ # initialize with/without subjectid
+ subjectid ? eval("#{self}.new(\"#{uri}\", #{subjectid})") : eval("#{self}.new(\"#{uri}\")")
+ end
end
# create default OpenTox classes
- SERVICES.each do |klass|
+ CLASSES.each do |klass|
c = Class.new do
include OpenTox
extend OpenTox::ClassMethods
diff --git a/lib/overwrite.rb b/lib/overwrite.rb
index c7a1d43..7b6cb4f 100644
--- a/lib/overwrite.rb
+++ b/lib/overwrite.rb
@@ -10,6 +10,10 @@ end
module URI
+ def self.compound? uri
+ uri =~ /compound/ and URI.valid? uri
+ end
+
def self.task? uri
uri =~ /task/ and URI.valid? uri
end
@@ -23,8 +27,8 @@ module URI
end
def self.accessible? uri, subjectid=nil
- if URI.task? uri
- # just ry to get a response, valid tasks may return codes > 400
+ if URI.task? uri or URI.compound? uri
+ # just try to get a response, valid tasks may return codes > 400
Net::HTTP.get_response(URI.parse(uri))
true
else
@@ -41,23 +45,46 @@ module URI
false
end
- def self.to_object uri, wait=true
+end
- # TODO add waiting task
- if task? uri and wait
- t = OpenTox::Task.new(uri)
- t.wait
- uri = t.resultURI
- end
+class File
+ def mime_type
+ `file -ib #{self.path}`.chomp
+ end
+end
- klass =
- subjectid ? eval("#{self}.new(\"#{uri}\", #{subjectid})") : eval("#{self}.new(\"#{uri}\")")
+# overwrite backtick operator to catch system errors
+module Kernel
+
+ # Override raises an error if _cmd_ returns a non-zero exit status.
+ # Returns stdout if _cmd_ succeeds. Note that these are simply concatenated; STDERR is not inline.
+ def ` cmd
+ stdout, stderr = ''
+ status = Open4::popen4(cmd) do |pid, stdin_stream, stdout_stream, stderr_stream|
+ stdout = stdout_stream.read
+ stderr = stderr_stream.read
+ end
+ raise stderr.strip if !status.success?
+ return stdout
+ rescue Exception
+ internal_server_error $!
end
+ alias_method :system!, :system
+
+ def system cmd
+ `#{cmd}`
+ return true
+ end
end
-class File
- def mime_type
- `file -ib #{self.path}`.chomp
+class Array
+ def short_backtrace
+ short = []
+ each do |c|
+ break if c =~ /sinatra\/base/
+ short << c
+ end
+ short.join("\n")
end
end
diff --git a/lib/rest-client-wrapper.rb b/lib/rest-client-wrapper.rb
index e594729..c9e6bbb 100644
--- a/lib/rest-client-wrapper.rb
+++ b/lib/rest-client-wrapper.rb
@@ -10,21 +10,10 @@ module OpenTox
# @param [String] destination URI
# @param [optional,Hash|String] Payload data posted to the service
# @param [optional,Hash] Headers with params like :accept, :content_type, :subjectid
- # @param [optional,OpenTox::Task] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
- # @param [wait,Boolean] Set to false to NOT wait for task if result is a task
# @return [RestClient::Response] REST call response
[:head,:get,:post,:put,:delete].each do |method|
- define_singleton_method method do |uri,payload={},headers={},waiting_task=nil, wait=true|
-
- # create request
- args={}
- args[:method] = method
- args[:url] = uri
- args[:timeout] = 600
- args[:payload] = payload
- headers.each{ |k,v| headers.delete(k) if v==nil } if headers #remove keys with empty values, as this can cause problems
- args[:headers] = headers
+ define_singleton_method method do |uri,payload={},headers={}|
# check input
bad_request_error "Invalid URI: '#{uri}'" unless URI.valid? uri
@@ -34,106 +23,25 @@ module OpenTox
[:accept,:content_type,:subjectid].each do |header|
bad_request_error "#{header} should be submitted in the headers" if payload and payload.is_a?(Hash) and payload[header]
end
- #bad_request_error "waiting_task is not 'nil', OpenTox::SubTask or OpenTox::Task: #{waiting_task.class}" unless waiting_task.nil? or waiting_task.is_a?(OpenTox::Task) or waiting_task.is_a?(OpenTox::SubTask)
+
+ # create request
+ args={}
+ args[:method] = method
+ args[:url] = uri
+ args[:timeout] = 600
+ args[:payload] = payload
+ headers.each{ |k,v| headers.delete(k) if v==nil } if headers #remove keys with empty values, as this can cause problems
+ args[:headers] = headers
# perform request
@request = RestClient::Request.new(args)
- #begin
- # do not throw RestClient exceptions in order to create a @response object (needed for error reports) in every case
- @response = @request.execute { |response, request, result| return response }
- # ignore error codes from Task services (may return error codes >= 400 according to API, which causes exceptions in RestClient and RDF::Reader)
- raise OpenTox::RestCallError.new @request, @response, "Response code is #{@response.code}." unless @response.code < 400 or URI.task? uri
- #return @response if @response.code==200 or !wait
-
- # wait for task
- #while @response.code==201 or @response.code==202
- #@response = wait_for_task(@response, uri, waiting_task)
- #end
- @response
-
- #rescue
- #rest_error $!.message
- #end
- end
- end
-
-=begin
- def wait_for_task( response, base_uri, waiting_task=nil )
-
- task = nil
- case @response.headers[:content_type]
- when /application\/rdf\+xml/
- # TODO: task uri from rdf
- #task = OpenTox::Task.from_rdfxml(@response)
- #task = OpenTox::Task.from_rdfxml(@response)
- when /text\/uri-list/
- rest_error "Uri list has more than one entry, should be a single task" if @response.split("\n").size > 1 #if uri list contains more then one uri, its not a task
- task = OpenTox::Task.new(@response.to_s.chomp) if URI.available? @response.to_s
- else
- rest_error "Unknown content-type for task : '"+@response.headers[:content_type].to_s+"'"+" base-uri: "+base_uri.to_s+" content: "+@response[0..200].to_s
+ # do not throw RestClient exceptions in order to create a @response object (needed for error reports) in every case
+ @response = @request.execute { |response, request, result| return response }
+ # ignore error codes from Task services (may return error codes >= 400 according to API, which causes exceptions in RestClient and RDF::Reader)
+ raise OpenTox::RestCallError.new @request, @response, "Response code is #{@response.code}." unless @response.code < 400 or URI.task? uri
+ @response
end
-
- task.wait waiting_task
- unless task.completed? # maybe task was cancelled / error
- if task.errorReport
- received_error task.errorReport, task.http_code, nil, {:rest_uri => task.uri, :rest_code => task.http_code}
- else
- rest_error "Status of task '"+task.uri.to_s+"' is no longer running (hasStatus is '"+task.status+
- "'), but it is neither completed nor has an errorReport"
- end
- end
- @response
- end
-
- def self.rest_error message
- puts message
- raise OpenTox::RestCallError.new @request, @response, message
end
- def self.received_error( body, code, content_type=nil, params=nil )
-
- # try to parse body TODO
- body.is_a?(OpenTox::ErrorReport) ? report = body : report = OpenTox::ErrorReport.from_rdf(body)
- rest_call_error "REST call returned error: '"+body.to_s+"'" unless report
- # parsing sucessfull
- # raise RestCallError with parsed report as error cause
- err = OpenTox::RestCallError.new(@request, @response, "REST call subsequent error")
- err.errorCause = report
- raise err
- end
-=end
-=begin
- def self.received_error( body, code, content_type=nil, params=nil )
-
- # try to parse body
- report = nil
- #report = OpenTox::ErrorReport.from_rdf(body)
- if body.is_a?(OpenTox::ErrorReport)
- report = body
- else
- case content_type
- when /yaml/
- report = YAML.load(body)
- when /rdf/
- report = OpenTox::ErrorReport.from_rdf(body)
- end
- end
-
- unless report
- # parsing was not successfull
- # raise 'plain' RestCallError
- err = OpenTox::RestCallError.new("REST call returned error: '"+body.to_s+"'")
- err.rest_params = params
- raise err
- else
- # parsing sucessfull
- # raise RestCallError with parsed report as error cause
- err = OpenTox::RestCallError.new("REST call subsequent error")
- err.errorCause = report
- err.rest_params = params
- raise err
- end
- end
-=end
end
end
diff --git a/lib/task.rb b/lib/task.rb
index 3a52dee..0562dc7 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -15,13 +15,11 @@ module OpenTox
pid = fork do
begin
result_uri = yield
- if URI.accessible?(result_uri)
- task.completed result_uri
- else
- not_found_error "\"#{result_uri}\" is not a valid result URI"
- end
+ task.completed result_uri
rescue
- task.error $!
+ RestClientWrapper.put(File.join(task.uri,'Error'),{:errorReport => $!.report.to_yaml})
+ task.kill
+ #raise $!
end
end
Process.detach(pid)
@@ -49,11 +47,13 @@ module OpenTox
end
def description
- metadata[RDF::DC.description]
+ pull
+ self.[](RDF::DC.description).uniq.first
end
def creator
- metadata[RDF::DC.creator]
+ pull
+ self.[](RDF::DC.creator).uniq.first
end
def cancel
@@ -66,16 +66,6 @@ module OpenTox
RestClientWrapper.put(File.join(@uri,'Completed'),{:resultURI => uri})
end
- def error error
- # TODO: switch task service to rdf
- #RestClientWrapper.put(File.join(@uri,'Error'),{:errorReport => error.report.to_rdfxml})
- # create report for non-runtime errors
- error.respond_to?(:reporti) ? report = error.report : report = OpenTox::ErrorReport.create(error)
- RestClientWrapper.put(File.join(@uri,'Error'),{:errorReport => report.to_yaml})
- kill
- raise error
- end
-
# waits for a task, unless time exceeds or state is no longer running
# @param [optional,Numeric] dur seconds pausing before checking again for completion
def wait(dur=0.3)
@@ -114,12 +104,11 @@ module OpenTox
res = RestClientWrapper.put(File.join(@uri,method.sub(/=/,'')),{})
super unless res.code == 200
else
- response = metadata[RDF::OT[method]].to_s
- response = metadata[RDF::OT1[method]].to_s if response.empty? # API 1.1 compatibility
- if response.empty?
- not_found_error "No #{method} metadata for #{@uri} "
- end
- return response
+ pull
+ response = self.[](RDF::OT[method])
+ response = self.[](RDF::OT1[method]) if response.empty? # API 1.1 compatibility
+ internal_server_error "No #{method} metadata for #{@uri} " if response.empty?
+ return response.uniq.first.to_s
end
rescue OpenTox::Error
raise $!
--
cgit v1.2.3
From 47672c664cda9f139fbd8d522a7ffbdf6813dd27 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Thu, 8 Mar 2012 19:16:21 +0000
Subject: TODO reminder
---
lib/error.rb | 1 +
1 file changed, 1 insertion(+)
(limited to 'lib')
diff --git a/lib/error.rb b/lib/error.rb
index 0ab2c73..7fc2461 100644
--- a/lib/error.rb
+++ b/lib/error.rb
@@ -47,6 +47,7 @@ module OpenTox
# define global methods for raising errors, eg. bad_request_error
Object.send(:define_method, klass.underscore.to_sym) do |message|
defined?(@uri) ? uri = @uri : uri=nil
+ # TODO: insert uri from sinatra
raise c, message, uri
end
end
--
cgit v1.2.3
From edfdc45754c05507deb63b16cb09dbdca6c8400f Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Fri, 9 Mar 2012 21:52:20 +0000
Subject: gemspec updated
---
lib/opentox-client/version.rb | 5 -----
1 file changed, 5 deletions(-)
delete mode 100644 lib/opentox-client/version.rb
(limited to 'lib')
diff --git a/lib/opentox-client/version.rb b/lib/opentox-client/version.rb
deleted file mode 100644
index d90a728..0000000
--- a/lib/opentox-client/version.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-module Opentox
- module Client
- VERSION = "0.0.1"
- end
-end
--
cgit v1.2.3
From 9cf20c9fa99bac82c8a4e455eb6c97ecb3f26776 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Mon, 12 Mar 2012 14:27:08 +0100
Subject: actor uri added
---
lib/error.rb | 9 +++++----
lib/task.rb | 7 +++----
2 files changed, 8 insertions(+), 8 deletions(-)
(limited to 'lib')
diff --git a/lib/error.rb b/lib/error.rb
index 7fc2461..e3329be 100644
--- a/lib/error.rb
+++ b/lib/error.rb
@@ -47,7 +47,6 @@ module OpenTox
# define global methods for raising errors, eg. bad_request_error
Object.send(:define_method, klass.underscore.to_sym) do |message|
defined?(@uri) ? uri = @uri : uri=nil
- # TODO: insert uri from sinatra
raise c, message, uri
end
end
@@ -68,14 +67,16 @@ module OpenTox
@http_code = http_code
#@report = report#.to_yaml
@report = {}
- @report[RDF::OT.actor] = error.uri
- @report[RDF::OT.message] = error.message
+ @report[RDF::OT.actor] = error.uri.to_s
+ @report[RDF::OT.message] = error.message.to_s
@report[RDF::OT.statusCode] = @http_code
@report[RDF::OT.errorCode] = error.class.to_s
@report[RDF::OT.errorDetails] = caller.collect{|line| line unless line =~ /#{File.dirname(__FILE__)}/}.compact.join("\n")
@report[RDF::OT.errorDetails] += "REST paramenters:\n#{error.request.args.inspect}" if defined? error.request
- @report[RDF::OT.message] += "\n" + error.response.body if defined? error.response
+ @report[RDF::OT.message] += "\n" + error.response.body.to_s if defined? error.response
# TODO fix Error cause
+ # should point to another errorReport, but errorReports do not have URIs
+ # create a separate service?
#report[RDF::OT.errorCause] = @report if defined?(@report)
end
diff --git a/lib/task.rb b/lib/task.rb
index 0562dc7..3f1b691 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -1,4 +1,3 @@
-require File.join(File.dirname(__FILE__),'error')
DEFAULT_TASK_MAX_DURATION = 36000
module OpenTox
@@ -9,7 +8,6 @@ module OpenTox
def self.create service_uri, params={}
- # TODO set/enforce request uri
# TODO: run observer in same process?
task = Task.new RestClientWrapper.post(service_uri,params).chomp
pid = fork do
@@ -19,7 +17,6 @@ module OpenTox
rescue
RestClientWrapper.put(File.join(task.uri,'Error'),{:errorReport => $!.report.to_yaml})
task.kill
- #raise $!
end
end
Process.detach(pid)
@@ -43,7 +40,7 @@ module OpenTox
def kill
Process.kill(9,@pid)
Process.kill(9,@observer_pid)
- rescue # no need to raise an exeption if processes are not running
+ rescue # no need to raise an exeption if processes are not running
end
def description
@@ -91,6 +88,8 @@ module OpenTox
RestClientWrapper.head(@uri).code == 200
end
+ # TODO: add queued?
+
def error?
code = RestClientWrapper.head(@uri).code
code >= 400 and code != 503
--
cgit v1.2.3
From 625c88673e90053f898423dfc96bda1d6c0fa8eb Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Tue, 13 Mar 2012 20:52:45 +0100
Subject: short backtrace for errorDetails
---
lib/error.rb | 12 +++++++++++-
lib/overwrite.rb | 10 ----------
lib/task.rb | 2 +-
3 files changed, 12 insertions(+), 12 deletions(-)
(limited to 'lib')
diff --git a/lib/error.rb b/lib/error.rb
index e3329be..cc87f47 100644
--- a/lib/error.rb
+++ b/lib/error.rb
@@ -71,7 +71,14 @@ module OpenTox
@report[RDF::OT.message] = error.message.to_s
@report[RDF::OT.statusCode] = @http_code
@report[RDF::OT.errorCode] = error.class.to_s
- @report[RDF::OT.errorDetails] = caller.collect{|line| line unless line =~ /#{File.dirname(__FILE__)}/}.compact.join("\n")
+
+ # cut backtrace
+ backtrace = caller.collect{|line| line unless line =~ /#{File.dirname(__FILE__)}/}.compact
+ cut_index = backtrace.find_index{|line| line.match /sinatra|minitest/}
+ cut_index ||= backtrace.size
+ cut_index -= 1
+ cut_index = backtrace.size-1 if cut_index < 0
+ @report[RDF::OT.errorDetails] = backtrace[0..cut_index].join("\n")
@report[RDF::OT.errorDetails] += "REST paramenters:\n#{error.request.args.inspect}" if defined? error.request
@report[RDF::OT.message] += "\n" + error.response.body.to_s if defined? error.response
# TODO fix Error cause
@@ -85,6 +92,9 @@ module OpenTox
send :define_method, "to_#{format}".to_sym do
rdf = RDF::Writer.for(format).buffer do |writer|
+ # TODO: not used for turtle
+ # http://rdf.rubyforge.org/RDF/Writer.html#
+ writer.prefix :ot, RDF::URI('http://www.opentox.org/api/1.2#')
subject = RDF::Node.new
@report.each do |predicate,object|
writer << [subject, predicate, object] if object
diff --git a/lib/overwrite.rb b/lib/overwrite.rb
index 7b6cb4f..97c35aa 100644
--- a/lib/overwrite.rb
+++ b/lib/overwrite.rb
@@ -78,13 +78,3 @@ module Kernel
end
end
-class Array
- def short_backtrace
- short = []
- each do |c|
- break if c =~ /sinatra\/base/
- short << c
- end
- short.join("\n")
- end
-end
diff --git a/lib/task.rb b/lib/task.rb
index 3f1b691..be02deb 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -15,7 +15,7 @@ module OpenTox
result_uri = yield
task.completed result_uri
rescue
- RestClientWrapper.put(File.join(task.uri,'Error'),{:errorReport => $!.report.to_yaml})
+ RestClientWrapper.put(File.join(task.uri,'Error'),{:errorReport => $!.report.to_yaml}) if $!.respond_to? :report
task.kill
end
end
--
cgit v1.2.3
From 87458637a9cdcee5066f2f3d087f8052fe89f064 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Wed, 14 Mar 2012 11:14:50 +0100
Subject: dataset metadata fixed
---
lib/opentox.rb | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
(limited to 'lib')
diff --git a/lib/opentox.rb b/lib/opentox.rb
index 342b04e..6ce9a12 100644
--- a/lib/opentox.rb
+++ b/lib/opentox.rb
@@ -31,8 +31,8 @@ module OpenTox
pull if @rdf.empty?
metadata = {}
@rdf.query([RDF::URI.new(@uri),nil,nil]).collect do |statement|
- metadata[statement.predicate] ||= []
- metadata[statement.predicate] << statement.object
+ metadata[statement.predicate.to_s] ||= []
+ metadata[statement.predicate.to_s] << statement.object.to_s
end
metadata
end
@@ -42,7 +42,8 @@ module OpenTox
# @return [Array] Values for supplied key
def [](key)
pull if @rdf.empty?
- @rdf.query([RDF::URI.new(@uri),key,nil]).collect{|statement| statement.object}
+ result = @rdf.query([RDF::URI.new(@uri),key,nil]).collect{|statement| statement.object.to_s}
+ result.size == 1 ? result.first : result
end
# Save object at service
--
cgit v1.2.3
From d657955ef09c69ce66e2eda3a03dbf4b87461915 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Wed, 14 Mar 2012 10:15:36 +0000
Subject: Fallback for OpenTox class if URI is ambiguous
---
lib/opentox-client.rb | 2 +-
lib/opentox.rb | 8 ++++++--
2 files changed, 7 insertions(+), 3 deletions(-)
(limited to 'lib')
diff --git a/lib/opentox-client.rb b/lib/opentox-client.rb
index 7d9329d..e68fd7f 100644
--- a/lib/opentox-client.rb
+++ b/lib/opentox-client.rb
@@ -14,7 +14,7 @@ RDF::OT1 = RDF::Vocabulary.new 'http://www.opentox.org/api/1.1#'
RDF::OTA = RDF::Vocabulary.new 'http://www.opentox.org/algorithmTypes.owl#'
#CLASSES = ["Compound", "Feature", "Dataset", "Algorithm", "Model", "Validation", "Task", "ErrorReport", "Investigation"]
-CLASSES = ["Compound", "Feature", "Dataset", "Algorithm", "Model", "Validation", "Task", "Investigation"]
+CLASSES = ["Generic", "Compound", "Feature", "Dataset", "Algorithm", "Model", "Validation", "Task", "Investigation"]
RDF_FORMATS = [:rdfxml,:ntriples,:turtle]
$default_rdf = "application/rdf+xml"
diff --git a/lib/opentox.rb b/lib/opentox.rb
index 342b04e..944eda5 100644
--- a/lib/opentox.rb
+++ b/lib/opentox.rb
@@ -125,8 +125,12 @@ module OpenTox
# guess class from uri, this is potentially unsafe, but polling metadata from large uri lists is way too slow (and not all service provide RDF.type in their metadata)
result = CLASSES.collect{|s| s if uri =~ /#{s.downcase}/}.compact
- internal_server_error "Cannot determine class from URI: '#{uri}.\nCandidate classes are #{result.inspect}" unless result.size == 1
- klass = result.first
+ if result.size == 1
+ klass = result.first
+ else
+ klass = OpenTox::Generic.new(uri)[RDF.type]
+ internal_server_error "Cannot determine class from URI '#{uri} (Candidate classes are #{result.inspect}) or matadata." unless klass
+ end
# initialize with/without subjectid
subjectid ? eval("#{self}.new(\"#{uri}\", #{subjectid})") : eval("#{self}.new(\"#{uri}\")")
end
--
cgit v1.2.3
From 1652bc3f3e635948fc3a73817f407adc6dee071a Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Wed, 14 Mar 2012 11:44:53 +0000
Subject: metadata methods fixed
---
lib/opentox.rb | 8 ++++----
lib/task.rb | 22 ++++------------------
2 files changed, 8 insertions(+), 22 deletions(-)
(limited to 'lib')
diff --git a/lib/opentox.rb b/lib/opentox.rb
index 0d88eaa..9493362 100644
--- a/lib/opentox.rb
+++ b/lib/opentox.rb
@@ -31,10 +31,10 @@ module OpenTox
pull if @rdf.empty?
metadata = {}
@rdf.query([RDF::URI.new(@uri),nil,nil]).collect do |statement|
- metadata[statement.predicate.to_s] ||= []
- metadata[statement.predicate.to_s] << statement.object.to_s
+ metadata[statement.predicate] ||= []
+ metadata[statement.predicate] << statement.object
end
- metadata
+ metadata.each{|k,v| metadata[k] = v.first if v.size == 1}
end
# Get metadata values
@@ -42,7 +42,7 @@ module OpenTox
# @return [Array] Values for supplied key
def [](key)
pull if @rdf.empty?
- result = @rdf.query([RDF::URI.new(@uri),key,nil]).collect{|statement| statement.object.to_s}
+ result = @rdf.query([RDF::URI.new(@uri),key,nil]).collect{|statement| statement.object}
result.size == 1 ? result.first : result
end
diff --git a/lib/task.rb b/lib/task.rb
index be02deb..9921c4c 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -97,24 +97,10 @@ module OpenTox
def method_missing(method,*args)
method = method.to_s
- begin
- case method
- when /=/
- res = RestClientWrapper.put(File.join(@uri,method.sub(/=/,'')),{})
- super unless res.code == 200
- else
- pull
- response = self.[](RDF::OT[method])
- response = self.[](RDF::OT1[method]) if response.empty? # API 1.1 compatibility
- internal_server_error "No #{method} metadata for #{@uri} " if response.empty?
- return response.uniq.first.to_s
- end
- rescue OpenTox::Error
- raise $!
- rescue
- $logger.error "Unknown #{self.class} method #{method}"
- super
- end
+ response = self.[](RDF::OT[method])
+ response = self.[](RDF::OT1[method]) if response.empty? # API 1.1 compatibility
+ internal_server_error "Unknown #{self.class} method #{method} for #{@uri}" if response.is_a? Array and response.empty?
+ return response.to_s
end
#TODO: subtasks
--
cgit v1.2.3
From e7f1ecb35d0522890a31b9ba44ebf10b05da80a8 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Thu, 15 Mar 2012 12:24:47 +0100
Subject: dynamic adjustment of task poll times
---
lib/task.rb | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
(limited to 'lib')
diff --git a/lib/task.rb b/lib/task.rb
index 9921c4c..2f79cf1 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -65,10 +65,14 @@ module OpenTox
# waits for a task, unless time exceeds or state is no longer running
# @param [optional,Numeric] dur seconds pausing before checking again for completion
- def wait(dur=0.3)
- due_to_time = Time.new + DEFAULT_TASK_MAX_DURATION
- while running?
+ # TODO: add waiting task
+ def wait
+ start_time = Time.new
+ due_to_time = start_time + DEFAULT_TASK_MAX_DURATION
+ dur = 0
+ while running?
sleep dur
+ dur = [[(Time.new - start_time)/20.0,0.3].max,300.0].min
time_out_error "max wait time exceeded ("+DEFAULT_TASK_MAX_DURATION.to_s+"sec), task: '"+@uri.to_s+"'" if (Time.new > due_to_time)
end
end
@@ -88,8 +92,6 @@ module OpenTox
RestClientWrapper.head(@uri).code == 200
end
- # TODO: add queued?
-
def error?
code = RestClientWrapper.head(@uri).code
code >= 400 and code != 503
--
cgit v1.2.3
From 585a0185af082bc3999375bfcd78677f4dc25059 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Thu, 15 Mar 2012 13:13:44 +0100
Subject: metadata reload fixed
---
lib/opentox.rb | 9 ++++++---
lib/task.rb | 12 ++++++------
2 files changed, 12 insertions(+), 9 deletions(-)
(limited to 'lib')
diff --git a/lib/opentox.rb b/lib/opentox.rb
index 9493362..4338302 100644
--- a/lib/opentox.rb
+++ b/lib/opentox.rb
@@ -27,8 +27,9 @@ module OpenTox
# Get object metadata
# @return [Hash] Metadata
+ # TODO: rename to_hash? or store in object variables
def metadata
- pull if @rdf.empty?
+ pull # force update
metadata = {}
@rdf.query([RDF::URI.new(@uri),nil,nil]).collect do |statement|
metadata[statement.predicate] ||= []
@@ -41,9 +42,11 @@ module OpenTox
# @param [RDF] Key from RDF Vocabularies
# @return [Array] Values for supplied key
def [](key)
- pull if @rdf.empty?
+ pull # force update
result = @rdf.query([RDF::URI.new(@uri),key,nil]).collect{|statement| statement.object}
- result.size == 1 ? result.first : result
+ return nil if result.empty?
+ return result.first.to_s if result.size == 1
+ return result.collect{|r| r.to_s}
end
# Save object at service
diff --git a/lib/task.rb b/lib/task.rb
index 2f79cf1..7452012 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -97,12 +97,12 @@ module OpenTox
code >= 400 and code != 503
end
- def method_missing(method,*args)
- method = method.to_s
- response = self.[](RDF::OT[method])
- response = self.[](RDF::OT1[method]) if response.empty? # API 1.1 compatibility
- internal_server_error "Unknown #{self.class} method #{method} for #{@uri}" if response.is_a? Array and response.empty?
- return response.to_s
+ [:hasStatus, :resultURI].each do |method|
+ define_method method do
+ response = self.[](RDF::OT[method])
+ response = self.[](RDF::OT1[method]) unless response # API 1.1 compatibility
+ response
+ end
end
#TODO: subtasks
--
cgit v1.2.3
From 2fd7dcb2d011e3a2029de56f48aca5722685ee80 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Thu, 15 Mar 2012 18:23:44 +0100
Subject: dataset methods implemented
---
lib/dataset.rb | 323 +++-----------------------------------------------
lib/opentox-client.rb | 3 +-
lib/opentox.rb | 36 ++++--
3 files changed, 42 insertions(+), 320 deletions(-)
(limited to 'lib')
diff --git a/lib/dataset.rb b/lib/dataset.rb
index 3de9d1f..8032533 100644
--- a/lib/dataset.rb
+++ b/lib/dataset.rb
@@ -1,318 +1,29 @@
module OpenTox
-
+
# Ruby wrapper for OpenTox Dataset Webservices (http://opentox.org/dev/apis/api-1.2/dataset).
- # TODO: fix API Doc
class Dataset
- #include OpenTox
-
- #attr_reader :features, :compounds, :data_entries, :metadata
-
- # Create dataset with optional URI. Does not load data into the dataset - you will need to execute one of the load_* methods to pull data from a service or to insert it from other representations.
- # @example Create an empty dataset
- # dataset = OpenTox::Dataset.new
- # @example Create an empty dataset with URI
- # dataset = OpenTox::Dataset.new("http:://webservices.in-silico/ch/dataset/1")
- # @param [optional, String] uri Dataset URI
- # @return [OpenTox::Dataset] Dataset object
- def initialize(uri=nil,subjectid=nil)
- super uri, subjectid
- @features = {}
- @compounds = []
- @data_entries = {}
- end
-
-=begin
- # Load YAML representation into the dataset
- # @param [String] yaml YAML representation of the dataset
- # @return [OpenTox::Dataset] Dataset object with YAML data
- def self.from_yaml service_uri, yaml, subjectid=nil
- Dataset.create(service_uri, subjectid).post yaml, :content_type => "application/x-yaml"
- end
-
- # Load RDF/XML representation from a file
- # @param [String] file File with RDF/XML representation of the dataset
- # @return [OpenTox::Dataset] Dataset object with RDF/XML data
- def self.from_rdfxml service_uri, rdfxml, subjectid=nil
- Dataset.create(service_uri, subjectid).post rdfxml, :content_type => "application/rdf+xml"
- end
-
- # Load CSV string (format specification: http://toxcreate.org/help)
- # - loads data_entries, compounds, features
- # - sets metadata (warnings) for parser errors
- # - you will have to set remaining metadata manually
- # @param [String] csv CSV representation of the dataset
- # @return [OpenTox::Dataset] Dataset object with CSV data
- def self.from_csv service_uri, csv, subjectid=nil
- Dataset.from_file(service_uri, csv, subjectid)
- end
-
- # Load Spreadsheet book (created with roo gem http://roo.rubyforge.org/, excel format specification: http://toxcreate.org/help)
- # - loads data_entries, compounds, features
- # - sets metadata (warnings) for parser errors
- # - you will have to set remaining metadata manually
- # @param [Excel] book Excel workbook object (created with roo gem)
- # @return [OpenTox::Dataset] Dataset object with Excel data
- def self.from_xls service_uri, xls, subjectid=nil
- Dataset.create(service_uri, subjectid).post xls, :content_type => "application/vnd.ms-excel"
- end
-
- def self.from_sdf service_uri, sdf, subjectid=nil
- Dataset.create(service_uri, subjectid).post sdf, :content_type => 'chemical/x-mdl-sdfile'
- end
-=end
-
- # Load all data (metadata, data_entries, compounds and features) from URI
- # TODO: move to opentox-server
- def data_entries reload=true
- if reload
- file = Tempfile.new("ot-rdfxml")
- file.puts get :accept => "application/rdf+xml"
- file.close
- to_delete = file.path
-
- data = {}
- feature_values = {}
- feature = {}
- feature_accept_values = {}
- other_statements = {}
- `rapper -i rdfxml -o ntriples #{file.path} 2>/dev/null`.each_line do |line|
- triple = line.chomp.split(' ',3)
- triple = triple[0..2].collect{|i| i.sub(/\s+.$/,'').gsub(/[<>"]/,'')}
- case triple[1]
- when /#{RDF::OT.values}|#{RDF::OT1.values}/i
- data[triple[0]] = {:compound => "", :values => []} unless data[triple[0]]
- data[triple[0]][:values] << triple[2]
- when /#{RDF::OT.value}|#{RDF::OT1.value}/i
- feature_values[triple[0]] = triple[2]
- when /#{RDF::OT.compound}|#{RDF::OT1.compound}/i
- data[triple[0]] = {:compound => "", :values => []} unless data[triple[0]]
- data[triple[0]][:compound] = triple[2]
- when /#{RDF::OT.feature}|#{RDF::OT1.feature}/i
- feature[triple[0]] = triple[2]
- when /#{RDF.type}/i
- if triple[2]=~/#{RDF::OT.Compound}|#{RDF::OT1.Compound}/i and !data[triple[0]]
- data[triple[0]] = {:compound => triple[0], :values => []}
- end
- when /#{RDF::OT.acceptValue}|#{RDF::OT1.acceptValue}/i # acceptValue in ambit datasets is only provided in dataset/ no in dataset//features
- feature_accept_values[triple[0]] = [] unless feature_accept_values[triple[0]]
- feature_accept_values[triple[0]] << triple[2]
- else
- end
- end
- File.delete(to_delete) if to_delete
- data.each do |id,entry|
- if entry[:values].size==0
- # no feature values add plain compounds
- @compounds << entry[:compound] unless @compounds.include? entry[:compound]
- else
- entry[:values].each do |value_id|
- if feature_values[value_id]
- split = feature_values[value_id].split(/\^\^/)
- case split[-1]
- when RDF::XSD.double, RDF::XSD.float
- value = split.first.to_f
- when RDF::XSD.boolean
- value = split.first=~/(?i)true/ ? true : false
- else
- value = split.first
- end
- end
- @compounds << entry[:compound] unless @compounds.include? entry[:compound]
- @features[feature[value_id][value_id]] = {} unless @features[feature[value_id]]
- @data_entries[entry[:compound].to_s] = {} unless @data_entries[entry[:compound].to_s]
- @data_entries[entry[:compound].to_s][feature[value_id]] = [] unless @data_entries[entry[:compound]][feature[value_id]]
- @data_entries[entry[:compound].to_s][feature[value_id]] << value if value!=nil
- end
- end
- end
- features subjectid
- #feature_accept_values.each do |feature, values|
- #self.features[feature][OT.acceptValue] = values
- #end
- self.metadata = metadata(subjectid)
- end
- @data_entries
- end
-
- # Load and return only compound URIs from the dataset service
- # @return [Array] Compound URIs in the dataset
- def compounds reload=true
- reload ? @compounds = Compound.all(File.join(@uri,"compounds")) : @compounds
- end
-
- # Load and return only features from the dataset service
- # @return [Hash] Features of the dataset
- def features reload=true
- reload ? @features = Feature.all(File.join(@uri,"features")) : @features
- end
-
-=begin
- # returns the accept_values of a feature, i.e. the classification domain / all possible feature values
- # @param [String] feature the URI of the feature
- # @return [Array] return array with strings, nil if value is not set (e.g. when feature is numeric)
- def accept_values(feature)
- load_features
- accept_values = features[feature][OT.acceptValue]
- accept_values.sort if accept_values
- accept_values
- end
-
- # Detect feature type(s) in the dataset
- # @return [String] `classification", "regression", "mixed" or unknown`
- def feature_type
- load_features
- feature_types = @features.collect{|f,metadata| metadata[RDF.type]}.flatten.uniq
- if feature_types.include?(OT.NominalFeature)
- "classification"
- elsif feature_types.include?(OT.NumericFeature)
- "regression"
- else
- "unknown"
- end
+ def data_entries
+ # TODO fix for api 1.2
+ data_entries = []
+ pull
+ @reload = false
+ metadata[RDF::OT1.dataEntry].collect{|data_entry|
+ data_entries << @rdf.to_hash[data_entry]
+ }
+ @reload = true
+ data_entries
end
-=end
- # Get Excel representation (alias for to_spreadsheet)
- # @return [Spreadsheet::Workbook] Workbook which can be written with the spreadsheet gem (data_entries only, metadata will will be discarded))
- def to_xls
- get :accept => "application/vnd.ms-excel"
+ def compounds
+ uri = File.join(@uri,"compounds")
+ RestClientWrapper.get(uri,{},{:accept => "text/uri-list", :subjectid => @subjectid}).split("\n").collect{|uri| OpenTox::Compound.new uri}
end
- # Get CSV string representation (data_entries only, metadata will be discarded)
- # @return [String] CSV representation
- def to_csv
- get :accept => "text/csv"
+ def features
+ uri = File.join(@uri,"features")
+ RestClientWrapper.get(uri,{},{:accept => "text/uri-list", :subjectid => @subjectid}).split("\n").collect{|uri| OpenTox::Feature.new uri}
end
- def to_sdf
- get :accept => 'chemical/x-mdl-sdfile'
- end
-
-
- # Get OWL-DL in ntriples format
- # @return [String] N-Triples representation
- def to_ntriples
- get :accept => "application/rdf+xml"
- end
-
- # Get OWL-DL in RDF/XML format
- # @return [String] RDF/XML representation
- def to_rdfxml
- get :accept => "application/rdf+xml"
- end
-
- # Get name (DC.title) of a feature
- # @param [String] feature Feature URI
- # @return [String] Feture title
- def feature_name(feature)
- features[feature][DC.title]
- end
-
- def title
- metadata[DC.title]
- end
-
- # Insert a statement (compound_uri,feature_uri,value)
- # @example Insert a statement (compound_uri,feature_uri,value)
- # dataset.add "http://webservices.in-silico.ch/compound/InChI=1S/C6Cl6/c7-1-2(8)4(10)6(12)5(11)3(1)9", "http://webservices.in-silico.ch/dataset/1/feature/hamster_carcinogenicity", true
- # @param [String] compound Compound URI
- # @param [String] feature Compound URI
- # @param [Boolean,Float] value Feature value
- def add (compound,feature,value)
- @compounds << compound unless @compounds.include? compound
- @features[feature] = {} unless @features[feature]
- @data_entries[compound] = {} unless @data_entries[compound]
- @data_entries[compound][feature] = [] unless @data_entries[compound][feature]
- @data_entries[compound][feature] << value if value!=nil
- end
-
- # Add a feature
- # @param [String] feature Feature URI
- # @param [Hash] metadata Hash with feature metadata
- def add_feature(feature,metadata={})
- @features[feature] = metadata
- end
-
- # Add/modify metadata for a feature
- # @param [String] feature Feature URI
- # @param [Hash] metadata Hash with feature metadata
- def add_feature_metadata(feature,metadata)
- metadata.each { |k,v| @features[feature][k] = v }
- end
-
- # Add a new compound
- # @param [String] compound Compound URI
- def add_compound (compound)
- @compounds << compound unless @compounds.include? compound
- end
-
- # Creates a new dataset, by splitting the current dataset, i.e. using only a subset of compounds and features
- # @param [Array] compounds List of compound URIs
- # @param [Array] features List of feature URIs
- # @param [Hash] metadata Hash containing the metadata for the new dataset
- # @param [String] subjectid
- # @return [OpenTox::Dataset] newly created dataset, already saved
- def split( compounds, features, metadata)
- LOGGER.debug "split dataset using "+compounds.size.to_s+"/"+@compounds.size.to_s+" compounds"
- raise "no new compounds selected" unless compounds and compounds.size>0
- dataset = OpenTox::Dataset.create(CONFIG[:services]["opentox-dataset"],@subjectid)
- if features.size==0
- compounds.each{ |c| dataset.add_compound(c) }
- else
- compounds.each do |c|
- features.each do |f|
- if @data_entries[c]==nil or @data_entries[c][f]==nil
- dataset.add(c,f,nil)
- else
- @data_entries[c][f].each do |v|
- dataset.add(c,f,v)
- end
- end
- end
- end
- end
- # set feature metadata in new dataset accordingly (including accept values)
- features.each do |f|
- self.features[f].each do |k,v|
- dataset.features[f][k] = v
- end
- end
- dataset.add_metadata(metadata)
- dataset.save
- dataset
- end
-
- # Save dataset at the dataset service
- # - creates a new dataset if uri is not set
- # - overwrites dataset if uri exists
- # @return [String] Dataset URI
- def save
- @compounds.uniq!
- # create dataset if uri is empty
- self.uri = RestClientWrapper.post(CONFIG[:services]["opentox-dataset"],{:subjectid => @subjectid}).to_s.chomp unless @uri
- if (CONFIG[:yaml_hosts].include?(URI.parse(@uri).host))
- RestClientWrapper.post(@uri,self.to_yaml,{:content_type => "application/x-yaml", :subjectid => @subjectid})
- else
- s = Serializer::Owl.new
- s.add_dataset(self)
- RestClientWrapper.post(@uri, s.to_rdfxml,{:content_type => "application/rdf+xml" , :subjectid => @subjectid})
- end
- @uri
- end
-
- private
- # Copy a dataset (rewrites URI)
- def copy(dataset)
- @metadata = dataset.metadata
- @data_entries = dataset.data_entries
- @compounds = dataset.compounds
- @features = dataset.features
- if @uri
- self.uri = @uri
- else
- @uri = dataset.metadata[XSD.anyURI]
- end
- end
end
end
diff --git a/lib/opentox-client.rb b/lib/opentox-client.rb
index e68fd7f..8616995 100644
--- a/lib/opentox-client.rb
+++ b/lib/opentox-client.rb
@@ -5,6 +5,7 @@ require 'rdf/raptor'
require "rest-client"
require 'uri'
require 'yaml'
+require 'json'
require 'logger'
# define constants and global variables
@@ -29,4 +30,4 @@ require File.join(File.dirname(__FILE__),"otlogger.rb") # avoid require conflict
require File.join(File.dirname(__FILE__),"opentox.rb")
require File.join(File.dirname(__FILE__),"task.rb")
require File.join(File.dirname(__FILE__),"compound.rb")
-#require File.join(File.dirname(__FILE__),"dataset.rb")
+require File.join(File.dirname(__FILE__),"dataset.rb")
diff --git a/lib/opentox.rb b/lib/opentox.rb
index 4338302..4b43547 100644
--- a/lib/opentox.rb
+++ b/lib/opentox.rb
@@ -4,7 +4,7 @@ $logger.level = Logger::DEBUG
module OpenTox
- attr_accessor :uri, :subjectid, :rdf, :response
+ attr_accessor :uri, :subjectid, :rdf, :response, :reload
# Ruby interface
@@ -15,38 +15,34 @@ module OpenTox
def initialize uri=nil, subjectid=nil
@uri = uri.to_s.chomp
@subjectid = subjectid
+ @reload = true
@rdf = RDF::Graph.new
end
# Load metadata from service
def pull
- kind_of?(OpenTox::Dataset) ? uri = File.join(@uri,"metadata") : uri = @uri
# TODO generic method for all formats
- parse_rdfxml RestClientWrapper.get(uri,{},{:accept => $default_rdf, :subjectid => @subjectid})
+ parse_rdfxml RestClientWrapper.get(@uri,{},{:accept => $default_rdf, :subjectid => @subjectid})
end
# Get object metadata
# @return [Hash] Metadata
- # TODO: rename to_hash? or store in object variables
def metadata
- pull # force update
- metadata = {}
- @rdf.query([RDF::URI.new(@uri),nil,nil]).collect do |statement|
- metadata[statement.predicate] ||= []
- metadata[statement.predicate] << statement.object
- end
- metadata.each{|k,v| metadata[k] = v.first if v.size == 1}
+ pull if @reload # force update
+ @rdf.to_hash[RDF::URI.new(@uri)]
end
# Get metadata values
# @param [RDF] Key from RDF Vocabularies
# @return [Array] Values for supplied key
def [](key)
- pull # force update
+ pull if @reload # force update
result = @rdf.query([RDF::URI.new(@uri),key,nil]).collect{|statement| statement.object}
- return nil if result.empty?
+ # TODO: convert to OpenTox objects??
+ return nil if result and result.empty?
return result.first.to_s if result.size == 1
return result.collect{|r| r.to_s}
+ result
end
# Save object at service
@@ -74,6 +70,20 @@ module OpenTox
end
end
+# def to_hash
+# hash = {}
+# metadata.each{|k,v| v.is_a?(Array) ? hash[k.to_s] = v.collect{|i| i.to_s} : hash[k.to_s] = v.to_s}
+# hash
+# end
+
+ def to_yaml
+ @rdf.to_hash.to_yaml
+ end
+
+ def to_json
+ to_hash.to_json
+ end
+
# REST API
def get headers={}
headers[:subjectid] ||= @subjectid
--
cgit v1.2.3
From fc990e6dae8af7cfdf7d12b4e1d9ccd3b557418a Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Mon, 19 Mar 2012 18:57:31 +0100
Subject: libraptor1-dev dependency added
---
lib/error.rb | 5 ++---
lib/opentox-client.rb | 2 ++
lib/overwrite.rb | 4 +---
lib/task.rb | 1 +
4 files changed, 6 insertions(+), 6 deletions(-)
(limited to 'lib')
diff --git a/lib/error.rb b/lib/error.rb
index cc87f47..e12f140 100644
--- a/lib/error.rb
+++ b/lib/error.rb
@@ -45,8 +45,7 @@ module OpenTox
OpenTox.const_set klass,c
# define global methods for raising errors, eg. bad_request_error
- Object.send(:define_method, klass.underscore.to_sym) do |message|
- defined?(@uri) ? uri = @uri : uri=nil
+ Object.send(:define_method, klass.underscore.to_sym) do |message,uri=nil|
raise c, message, uri
end
end
@@ -65,7 +64,6 @@ module OpenTox
class ErrorReport
def initialize http_code, error
@http_code = http_code
- #@report = report#.to_yaml
@report = {}
@report[RDF::OT.actor] = error.uri.to_s
@report[RDF::OT.message] = error.message.to_s
@@ -95,6 +93,7 @@ module OpenTox
# TODO: not used for turtle
# http://rdf.rubyforge.org/RDF/Writer.html#
writer.prefix :ot, RDF::URI('http://www.opentox.org/api/1.2#')
+ writer.prefix :ot1_1, RDF::URI('http://www.opentox.org/api/1.1#')
subject = RDF::Node.new
@report.each do |predicate,object|
writer << [subject, predicate, object] if object
diff --git a/lib/opentox-client.rb b/lib/opentox-client.rb
index 8616995..dec3512 100644
--- a/lib/opentox-client.rb
+++ b/lib/opentox-client.rb
@@ -26,6 +26,8 @@ FALSE_REGEXP = /^(false|inactive|0|0.0|low tox|deactivating|non-carcinogen|non-m
require File.join(File.dirname(__FILE__),"overwrite.rb")
require File.join(File.dirname(__FILE__),"error.rb")
require File.join(File.dirname(__FILE__),"rest-client-wrapper.rb")
+require File.join(File.dirname(__FILE__),"authorization.rb")
+require File.join(File.dirname(__FILE__),"policy.rb")
require File.join(File.dirname(__FILE__),"otlogger.rb") # avoid require conflicts with logger
require File.join(File.dirname(__FILE__),"opentox.rb")
require File.join(File.dirname(__FILE__),"task.rb")
diff --git a/lib/overwrite.rb b/lib/overwrite.rb
index 97c35aa..e3f72ad 100644
--- a/lib/overwrite.rb
+++ b/lib/overwrite.rb
@@ -64,10 +64,8 @@ module Kernel
stdout = stdout_stream.read
stderr = stderr_stream.read
end
- raise stderr.strip if !status.success?
+ internal_server_error stdout + stderr if !status.success?
return stdout
- rescue Exception
- internal_server_error $!
end
alias_method :system!, :system
diff --git a/lib/task.rb b/lib/task.rb
index 7452012..f19a918 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -15,6 +15,7 @@ module OpenTox
result_uri = yield
task.completed result_uri
rescue
+ puts $!.report.to_yaml
RestClientWrapper.put(File.join(task.uri,'Error'),{:errorReport => $!.report.to_yaml}) if $!.respond_to? :report
task.kill
end
--
cgit v1.2.3
From 7883965d1ddca56520d0219c447821d056ed22d1 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Wed, 21 Mar 2012 11:48:04 +0100
Subject: authorization added, tests not yet working
---
lib/authorization.rb | 77 ++++++++++++++++++++++++++--------------------------
1 file changed, 39 insertions(+), 38 deletions(-)
(limited to 'lib')
diff --git a/lib/authorization.rb b/lib/authorization.rb
index 1938814..e57eda3 100644
--- a/lib/authorization.rb
+++ b/lib/authorization.rb
@@ -1,21 +1,22 @@
module OpenTox
+ AA ||= "https://opensso.in-silico.ch" #if not set in .opentox/conf/[environment].yaml
#Module for Authorization and Authentication
#@example Authentication
# require "opentox-client"
- # OpenTox::Authorization::AA_SERVER = "https://opensso.in-silico.ch" #if not set in .opentox/conf/[environment].yaml
+ # OpenTox::Authorization::AA = "https://opensso.in-silico.ch" #if not set in .opentox/conf/[environment].yaml
# token = OpenTox::Authorization.authenticate("benutzer", "passwort")
#@see http://www.opentox.org/dev/apis/api-1.2/AA OpenTox A&A API 1.2 specification
module Authorization
- #Helper Class AA to create and send default policies out of xml templates
+ #Helper Class to create and send default policies out of xml templates
#@example Creating a default policy to a URI
# aa=OpenTox::Authorization::AA.new(tok)
# xml=aa.get_xml('http://uri....')
# OpenTox::Authorization.create_policy(xml,tok)
- class AA
+ class Helper
attr_accessor :user, :subjectid, :policy
#Generates AA object - requires subjectid
@@ -41,8 +42,8 @@ module OpenTox
xml = get_xml(uri)
ret = false
ret = Authorization.create_policy(xml, @subjectid)
- @@logger.debug "Policy send with subjectid: #{@subjectid}"
- @@logger.warn "Not created Policy is: #{xml}" if !ret
+ $logger.debug "Policy send with subjectid: #{@subjectid}"
+ $logger.warn "Not created Policy is: #{xml}" if !ret
ret
end
@@ -51,16 +52,16 @@ module OpenTox
#Returns the open-sso server set in the config file .opentox/config/[environment].yaml
# @return [String, nil] the openSSO server URI or nil
def self.server
- return AA_SERVER
+ return AA
end
#Authentication against OpenSSO. Returns token. Requires Username and Password.
# @param [String, String]Username,Password
# @return [String, nil] gives subjectid or nil
def self.authenticate(user, pw)
- return nil if !AA_SERVER
+ return nil if !AA
begin
- resource = RestClient::Resource.new("#{AA_SERVER}/auth/authenticate")
+ resource = RestClient::Resource.new("#{AA}/auth/authenticate")
out = resource.post(:username=>user, :password => pw).sub("token.id=","").sub("\n","")
return out
rescue
@@ -73,7 +74,7 @@ module OpenTox
# @return [Boolean] true if logout is OK
def self.logout(subjectid)
begin
- resource = RestClient::Resource.new("#{AA_SERVER}/auth/logout")
+ resource = RestClient::Resource.new("#{AA}/auth/logout")
resource.post(:subjectid => subjectid)
return true
rescue
@@ -85,9 +86,9 @@ module OpenTox
# @param [String,String,String]uri,action,subjectid
# @return [Boolean, nil] returns true, false or nil (if authorization-request fails).
def self.authorize(uri, action, subjectid)
- return true if !AA_SERVER
+ return true if !AA
begin
- resource = RestClient::Resource.new("#{AA_SERVER}/auth/authorize")
+ resource = RestClient::Resource.new("#{AA}/auth/authorize")
return true if resource.post(:uri => uri, :action => action, :subjectid => subjectid) == "boolean=true\n"
rescue
return nil
@@ -98,9 +99,9 @@ module OpenTox
# @param [String]subjectid subjectid from openSSO session
# @return [Boolean] subjectid is valid or not.
def self.is_token_valid(subjectid)
- return true if !AA_SERVER
+ return true if !AA
begin
- resource = RestClient::Resource.new("#{AA_SERVER}/auth/isTokenValid")
+ resource = RestClient::Resource.new("#{AA}/auth/isTokenValid")
return true if resource.post(:tokenid => subjectid) == "boolean=true\n"
rescue
return false
@@ -112,7 +113,7 @@ module OpenTox
# @return [Array, nil] returns an Array of policy names or nil if request fails
def self.list_policies(subjectid)
begin
- resource = RestClient::Resource.new("#{AA_SERVER}/pol")
+ resource = RestClient::Resource.new("#{AA}/pol")
out = resource.get(:subjectid => subjectid)
return out.split("\n")
rescue RestClient::InternalServerError => e
@@ -127,7 +128,7 @@ module OpenTox
# @return [String] XML of the policy
def self.list_policy(policy, subjectid)
begin
- resource = RestClient::Resource.new("#{AA_SERVER}/pol")
+ resource = RestClient::Resource.new("#{AA}/pol")
return resource.get(:subjectid => subjectid,:id => policy)
rescue
return nil
@@ -160,7 +161,7 @@ module OpenTox
# return [String, nil]owner,nil returns owner of the URI
def self.get_uri_owner(uri, subjectid)
begin
- resource = RestClient::Resource.new("#{AA_SERVER}/pol")
+ resource = RestClient::Resource.new("#{AA}/pol")
return resource.get(:uri => uri, :subjectid => subjectid).sub("\n","")
rescue
return nil
@@ -181,7 +182,7 @@ module OpenTox
# return [Array, nil] returns an Array of policy names or nil if request fails
def self.list_uri_policies(uri, subjectid)
begin
- resource = RestClient::Resource.new("#{AA_SERVER}/pol")
+ resource = RestClient::Resource.new("#{AA}/pol")
out = resource.get(:uri => uri, :polnames => true, :subjectid => subjectid)
policies = []; notfirstline = false
out.split("\n").each do |line|
@@ -199,8 +200,8 @@ module OpenTox
# return [Boolean] returns true if policy is created
def self.create_policy(policy, subjectid)
begin
- resource = RestClient::Resource.new("#{AA_SERVER}/Pol/opensso-pol")
- @@logger.debug "OpenTox::Authorization.create_policy policy: #{policy[168,43]} with token:" + subjectid.to_s + " length: " + subjectid.length.to_s
+ resource = RestClient::Resource.new("#{AA}/Pol/opensso-pol")
+ $logger.debug "OpenTox::Authorization.create_policy policy: #{policy[168,43]} with token:" + subjectid.to_s + " length: " + subjectid.length.to_s
return true if resource.post(policy, :subjectid => subjectid, :content_type => "application/xml")
rescue
return false
@@ -212,8 +213,8 @@ module OpenTox
# @return [Boolean,nil]
def self.delete_policy(policy, subjectid)
begin
- resource = RestClient::Resource.new("#{AA_SERVER}/pol")
- @@logger.debug "OpenTox::Authorization.delete_policy policy: #{policy} with token: #{subjectid}"
+ resource = RestClient::Resource.new("#{AA}/pol")
+ $logger.debug "OpenTox::Authorization.delete_policy policy: #{policy} with token: #{subjectid}"
return true if resource.delete(:subjectid => subjectid, :id => policy)
rescue
return nil
@@ -225,7 +226,7 @@ module OpenTox
# @return [Array]
def self.list_groups(subjectid)
begin
- resource = RestClient::Resource.new("#{AA_SERVER}/opensso/identity/search")
+ resource = RestClient::Resource.new("#{AA}/opensso/identity/search")
grps = resource.post(:admin => subjectid, :attributes_names => "objecttype", :attributes_values_objecttype => "group")
grps = grps.split("\n").collect{|x| x.sub("string=","")}
grps.delete_if{|g|g=="MemberManagement"||g=="Webmasters"}
@@ -240,7 +241,7 @@ module OpenTox
# @return [Array] gives array of LDAP groups of a user
def self.list_user_groups(user, subjectid)
begin
- resource = RestClient::Resource.new("#{AA_SERVER}/opensso/identity/read")
+ resource = RestClient::Resource.new("#{AA}/opensso/identity/read")
out = resource.post(:name => user, :admin => subjectid, :attributes_names => "group")
grps = []
out.split("\n").each do |line|
@@ -257,7 +258,7 @@ module OpenTox
# @return [String]user
def self.get_user(subjectid)
begin
- resource = RestClient::Resource.new("#{AA_SERVER}/opensso/identity/attributes")
+ resource = RestClient::Resource.new("#{AA}/opensso/identity/attributes")
out = resource.post(:subjectid => subjectid, :attributes_names => "uid")
user = ""; check = false
out.split("\n").each do |line|
@@ -273,13 +274,13 @@ module OpenTox
end
end
- #Send default policy with Authorization::AA class
+ #Send default policy with Authorization::Helper class
# @param [String, String]URI,subjectid
def self.send_policy(uri, subjectid)
- return true if !AA_SERVER
- aa = Authorization::AA.new(subjectid)
+ return true if !AA
+ aa = Authorization::Helper.new(subjectid)
ret = aa.send(uri)
- @@logger.debug "OpenTox::Authorization send policy for URI: #{uri} | subjectid: #{subjectid} - policy created: #{ret}"
+ $logger.debug "OpenTox::Authorization send policy for URI: #{uri} | subjectid: #{subjectid} - policy created: #{ret}"
ret
end
@@ -291,7 +292,7 @@ module OpenTox
if policies
policies.each do |policy|
ret = delete_policy(policy, subjectid)
- @@logger.debug "OpenTox::Authorization delete policy: #{policy} - with result: #{ret}"
+ $logger.debug "OpenTox::Authorization delete policy: #{policy} - with result: #{ret}"
end
end
return true
@@ -304,11 +305,11 @@ module OpenTox
def self.check_policy(uri, subjectid)
return true unless uri and subjectid
token_valid = OpenTox::Authorization.is_token_valid(subjectid)
- @@logger.debug "OpenTox::Authorization.check_policy with uri: #{uri}, subjectid: #{subjectid} is valid: #{token_valid}"
+ $logger.debug "OpenTox::Authorization.check_policy with uri: #{uri}, subjectid: #{subjectid} is valid: #{token_valid}"
# check if subjectid is valid
unless token_valid
# abort if invalid
- @@logger.error "OpenTox::Authorization.check_policy, subjectid NOT valid: #{subjectid}"
+ $logger.error "OpenTox::Authorization.check_policy, subjectid NOT valid: #{subjectid}"
return false
end
@@ -320,7 +321,7 @@ module OpenTox
if authorize(uri, "POST", subjectid)
true
else
- @@logger.error "OpenTox::Authorization.check_policy, already exists, but no POST-authorization with subjectid: #{subjectid}"
+ $logger.error "OpenTox::Authorization.check_policy, already exists, but no POST-authorization with subjectid: #{subjectid}"
false
end
end
@@ -338,25 +339,25 @@ module OpenTox
# @return [Boolean] true if access granted, else otherwise
def self.authorized?(uri, request_method, subjectid)
if CONFIG[:authorization][:free_request].include?(request_method)
- #@@logger.debug "authorized? >>true<< (request is free), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}"
+ #$logger.debug "authorized? >>true<< (request is free), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}"
true
elsif OpenTox::Authorization.free_uri?(uri, request_method)
- #@@logger.debug "authorized? >>true<< (uris is free_uri), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}"
+ #$logger.debug "authorized? >>true<< (uris is free_uri), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}"
true
elsif CONFIG[:authorization][:authenticate_request].include?(request_method)
ret = OpenTox::Authorization.is_token_valid(subjectid)
- @@logger.debug "authorized? >>#{ret}<< (token is in/valid), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}" unless ret
+ $logger.debug "authorized? >>#{ret}<< (token is in/valid), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}" unless ret
ret
elsif OpenTox::Authorization.authorize_exception?(uri, request_method)
ret = OpenTox::Authorization.is_token_valid(subjectid)
- @@logger.debug "authorized? >>#{ret}<< (uris is authorize exception, token is in/valid), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}" unless ret
+ $logger.debug "authorized? >>#{ret}<< (uris is authorize exception, token is in/valid), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}" unless ret
ret
elsif CONFIG[:authorization][:authorize_request].include?(request_method)
ret = OpenTox::Authorization.authorize(uri, request_method, subjectid)
- @@logger.debug "authorized? >>#{ret}<< (uri (not) authorized), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}" unless ret
+ $logger.debug "authorized? >>#{ret}<< (uri (not) authorized), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}" unless ret
ret
else
- @@logger.error "invalid request/uri method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}"
+ $logger.error "invalid request/uri method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}"
false
end
end
--
cgit v1.2.3
From 556b33d064d5c639f520bfebc043432531a0eaa6 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Wed, 21 Mar 2012 12:14:18 +0100
Subject: backtick errors fixed
---
lib/overwrite.rb | 2 ++
1 file changed, 2 insertions(+)
(limited to 'lib')
diff --git a/lib/overwrite.rb b/lib/overwrite.rb
index e3f72ad..10a3a82 100644
--- a/lib/overwrite.rb
+++ b/lib/overwrite.rb
@@ -66,6 +66,8 @@ module Kernel
end
internal_server_error stdout + stderr if !status.success?
return stdout
+ rescue
+ internal_server_error $!.message
end
alias_method :system!, :system
--
cgit v1.2.3
From 9b51fd3f058d96263e32665b3dd83e38ab30563d Mon Sep 17 00:00:00 2001
From: rautenberg
Date: Wed, 21 Mar 2012 16:26:32 +0100
Subject: prevent ssl uris from URI.accessible? check
---
lib/rest-client-wrapper.rb | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
(limited to 'lib')
diff --git a/lib/rest-client-wrapper.rb b/lib/rest-client-wrapper.rb
index c9e6bbb..13ccf09 100644
--- a/lib/rest-client-wrapper.rb
+++ b/lib/rest-client-wrapper.rb
@@ -17,11 +17,11 @@ module OpenTox
# check input
bad_request_error "Invalid URI: '#{uri}'" unless URI.valid? uri
- not_found_error "URI '#{uri}' not found." unless URI.accessible? uri
+ not_found_error "URI '#{uri}' not found." unless URI.accessible? uri unless URI.ssl?(uri)
bad_request_error "Headers are not a hash: #{headers.inspect}" unless headers==nil or headers.is_a?(Hash)
# make sure that no header parameters are set in the payload
[:accept,:content_type,:subjectid].each do |header|
- bad_request_error "#{header} should be submitted in the headers" if payload and payload.is_a?(Hash) and payload[header]
+ bad_request_error "#{header} should be submitted in the headers" if payload and payload.is_a?(Hash) and payload[header] unless URI(uri).host == URI(AA).host
end
# create request
--
cgit v1.2.3
From e2c7ee88523091bfa824a5837c48cb2f4391e393 Mon Sep 17 00:00:00 2001
From: rautenberg
Date: Wed, 21 Mar 2012 16:27:10 +0100
Subject: check if https uri
---
lib/overwrite.rb | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/overwrite.rb b/lib/overwrite.rb
index e3f72ad..6a1f151 100644
--- a/lib/overwrite.rb
+++ b/lib/overwrite.rb
@@ -21,11 +21,15 @@ module URI
def self.dataset? uri, subjectid=nil
uri =~ /dataset/ and URI.accessible? uri, subjectid=nil
end
-
+
def self.model? uri, subjectid=nil
uri =~ /model/ and URI.accessible? uri, subjectid=nil
end
+ def self.ssl? uri, subjectid=nil
+ URI.parse(uri).instance_of? URI::HTTPS
+ end
+
def self.accessible? uri, subjectid=nil
if URI.task? uri or URI.compound? uri
# just try to get a response, valid tasks may return codes > 400
--
cgit v1.2.3
From 882bec0b303048d59b313e65f493eba1db6d82f6 Mon Sep 17 00:00:00 2001
From: rautenberg
Date: Wed, 21 Mar 2012 16:28:29 +0100
Subject: change RestClient methods to RestClientWrapper, remove list_groups
method
---
lib/authorization.rb | 69 +++++++++++++++-------------------------------------
1 file changed, 20 insertions(+), 49 deletions(-)
(limited to 'lib')
diff --git a/lib/authorization.rb b/lib/authorization.rb
index e57eda3..4d54c41 100644
--- a/lib/authorization.rb
+++ b/lib/authorization.rb
@@ -1,10 +1,10 @@
module OpenTox
- AA ||= "https://opensso.in-silico.ch" #if not set in .opentox/conf/[environment].yaml
+ AA ||= "https://opensso.in-silico.ch" #if not set in .opentox/conf/[environment].yaml
#Module for Authorization and Authentication
#@example Authentication
# require "opentox-client"
- # OpenTox::Authorization::AA = "https://opensso.in-silico.ch" #if not set in .opentox/conf/[environment].yaml
+ # OpenTox::Authorization::AA = "https://opensso.in-silico.ch" #if not set in .opentox/conf/[environment].yaml
# token = OpenTox::Authorization.authenticate("benutzer", "passwort")
#@see http://www.opentox.org/dev/apis/api-1.2/AA OpenTox A&A API 1.2 specification
@@ -61,8 +61,7 @@ module OpenTox
def self.authenticate(user, pw)
return nil if !AA
begin
- resource = RestClient::Resource.new("#{AA}/auth/authenticate")
- out = resource.post(:username=>user, :password => pw).sub("token.id=","").sub("\n","")
+ out = RestClientWrapper.post("#{AA}/auth/authenticate",{:username=>user, :password => pw}).sub("token.id=","").sub("\n","")
return out
rescue
return nil
@@ -74,12 +73,12 @@ module OpenTox
# @return [Boolean] true if logout is OK
def self.logout(subjectid)
begin
- resource = RestClient::Resource.new("#{AA}/auth/logout")
- resource.post(:subjectid => subjectid)
- return true
+ out = RestClientWrapper.post("#{AA}/auth/logout",:subjectid => subjectid)
+ return true unless is_token_valid(subjectid)
rescue
return false
end
+ return false
end
#Authorization against OpenSSO for a URI with request-method (action) [GET/POST/PUT/DELETE]
@@ -88,8 +87,7 @@ module OpenTox
def self.authorize(uri, action, subjectid)
return true if !AA
begin
- resource = RestClient::Resource.new("#{AA}/auth/authorize")
- return true if resource.post(:uri => uri, :action => action, :subjectid => subjectid) == "boolean=true\n"
+ return true if RestClientWrapper.post("#{AA}/auth/authorize",{:uri => uri, :action => action, :subjectid => subjectid})== "boolean=true\n"
rescue
return nil
end
@@ -101,11 +99,9 @@ module OpenTox
def self.is_token_valid(subjectid)
return true if !AA
begin
- resource = RestClient::Resource.new("#{AA}/auth/isTokenValid")
- return true if resource.post(:tokenid => subjectid) == "boolean=true\n"
- rescue
- return false
+ return true if RestClientWrapper.post("#{AA}/auth/isTokenValid",:tokenid => subjectid) == "boolean=true\n"
end
+ return false
end
#Returns array with all policies of the token owner
@@ -113,11 +109,8 @@ module OpenTox
# @return [Array, nil] returns an Array of policy names or nil if request fails
def self.list_policies(subjectid)
begin
- resource = RestClient::Resource.new("#{AA}/pol")
- out = resource.get(:subjectid => subjectid)
+ out = RestClientWrapper.get("#{AA}/pol",nil,:subjectid => subjectid)
return out.split("\n")
- rescue RestClient::InternalServerError => e
- raise e.response
rescue
return nil
end
@@ -128,8 +121,7 @@ module OpenTox
# @return [String] XML of the policy
def self.list_policy(policy, subjectid)
begin
- resource = RestClient::Resource.new("#{AA}/pol")
- return resource.get(:subjectid => subjectid,:id => policy)
+ return RestClientWrapper.get("#{AA}/pol",nil,{:subjectid => subjectid,:id => policy})
rescue
return nil
end
@@ -161,8 +153,7 @@ module OpenTox
# return [String, nil]owner,nil returns owner of the URI
def self.get_uri_owner(uri, subjectid)
begin
- resource = RestClient::Resource.new("#{AA}/pol")
- return resource.get(:uri => uri, :subjectid => subjectid).sub("\n","")
+ return RestClientWrapper.get("#{AA}/pol",nil,{:subjectid => subjectid, :uri => uri}).sub("\n","")
rescue
return nil
end
@@ -182,8 +173,7 @@ module OpenTox
# return [Array, nil] returns an Array of policy names or nil if request fails
def self.list_uri_policies(uri, subjectid)
begin
- resource = RestClient::Resource.new("#{AA}/pol")
- out = resource.get(:uri => uri, :polnames => true, :subjectid => subjectid)
+ out = RestClientWrapper.get("#{AA}/pol",nil,{:uri => uri, :polnames => true, :subjectid => subjectid})
policies = []; notfirstline = false
out.split("\n").each do |line|
policies << line if notfirstline
@@ -200,9 +190,8 @@ module OpenTox
# return [Boolean] returns true if policy is created
def self.create_policy(policy, subjectid)
begin
- resource = RestClient::Resource.new("#{AA}/Pol/opensso-pol")
- $logger.debug "OpenTox::Authorization.create_policy policy: #{policy[168,43]} with token:" + subjectid.to_s + " length: " + subjectid.length.to_s
- return true if resource.post(policy, :subjectid => subjectid, :content_type => "application/xml")
+ $logger.debug "OpenTox::Authorization.create_policy policy: #{policy[168,43]} with token:" + subjectid.to_s + " length: " + subjectid.length.to_s
+ return true if RestClientWrapper.post("#{AA}/Pol/opensso-pol",policy, {:subjectid => subjectid, :content_type => "application/xml"})
rescue
return false
end
@@ -213,36 +202,19 @@ module OpenTox
# @return [Boolean,nil]
def self.delete_policy(policy, subjectid)
begin
- resource = RestClient::Resource.new("#{AA}/pol")
$logger.debug "OpenTox::Authorization.delete_policy policy: #{policy} with token: #{subjectid}"
- return true if resource.delete(:subjectid => subjectid, :id => policy)
+ return true if RestClientWrapper.delete("#{AA}/pol",nil, {:subjectid => subjectid, :id => policy})
rescue
return nil
end
end
- #Returns array of all possible LDAP-Groups
- # @param [String]subjectid
- # @return [Array]
- def self.list_groups(subjectid)
- begin
- resource = RestClient::Resource.new("#{AA}/opensso/identity/search")
- grps = resource.post(:admin => subjectid, :attributes_names => "objecttype", :attributes_values_objecttype => "group")
- grps = grps.split("\n").collect{|x| x.sub("string=","")}
- grps.delete_if{|g|g=="MemberManagement"||g=="Webmasters"}
- grps
- rescue
- []
- end
- end
-
#Returns array of the LDAP-Groups of an user
# @param [String]subjectid
# @return [Array] gives array of LDAP groups of a user
def self.list_user_groups(user, subjectid)
begin
- resource = RestClient::Resource.new("#{AA}/opensso/identity/read")
- out = resource.post(:name => user, :admin => subjectid, :attributes_names => "group")
+ out = RestClientWrapper.post("#{AA}/opensso/identity/read", {:name => user, :admin => subjectid, :attributes_names => "group"})
grps = []
out.split("\n").each do |line|
grps << line.sub("identitydetails.group=","") if line.include?("identitydetails.group=")
@@ -258,8 +230,7 @@ module OpenTox
# @return [String]user
def self.get_user(subjectid)
begin
- resource = RestClient::Resource.new("#{AA}/opensso/identity/attributes")
- out = resource.post(:subjectid => subjectid, :attributes_names => "uid")
+ out = RestClientWrapper.post("#{AA}/opensso/identity/attributes", {:subjectid => subjectid, :attributes_names => "uid"})
user = ""; check = false
out.split("\n").each do |line|
if check
@@ -301,7 +272,7 @@ module OpenTox
# Checks (if subjectid is valid) if a policy exist and create default policy if not
# @param [String] uri
# @param [String] subjectid
- # @return [Boolean] true if policy checked/created successfully (or no uri/subjectid given), false else
+ # @return [Boolean] true if policy checked/created successfully (or no uri/subjectid given), false else
def self.check_policy(uri, subjectid)
return true unless uri and subjectid
token_valid = OpenTox::Authorization.is_token_valid(subjectid)
@@ -321,7 +292,7 @@ module OpenTox
if authorize(uri, "POST", subjectid)
true
else
- $logger.error "OpenTox::Authorization.check_policy, already exists, but no POST-authorization with subjectid: #{subjectid}"
+ $logger.error "OpenTox::Authorization.check_policy, already exists, but no POST-authorization with subjectid: #{subjectid}"
false
end
end
--
cgit v1.2.3
From b9249a71bc4fd6323f2ec879018f497027a4545a Mon Sep 17 00:00:00 2001
From: rautenberg
Date: Thu, 22 Mar 2012 12:21:31 +0100
Subject: retry opensso if connection fails (1x) log error if fails twice
---
lib/authorization.rb | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
(limited to 'lib')
diff --git a/lib/authorization.rb b/lib/authorization.rb
index 4d54c41..470ecd8 100644
--- a/lib/authorization.rb
+++ b/lib/authorization.rb
@@ -5,7 +5,7 @@ module OpenTox
#@example Authentication
# require "opentox-client"
# OpenTox::Authorization::AA = "https://opensso.in-silico.ch" #if not set in .opentox/conf/[environment].yaml
- # token = OpenTox::Authorization.authenticate("benutzer", "passwort")
+ # token = OpenTox::Authorization.authenticate("username", "password")
#@see http://www.opentox.org/dev/apis/api-1.2/AA OpenTox A&A API 1.2 specification
module Authorization
@@ -42,11 +42,12 @@ module OpenTox
xml = get_xml(uri)
ret = false
ret = Authorization.create_policy(xml, @subjectid)
+ $logger.warn "Create policy on openSSO failed for URI: #{uri} subjectid: #{@subjectid}. Will try again." if !ret
+ ret = Authorization.create_policy(xml, @subjectid) if !ret
$logger.debug "Policy send with subjectid: #{@subjectid}"
- $logger.warn "Not created Policy is: #{xml}" if !ret
+ $logger.error "Not created Policy is: #{xml}" if !ret
ret
end
-
end
#Returns the open-sso server set in the config file .opentox/config/[environment].yaml
--
cgit v1.2.3
From 3bf0e33c86cd4cd460412c01eed9a37afacad4d5 Mon Sep 17 00:00:00 2001
From: rautenberg
Date: Thu, 22 Mar 2012 12:23:09 +0100
Subject: add policy-lib mods from feature/policy and add policy tests
---
lib/policy.rb | 331 ++++++++++++++++++++++++++++++++++++----------------------
1 file changed, 204 insertions(+), 127 deletions(-)
(limited to 'lib')
diff --git a/lib/policy.rb b/lib/policy.rb
index 8591d52..56a90b7 100644
--- a/lib/policy.rb
+++ b/lib/policy.rb
@@ -1,28 +1,29 @@
module OpenTox
require "rexml/document"
- #Module for policy-processing
+ #Module for policy-processing
# @see also http://www.opentox.org/dev/apis/api-1.2/AA for opentox API specs
# Class Policies corresponds to container of an xml-policy-fle
- class Policies
-
- attr_accessor :name, :policies
-
+ class Policies
+
+ #Hash for policy objects see {Policy Policy}
+ attr_accessor :policies, :name
+
def initialize()
@policies = {}
end
-
+
#create new policy instance with name
# @param [String]name of the policy
def new_policy(name)
@policies[name] = Policy.new(name)
end
-
+
#drop a specific policy in a policies instance
# @param [String]name of the policy
# @return [Boolean]
def drop_policy(name)
- return true if @policies.delete(name)
+ return true if @policies.delete(name)
end
#drop all policies in a policies instance
@@ -32,58 +33,63 @@ module OpenTox
end
return true
end
-
+
# @return [Array] set of arrays affected by policies
def uris
- @policies.collect{ |k,v| v.uris }.flatten.uniq
+ @policies.collect{ |k,v| v.uri }.flatten.uniq
end
- #drop all policies in a policies instance
+ #list all policy names in a policies instance
+ # @return [Array]
def names
out = []
@policies.each do |name, policy|
- out << name
+ out << name
end
return out
end
- #loads a default policy template in policies instance
- def load_default_policy(user, uri, group="member")
+ # Loads a default policy template in a policies instance
+ # @param [String]user username in LDAP string of user policy: 'uid=,ou=people,dc=opentox,dc=org'
+ # @param [String]uri URI
+ # @param [String]group groupname in LDAP string of group policy: 'cn=,ou=groups,dc=opentox,dc=org'
+ def load_default_policy(user, uri, group="member")
template = case user
when "guest", "anonymous" then "default_guest_policy"
- else "default_policy"
+ else "default_policy"
end
xml = File.read(File.join(File.dirname(__FILE__), "templates/#{template}.xml"))
self.load_xml(xml)
datestring = Time.now.strftime("%Y-%m-%d-%H-%M-%S-x") + rand(1000).to_s
-
+
@policies["policy_user"].name = "policy_user_#{user}_#{datestring}"
- @policies["policy_user"].rules["rule_user"].uri = uri
- @policies["policy_user"].rules["rule_user"].name = "rule_user_#{user}_#{datestring}"
- @policies["policy_user"].subjects["subject_user"].name = "subject_user_#{user}_#{datestring}"
- @policies["policy_user"].subjects["subject_user"].value = "uid=#{user},ou=people,dc=opentox,dc=org"
+ @policies["policy_user"].rule.uri = uri
+ @policies["policy_user"].rule.name = "rule_user_#{user}_#{datestring}"
+ @policies["policy_user"].subject.name = "subject_user_#{user}_#{datestring}"
+ @policies["policy_user"].subject.value = "uid=#{user},ou=people,dc=opentox,dc=org"
@policies["policy_user"].subject_group = "subjects_user_#{user}_#{datestring}"
-
- @policies["policy_group"].name = "policy_group_#{group}_#{datestring}"
- @policies["policy_group"].rules["rule_group"].uri = uri
- @policies["policy_group"].rules["rule_group"].name = "rule_group_#{group}_#{datestring}"
- @policies["policy_group"].subjects["subject_group"].name = "subject_group_#{group}_#{datestring}"
- @policies["policy_group"].subjects["subject_group"].value = "cn=#{group},ou=groups,dc=opentox,dc=org"
- @policies["policy_group"].subject_group = "subjects_#{group}_#{datestring}"
+
+ @policies["policy_group"].name = "policy_group_#{group}_#{datestring}"
+ @policies["policy_group"].rule.uri = uri
+ @policies["policy_group"].rule.name = "rule_group_#{group}_#{datestring}"
+ @policies["policy_group"].subject.name = "subject_group_#{group}_#{datestring}"
+ @policies["policy_group"].subject.value = "cn=#{group},ou=groups,dc=opentox,dc=org"
+ @policies["policy_group"].subject_group = "subjects_#{group}_#{datestring}"
return true
- end
+ end
- #loads a xml template
+ #loads a xml template
def load_xml(xml)
rexml = REXML::Document.new(xml)
rexml.elements.each("Policies/Policy") do |pol| #Policies
policy_name = pol.attributes["name"]
new_policy(policy_name)
- #@policies[policy_name] = Policy.new(policy_name)
+ #@policies[policy_name] = Policy.new(policy_name)
rexml.elements.each("Policies/Policy[@name='#{policy_name}']/Rule") do |r| #Rules
- rule_name = r.attributes["name"]
+ rule_name = r.attributes["name"]
uri = rexml.elements["Policies/Policy[@name='#{policy_name}']/Rule[@name='#{rule_name}']/ResourceName"].attributes["name"]
- @policies[policy_name].rules[rule_name] = @policies[policy_name].new_rule(rule_name, uri)
+ @policies[policy_name].rule.name = rule_name
+ @policies[policy_name].uri = uri
rexml.elements.each("Policies/Policy[@name='#{policy_name}']/Rule[@name='#{rule_name}']/AttributeValuePair") do |attribute_pairs|
action=nil; value=nil;
attribute_pairs.each_element do |elem|
@@ -93,163 +99,234 @@ module OpenTox
if action and value
case action
when "GET"
- @policies[policy_name].rules[rule_name].get = value
+ @policies[policy_name].rule.get = value
when "POST"
- @policies[policy_name].rules[rule_name].post = value
+ @policies[policy_name].rule.post = value
when "PUT"
- @policies[policy_name].rules[rule_name].put = value
- when "DELETE"
- @policies[policy_name].rules[rule_name].delete = value
+ @policies[policy_name].rule.put = value
+ when "DELETE"
+ @policies[policy_name].rule.delete = value
end
end
- end
+ end
end
rexml.elements.each("Policies/Policy[@name='#{policy_name}']/Subjects") do |subjects| #Subjects
- @policies[policy_name].subject_group = subjects.attributes["name"]
+ @policies[policy_name].subject_group = subjects.attributes["name"]
rexml.elements.each("Policies/Policy[@name='#{policy_name}']/Subjects[@name='#{@policies[policy_name].subject_group}']/Subject") do |s| #Subject
subject_name = s.attributes["name"]
subject_type = s.attributes["type"]
subject_value = rexml.elements["Policies/Policy[@name='#{policy_name}']/Subjects[@name='#{@policies[policy_name].subject_group}']/Subject[@name='#{subject_name}']/AttributeValuePair/Value"].text
- @policies[policy_name].new_subject(subject_name, subject_type, subject_value) if subject_name and subject_type and subject_value
+ if subject_name and subject_type and subject_value
+ @policies[policy_name].subject.name = subject_name
+ @policies[policy_name].type = subject_type
+ @policies[policy_name].value = subject_value
+ end
end
- end
- end
+ end
+ end
end
-
+
#generates xml from policies instance
def to_xml
doc = REXML::Document.new()
doc << REXML::DocType.new("Policies", "PUBLIC \"-//Sun Java System Access Manager7.1 2006Q3\n Admin CLI DTD//EN\" \"jar://com/sun/identity/policy/policyAdmin.dtd\"")
doc.add_element(REXML::Element.new("Policies"))
-
+
@policies.each do |name, pol|
policy = REXML::Element.new("Policy")
policy.attributes["name"] = pol.name
policy.attributes["referralPolicy"] = false
policy.attributes["active"] = true
- @policies[name].rules.each do |r,rl|
- rule = @policies[name].rules[r]
- out_rule = REXML::Element.new("Rule")
- out_rule.attributes["name"] = rule.name
- servicename = REXML::Element.new("ServiceName")
- servicename.attributes["name"]="iPlanetAMWebAgentService"
- out_rule.add_element(servicename)
- rescourcename = REXML::Element.new("ResourceName")
- rescourcename.attributes["name"] = rule.uri
- out_rule.add_element(rescourcename)
-
- ["get","post","delete","put"].each do |act|
- if rule.method(act).call
- attribute = REXML::Element.new("Attribute")
- attribute.attributes["name"] = act.upcase
- attributevaluepair = REXML::Element.new("AttributeValuePair")
- attributevaluepair.add_element(attribute)
- attributevalue = REXML::Element.new("Value")
- attributevaluepair.add_element(attributevalue)
- attributevalue.add_text REXML::Text.new(rule.method(act).call)
- out_rule.add_element(attributevaluepair)
-
- end
+ rule = @policies[name].rule
+ out_rule = REXML::Element.new("Rule")
+ out_rule.attributes["name"] = rule.name
+ servicename = REXML::Element.new("ServiceName")
+ servicename.attributes["name"]="iPlanetAMWebAgentService"
+ out_rule.add_element(servicename)
+ rescourcename = REXML::Element.new("ResourceName")
+ rescourcename.attributes["name"] = rule.uri
+ out_rule.add_element(rescourcename)
+
+ ["get","post","delete","put"].each do |act|
+ if rule.method(act).call
+ attribute = REXML::Element.new("Attribute")
+ attribute.attributes["name"] = act.upcase
+ attributevaluepair = REXML::Element.new("AttributeValuePair")
+ attributevaluepair.add_element(attribute)
+ attributevalue = REXML::Element.new("Value")
+ attributevaluepair.add_element(attributevalue)
+ attributevalue.add_text REXML::Text.new(rule.method(act).call)
+ out_rule.add_element(attributevaluepair)
end
- policy.add_element(out_rule)
- end
+ end
+ policy.add_element(out_rule)
subjects = REXML::Element.new("Subjects")
subjects.attributes["name"] = pol.subject_group
subjects.attributes["description"] = ""
- @policies[name].subjects.each do |subj, subjs|
- subject = REXML::Element.new("Subject")
- subject.attributes["name"] = pol.subjects[subj].name
- subject.attributes["type"] = pol.subjects[subj].type
- subject.attributes["includeType"] = "inclusive"
- attributevaluepair = REXML::Element.new("AttributeValuePair")
- attribute = REXML::Element.new("Attribute")
- attribute.attributes["name"] = "Values"
- attributevaluepair.add_element(attribute)
- attributevalue = REXML::Element.new("Value")
- attributevalue.add_text REXML::Text.new(pol.subjects[subj].value)
- attributevaluepair.add_element(attributevalue)
- subject.add_element(attributevaluepair)
- subjects.add_element(subject)
- end
+ subj = @policies[name].subject.name
+ subject = REXML::Element.new("Subject")
+ subject.attributes["name"] = pol.subject.name
+ subject.attributes["type"] = pol.subject.type
+ subject.attributes["includeType"] = "inclusive"
+ attributevaluepair = REXML::Element.new("AttributeValuePair")
+ attribute = REXML::Element.new("Attribute")
+ attribute.attributes["name"] = "Values"
+ attributevaluepair.add_element(attribute)
+ attributevalue = REXML::Element.new("Value")
+ attributevalue.add_text REXML::Text.new(pol.subject.value)
+ attributevaluepair.add_element(attributevalue)
+ subject.add_element(attributevaluepair)
+ subjects.add_element(subject)
policy.add_element(subjects)
doc.root.add_element(policy)
- end
+ end
out = ""
doc.write(out, 2)
return out
- end
-
+ end
+
end
-
- #single policy in a policies instance
- class Policy
-
- attr_accessor :name, :rules, :subject_group, :subjects
-
+
+ #single policy in a {Policies Policies} instance
+ class Policy
+
+ attr_accessor :name, :rule, :subject_group, :subject, :value, :type, :uri, :group, :user
+
def initialize(name)
@name = name
- @rules = {}
- @subject_group = ""
- @subjects = {}
+ @rule = Rule.new("#{name}_rule", nil)
+ @subject_group = "#{name}_subjects"
+ @subject = Subject.new("#{name}_subject", nil, nil)
end
-
- #create a new rule instance for the policy
- def new_rule(name, uri)
- @rules[name] = Rule.new(name, uri)
+
+ # Subject type LDAPUsers or LDAPGroups
+ def type
+ @subject.type
end
-
- #create a new subject instance for the policy
- def new_subject(name, type, value)
- @subjects[name] = Subject.new(name, type, value)
+
+ # Set subject type
+ # @param [String],type
+ def type=(type)
+ @subject.type = type
end
-
- # @return [Array] set of uris affected by policy
- def uris
- @rules.collect{ |k,v| v.uri }.uniq
+
+ # returns LDAP Distinguished Name (DN) e.g. uid=username,ou=people,dc=opentox,dc=org or cn=membergroup,ou=groups,dc=opentox,dc=org
+ def value
+ @subject.value
+ end
+
+ # sets LDAP Distinguished Name (DN) for policy e.g.
+ # @param [String],LDAPString
+ def value=(value)
+ @subject.value = value
+ end
+
+ # uri affected by policy
+ # @return uri affected by policy
+ def uri
+ @rule.uri
+ end
+
+ # sets uri affected by policy
+ # @param [String] set URI
+ def uri=(uri)
+ @rule.uri = uri
+ end
+
+ # Get the groupname from within the LDAP Distinguished Name (DN)
+ def group
+ return false if !value && type != "LDAPGroups"
+ value.split(",").each{|part| return part.gsub("cn=","") if part.match("cn=")}
+ end
+
+ # Get the username from within the LDAP Distinguished Name (DN)
+ def user
+ return false if !value && type != "LDAPUsers"
+ value.split(",").each{|part| return part.gsub("uid=","") if part.match("uid=")}
+ end
+
+ # helper method sets value and type to opentox LDAP Distinguished Name (DN) of a user
+ def set_ot_user(username)
+ self.value = "uid=#{username},ou=people,dc=opentox,dc=org"
+ self.type = "LDAPUsers"
+ true
+ end
+
+ def set_ot_group(groupname)
+ self.value = "cn=#{groupname},ou=groups,dc=opentox,dc=org"
+ self.type = "LDAPGroups"
+ true
end
-
+
#rule inside a policy
class Rule
-
- attr_accessor :name, :uri, :get, :post, :put, :delete
-
+
+ attr_accessor :name, :uri, :get, :post, :put, :delete, :read, :readwrite
+
def initialize(name, uri)
@name = name
@uri = uri
end
-
- def rename(new, old)
- self[new] = self.delete(old)
- self[new].name = new
- end
-
+
+ #Set Rule attribute for request-method GET
+ # @param [String]value (allow,deny,nil)
def get=(value)
@get = check_value(value, @get)
end
-
+
+ #Set Rule attribute for request-method POST
+ # @param [String]value (allow,deny,nil)
def post=(value)
@post = check_value(value, @post)
end
-
+
+ #Set Rule attribute for request-method DELETE
+ # @param [String]value (allow,deny,nil)
def delete=(value)
@delete = check_value(value, @delete)
end
-
+
+ #Set Rule attribute for request-method PUT
+ # @param [String]value (allow,deny,nil)
def put=(value)
@put = check_value(value, @put)
end
-
+
+ def read
+ return true if @get == "allow" && (@put == "deny" || !@put) && (@post == "deny" || !@post)
+ end
+
+ def readwrite
+ return true if @get == "allow" && @put == "allow" && @post == "allow"
+ end
+
+ def read=(value)
+ if value
+ @get = "allow"; @put = nil; @post = nil
+ else
+ @get = nil; @put = nil; @post = nil
+ end
+ end
+
+ def readwrite=(value)
+ if value
+ @get = "allow"; @put = "allow"; @post = "allow"
+ else
+ @get = nil; @put = nil; @post = nil
+ end
+ end
+
private
- #checks if value is allow or deny. returns old value if not valid.
+ #checks if value is allow, deny or nil. returns old value if not valid.
def check_value(new_value, old_value)
- return (new_value=="allow" || new_value=="deny" || new_value==nil) ? new_value : old_value
+ return (new_value=="allow" || new_value=="deny" || new_value==nil) ? new_value : old_value
end
end
-
+
class Subject
- attr_accessor :name, :type, :value
+ attr_accessor :name, :type, :value
def initialize(name, type, value)
@name = name
@@ -258,4 +335,4 @@ module OpenTox
end
end
end
-end
\ No newline at end of file
+end
--
cgit v1.2.3
From 792de68f0b3e10379fc69a9565747d978fb6f4be Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Thu, 22 Mar 2012 12:55:18 +0100
Subject: improved error reporting for failed system calls
---
lib/overwrite.rb | 8 +-------
lib/task.rb | 11 +++++++----
2 files changed, 8 insertions(+), 11 deletions(-)
(limited to 'lib')
diff --git a/lib/overwrite.rb b/lib/overwrite.rb
index d99e5a2..4ba6811 100644
--- a/lib/overwrite.rb
+++ b/lib/overwrite.rb
@@ -68,17 +68,11 @@ module Kernel
stdout = stdout_stream.read
stderr = stderr_stream.read
end
- internal_server_error stdout + stderr if !status.success?
+ internal_server_error "`" + cmd + "` failed.\n" + stdout + stderr if !status.success?
return stdout
rescue
internal_server_error $!.message
end
- alias_method :system!, :system
-
- def system cmd
- `#{cmd}`
- return true
- end
end
diff --git a/lib/task.rb b/lib/task.rb
index f19a918..6923e28 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -8,14 +8,12 @@ module OpenTox
def self.create service_uri, params={}
- # TODO: run observer in same process?
task = Task.new RestClientWrapper.post(service_uri,params).chomp
pid = fork do
begin
result_uri = yield
task.completed result_uri
rescue
- puts $!.report.to_yaml
RestClientWrapper.put(File.join(task.uri,'Error'),{:errorReport => $!.report.to_yaml}) if $!.respond_to? :report
task.kill
end
@@ -80,7 +78,7 @@ module OpenTox
end
- # get only header for ststus requests
+ # get only header for status requests
def running?
RestClientWrapper.head(@uri).code == 202
end
@@ -98,6 +96,11 @@ module OpenTox
code >= 400 and code != 503
end
+ def errorReport
+ # TODO: fix rdf output at task service
+ not_implemented_error "RDF output of errorReports has to be fixed at task service"
+ end
+
[:hasStatus, :resultURI].each do |method|
define_method method do
response = self.[](RDF::OT[method])
@@ -106,6 +109,6 @@ module OpenTox
end
end
- #TODO: subtasks
+ #TODO: subtasks (only for progress)
end
--
cgit v1.2.3
From 0071cbd5f91cd3456a6e46b27155e8e408b384c1 Mon Sep 17 00:00:00 2001
From: rautenberg
Date: Fri, 23 Mar 2012 17:22:35 +0100
Subject: fix subjectid quoting in eval
---
lib/opentox.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/opentox.rb b/lib/opentox.rb
index 4b43547..2232063 100644
--- a/lib/opentox.rb
+++ b/lib/opentox.rb
@@ -146,7 +146,7 @@ module OpenTox
internal_server_error "Cannot determine class from URI '#{uri} (Candidate classes are #{result.inspect}) or matadata." unless klass
end
# initialize with/without subjectid
- subjectid ? eval("#{self}.new(\"#{uri}\", #{subjectid})") : eval("#{self}.new(\"#{uri}\")")
+ subjectid ? eval("#{self}.new(\"#{uri}\", \"#{subjectid}\")") : eval("#{self}.new(\"#{uri}\")")
end
end
--
cgit v1.2.3
From 3cbfaf2c2be98c0d79d48063427785f08b032e15 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Wed, 28 Mar 2012 10:10:08 +0000
Subject: result uri check in task temporarily removed
---
lib/task.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/task.rb b/lib/task.rb
index 6923e28..bcf806e 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -58,7 +58,7 @@ module OpenTox
end
def completed(uri)
- not_found_error "Result URI \"#{uri}\" does not exist." unless URI.accessible? uri
+ #not_found_error "Result URI \"#{uri}\" does not exist." unless URI.accessible? uri
RestClientWrapper.put(File.join(@uri,'Completed'),{:resultURI => uri})
end
--
cgit v1.2.3
From a8fa38376624cdc5212e63e74b308ba1af32ae53 Mon Sep 17 00:00:00 2001
From: rautenberg
Date: Wed, 28 Mar 2012 12:54:05 +0200
Subject: aa to new config
---
lib/authorization.rb | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
(limited to 'lib')
diff --git a/lib/authorization.rb b/lib/authorization.rb
index 470ecd8..33fa0a4 100644
--- a/lib/authorization.rb
+++ b/lib/authorization.rb
@@ -1,6 +1,6 @@
module OpenTox
-
- AA ||= "https://opensso.in-silico.ch" #if not set in .opentox/conf/[environment].yaml
+ AA = $aa[:uri] if defined? $aa
+ AA ||= "https://opensso.in-silico.ch" #if not set in .opentox/conf/[application]/[test].rb
#Module for Authorization and Authentication
#@example Authentication
# require "opentox-client"
@@ -310,13 +310,13 @@ module OpenTox
# @param [String] subjectid
# @return [Boolean] true if access granted, else otherwise
def self.authorized?(uri, request_method, subjectid)
- if CONFIG[:authorization][:free_request].include?(request_method)
+ if $aa[:free_request].include?(request_method)
#$logger.debug "authorized? >>true<< (request is free), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}"
true
elsif OpenTox::Authorization.free_uri?(uri, request_method)
#$logger.debug "authorized? >>true<< (uris is free_uri), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}"
true
- elsif CONFIG[:authorization][:authenticate_request].include?(request_method)
+ elsif $aa[:authenticate_request].include?(request_method)
ret = OpenTox::Authorization.is_token_valid(subjectid)
$logger.debug "authorized? >>#{ret}<< (token is in/valid), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}" unless ret
ret
@@ -324,7 +324,7 @@ module OpenTox
ret = OpenTox::Authorization.is_token_valid(subjectid)
$logger.debug "authorized? >>#{ret}<< (uris is authorize exception, token is in/valid), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}" unless ret
ret
- elsif CONFIG[:authorization][:authorize_request].include?(request_method)
+ elsif $aa[:authorize_request].include?(request_method)
ret = OpenTox::Authorization.authorize(uri, request_method, subjectid)
$logger.debug "authorized? >>#{ret}<< (uri (not) authorized), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}" unless ret
ret
@@ -336,9 +336,9 @@ module OpenTox
private
def self.free_uri?(uri, request_method)
- if CONFIG[:authorization][:free_uris]
- CONFIG[:authorization][:free_uris].each do |request_methods,uris|
- if request_methods and uris and request_methods.include?(request_method.to_sym)
+ if $aa[:free_uris]
+ $aa[:free_uris].each do |request_methods,uris|
+ if request_methods and uris and request_methods.include?(request_method.to_s)
uris.each do |u|
return true if u.match uri
end
@@ -349,8 +349,8 @@ module OpenTox
end
def self.authorize_exception?(uri, request_method)
- if CONFIG[:authorization][:authorize_exceptions]
- CONFIG[:authorization][:authorize_exceptions].each do |request_methods,uris|
+ if $aa[:authorize_exceptions]
+ $aa[:authorize_exceptions].each do |request_methods,uris|
if request_methods and uris and request_methods.include?(request_method.to_sym)
uris.each do |u|
return true if u.match uri
--
cgit v1.2.3
From 0d457e40c005ba4209ec7e3093aa06d73d65a442 Mon Sep 17 00:00:00 2001
From: rautenberg
Date: Wed, 28 Mar 2012 18:26:19 +0200
Subject: change for new aa variables
---
lib/overwrite.rb | 4 ++--
lib/rest-client-wrapper.rb | 5 +++--
2 files changed, 5 insertions(+), 4 deletions(-)
(limited to 'lib')
diff --git a/lib/overwrite.rb b/lib/overwrite.rb
index 4ba6811..d98769e 100644
--- a/lib/overwrite.rb
+++ b/lib/overwrite.rb
@@ -30,13 +30,13 @@ module URI
URI.parse(uri).instance_of? URI::HTTPS
end
- def self.accessible? uri, subjectid=nil
+ def self.accessible?(uri, subjectid=nil)
if URI.task? uri or URI.compound? uri
# just try to get a response, valid tasks may return codes > 400
Net::HTTP.get_response(URI.parse(uri))
true
else
- Net::HTTP.get_response(URI.parse(uri)).code.to_i < 400
+ Net::HTTP.get_response(URI.parse(uri + (subjectid ? "?subjectid=#{CGI.escape subjectid}" : ""))).code.to_i < 400
end
rescue
false
diff --git a/lib/rest-client-wrapper.rb b/lib/rest-client-wrapper.rb
index 13ccf09..30292de 100644
--- a/lib/rest-client-wrapper.rb
+++ b/lib/rest-client-wrapper.rb
@@ -16,12 +16,13 @@ module OpenTox
define_singleton_method method do |uri,payload={},headers={}|
# check input
+ @subjectid = headers[:subjectid] ? headers[:subjectid] : nil
bad_request_error "Invalid URI: '#{uri}'" unless URI.valid? uri
- not_found_error "URI '#{uri}' not found." unless URI.accessible? uri unless URI.ssl?(uri)
+ not_found_error "URI '#{uri}' not found." unless URI.accessible?(uri, @subjectid) unless URI.ssl?(uri)
bad_request_error "Headers are not a hash: #{headers.inspect}" unless headers==nil or headers.is_a?(Hash)
# make sure that no header parameters are set in the payload
[:accept,:content_type,:subjectid].each do |header|
- bad_request_error "#{header} should be submitted in the headers" if payload and payload.is_a?(Hash) and payload[header] unless URI(uri).host == URI(AA).host
+ bad_request_error "#{header} should be submitted in the headers" if payload and payload.is_a?(Hash) and payload[header] unless URI(uri).host == URI($aa[:uri]).host
end
# create request
--
cgit v1.2.3
From ef6b74aa8167c1cd2685e8c7ab97f6905d5a03b9 Mon Sep 17 00:00:00 2001
From: rautenberg
Date: Thu, 29 Mar 2012 13:24:27 +0200
Subject: let subjectid in header if aa is defined and request go to opensso
---
lib/rest-client-wrapper.rb | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
(limited to 'lib')
diff --git a/lib/rest-client-wrapper.rb b/lib/rest-client-wrapper.rb
index 30292de..a5adc80 100644
--- a/lib/rest-client-wrapper.rb
+++ b/lib/rest-client-wrapper.rb
@@ -16,13 +16,16 @@ module OpenTox
define_singleton_method method do |uri,payload={},headers={}|
# check input
- @subjectid = headers[:subjectid] ? headers[:subjectid] : nil
+ @subjectid = headers[:subjectid] ? headers[:subjectid] : nil
bad_request_error "Invalid URI: '#{uri}'" unless URI.valid? uri
not_found_error "URI '#{uri}' not found." unless URI.accessible?(uri, @subjectid) unless URI.ssl?(uri)
bad_request_error "Headers are not a hash: #{headers.inspect}" unless headers==nil or headers.is_a?(Hash)
# make sure that no header parameters are set in the payload
[:accept,:content_type,:subjectid].each do |header|
- bad_request_error "#{header} should be submitted in the headers" if payload and payload.is_a?(Hash) and payload[header] unless URI(uri).host == URI($aa[:uri]).host
+ if defined? $aa || URI(uri).host == URI($aa[:uri]).host
+ else
+ bad_request_error "#{header} should be submitted in the headers" if payload and payload.is_a?(Hash) and payload[header]
+ end
end
# create request
--
cgit v1.2.3
From 97f9367b05a9a665022adc5c3f0a988acb1c4fa3 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Thu, 29 Mar 2012 14:50:03 +0200
Subject: RestClientWrapper follows redirects
---
lib/error.rb | 11 ++++++-----
lib/opentox.rb | 6 ------
lib/rest-client-wrapper.rb | 13 ++++++++-----
3 files changed, 14 insertions(+), 16 deletions(-)
(limited to 'lib')
diff --git a/lib/error.rb b/lib/error.rb
index e12f140..579f42b 100644
--- a/lib/error.rb
+++ b/lib/error.rb
@@ -52,11 +52,12 @@ module OpenTox
# Errors received from RestClientWrapper calls
class RestCallError < Error
- attr_accessor :request, :response
- def initialize request, response, message
+ attr_accessor :request#, :response
+ def initialize message, request, uri
+ #def initialize request, response, message
@request = request
- @response = response
- super 502, message, request.url
+ #@response = response
+ super 502, message, uri
end
end
@@ -78,7 +79,7 @@ module OpenTox
cut_index = backtrace.size-1 if cut_index < 0
@report[RDF::OT.errorDetails] = backtrace[0..cut_index].join("\n")
@report[RDF::OT.errorDetails] += "REST paramenters:\n#{error.request.args.inspect}" if defined? error.request
- @report[RDF::OT.message] += "\n" + error.response.body.to_s if defined? error.response
+ #@report[RDF::OT.message] += "\n" + error.response.body.to_s if defined? error.response
# TODO fix Error cause
# should point to another errorReport, but errorReports do not have URIs
# create a separate service?
diff --git a/lib/opentox.rb b/lib/opentox.rb
index 2232063..187eb08 100644
--- a/lib/opentox.rb
+++ b/lib/opentox.rb
@@ -70,12 +70,6 @@ module OpenTox
end
end
-# def to_hash
-# hash = {}
-# metadata.each{|k,v| v.is_a?(Array) ? hash[k.to_s] = v.collect{|i| i.to_s} : hash[k.to_s] = v.to_s}
-# hash
-# end
-
def to_yaml
@rdf.to_hash.to_yaml
end
diff --git a/lib/rest-client-wrapper.rb b/lib/rest-client-wrapper.rb
index 30292de..aa5d9c4 100644
--- a/lib/rest-client-wrapper.rb
+++ b/lib/rest-client-wrapper.rb
@@ -34,13 +34,16 @@ module OpenTox
headers.each{ |k,v| headers.delete(k) if v==nil } if headers #remove keys with empty values, as this can cause problems
args[:headers] = headers
- # perform request
@request = RestClient::Request.new(args)
- # do not throw RestClient exceptions in order to create a @response object (needed for error reports) in every case
- @response = @request.execute { |response, request, result| return response }
# ignore error codes from Task services (may return error codes >= 400 according to API, which causes exceptions in RestClient and RDF::Reader)
- raise OpenTox::RestCallError.new @request, @response, "Response code is #{@response.code}." unless @response.code < 400 or URI.task? uri
- @response
+ @response = @request.execute do |response, request, result|
+ if [301, 302, 307].include? response.code and request.method == :get
+ response.follow_redirection(request, result)
+ else
+ raise OpenTox::RestCallError.new response.to_s, request, uri unless response.code < 400 or URI.task? uri
+ response
+ end
+ end
end
end
--
cgit v1.2.3
From 2551ed827399c20f571fa72edef5a59682ec5700 Mon Sep 17 00:00:00 2001
From: rautenberg
Date: Thu, 29 Mar 2012 18:08:26 +0200
Subject: fix logout error
---
lib/authorization.rb | 2 ++
1 file changed, 2 insertions(+)
(limited to 'lib')
diff --git a/lib/authorization.rb b/lib/authorization.rb
index 33fa0a4..a6d584c 100644
--- a/lib/authorization.rb
+++ b/lib/authorization.rb
@@ -101,6 +101,8 @@ module OpenTox
return true if !AA
begin
return true if RestClientWrapper.post("#{AA}/auth/isTokenValid",:tokenid => subjectid) == "boolean=true\n"
+ rescue
+ return false
end
return false
end
--
cgit v1.2.3
From 57f51d8ca7f6578eccb38deff1ab0c518f7a1df6 Mon Sep 17 00:00:00 2001
From: rautenberg
Date: Fri, 30 Mar 2012 13:54:35 +0200
Subject: fix request comparison
---
lib/authorization.rb | 1 +
1 file changed, 1 insertion(+)
(limited to 'lib')
diff --git a/lib/authorization.rb b/lib/authorization.rb
index a6d584c..fd20f68 100644
--- a/lib/authorization.rb
+++ b/lib/authorization.rb
@@ -312,6 +312,7 @@ module OpenTox
# @param [String] subjectid
# @return [Boolean] true if access granted, else otherwise
def self.authorized?(uri, request_method, subjectid)
+ request_method = request_method.to_sym if request_method
if $aa[:free_request].include?(request_method)
#$logger.debug "authorized? >>true<< (request is free), method: #{request_method}, URI: #{uri}, subjectid: #{subjectid}"
true
--
cgit v1.2.3
From b01dce14f765875d7c75edb545323b444fa2b140 Mon Sep 17 00:00:00 2001
From: rautenberg
Date: Tue, 10 Apr 2012 18:11:59 +0200
Subject: documentation for policy lib, seperate method to load default
template xml
---
lib/policy.rb | 19 +++++++++++++++++--
1 file changed, 17 insertions(+), 2 deletions(-)
(limited to 'lib')
diff --git a/lib/policy.rb b/lib/policy.rb
index 56a90b7..3e7c143 100644
--- a/lib/policy.rb
+++ b/lib/policy.rb
@@ -58,7 +58,7 @@ module OpenTox
when "guest", "anonymous" then "default_guest_policy"
else "default_policy"
end
- xml = File.read(File.join(File.dirname(__FILE__), "templates/#{template}.xml"))
+ xml = get_xml_template(template)
self.load_xml(xml)
datestring = Time.now.strftime("%Y-%m-%d-%H-%M-%S-x") + rand(1000).to_s
@@ -78,6 +78,10 @@ module OpenTox
return true
end
+ def get_xml_template(template)
+ File.read(File.join(File.dirname(__FILE__), "templates/#{template}.xml"))
+ end
+
#loads a xml template
def load_xml(xml)
rexml = REXML::Document.new(xml)
@@ -247,19 +251,22 @@ module OpenTox
end
# helper method sets value and type to opentox LDAP Distinguished Name (DN) of a user
+ # @param [String]Username set a username into LDAP DN
def set_ot_user(username)
self.value = "uid=#{username},ou=people,dc=opentox,dc=org"
self.type = "LDAPUsers"
true
end
+ # @param [String]Username set a groupname into LDAP DN
def set_ot_group(groupname)
self.value = "cn=#{groupname},ou=groups,dc=opentox,dc=org"
self.type = "LDAPGroups"
true
end
- #rule inside a policy
+ # policyrule
+ # sets the permission for REST actions (GET, POST, PUT, DELETE) of a specific URI to allow/deny/nil
class Rule
attr_accessor :name, :uri, :get, :post, :put, :delete, :read, :readwrite
@@ -293,14 +300,18 @@ module OpenTox
@put = check_value(value, @put)
end
+ # read getter method
def read
return true if @get == "allow" && (@put == "deny" || !@put) && (@post == "deny" || !@post)
end
+ # readwrite getter method
def readwrite
return true if @get == "allow" && @put == "allow" && @post == "allow"
end
+ # Set(true case) or remove read(GET=allow) permissions.
+ # @param [Boolean]value (true,false)
def read=(value)
if value
@get = "allow"; @put = nil; @post = nil
@@ -309,6 +320,8 @@ module OpenTox
end
end
+ # Set(true case) or remove readwrite(GET=allow,POST=allow,PUT=allow) permissions.
+ # @param [Boolean]value (true,false)
def readwrite=(value)
if value
@get = "allow"; @put = "allow"; @post = "allow"
@@ -324,6 +337,8 @@ module OpenTox
end
end
+ # Subject of a policy
+ # name(subjectname), type('LDAPUsers' or 'LDAPGroups'), value(LDAP DN e.G.:'uid=guest,ou=people,dc=opentox,dc=org')
class Subject
attr_accessor :name, :type, :value
--
cgit v1.2.3
From f8b6f8d19566d372e47edba7968ce66ff09052c9 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Thu, 26 Apr 2012 16:04:05 +0200
Subject: tests removed, URI.accessible? check temporarily removed
---
lib/opentox.rb | 1 +
lib/rest-client-wrapper.rb | 3 ++-
2 files changed, 3 insertions(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/opentox.rb b/lib/opentox.rb
index 187eb08..6ce439d 100644
--- a/lib/opentox.rb
+++ b/lib/opentox.rb
@@ -111,6 +111,7 @@ module OpenTox
end
def create service_uri, subjectid=nil
+ #uri = uri(SecureRandom.uuid)
uri = RestClientWrapper.post(service_uri, {}, {:accept => 'text/uri-list', :subjectid => subjectid})
URI.task?(service_uri) ? from_uri(uri, subjectid, false) : from_uri(uri, subjectid)
end
diff --git a/lib/rest-client-wrapper.rb b/lib/rest-client-wrapper.rb
index 479d5a5..3071432 100644
--- a/lib/rest-client-wrapper.rb
+++ b/lib/rest-client-wrapper.rb
@@ -18,7 +18,8 @@ module OpenTox
# check input
@subjectid = headers[:subjectid] ? headers[:subjectid] : nil
bad_request_error "Invalid URI: '#{uri}'" unless URI.valid? uri
- not_found_error "URI '#{uri}' not found." unless URI.accessible?(uri, @subjectid) unless URI.ssl?(uri)
+ #TODO fix for internal installations
+ #not_found_error "URI '#{uri}' not found." unless URI.accessible?(uri, @subjectid) unless URI.ssl?(uri)
bad_request_error "Headers are not a hash: #{headers.inspect}" unless headers==nil or headers.is_a?(Hash)
# make sure that no header parameters are set in the payload
[:accept,:content_type,:subjectid].each do |header|
--
cgit v1.2.3
From 1d49fe0da8e7d4dfc57fdbfffdc4e32db2ef0647 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Wed, 2 May 2012 20:06:16 +0000
Subject: initial task service
---
lib/error.rb | 38 ++++++++++++++++++++++++++++++++------
lib/opentox-client.rb | 2 ++
lib/opentox.rb | 9 +++++----
lib/overwrite.rb | 3 ++-
lib/rest-client-wrapper.rb | 6 ++++--
lib/task.rb | 23 +++++++++++++++++++----
6 files changed, 64 insertions(+), 17 deletions(-)
(limited to 'lib')
diff --git a/lib/error.rb b/lib/error.rb
index 579f42b..58b9816 100644
--- a/lib/error.rb
+++ b/lib/error.rb
@@ -7,12 +7,38 @@ class RuntimeError
super message
@uri = uri
@http_code ||= 500
- $logger.error "\n"+self.report.to_turtle
+ $logger.error "\n"+self.to_turtle
end
- def report
- # TODO: remove kludge for old task services
- OpenTox::ErrorReport.new(@http_code, self)
+ # define to_ and self.from_ methods for various rdf formats
+ RDF_FORMATS.each do |format|
+
+ send :define_method, "to_#{format}".to_sym do
+ rdf = RDF::Writer.for(format).buffer do |writer|
+ # TODO: not used for turtle
+ # http://rdf.rubyforge.org/RDF/Writer.html#
+ writer.prefix :ot, RDF::URI('http://www.opentox.org/api/1.2#')
+ writer.prefix :ot1_1, RDF::URI('http://www.opentox.org/api/1.1#')
+ subject = RDF::Node.new
+ writer << [subject, RDF.type, RDF::OT.ErrorReport]
+ writer << [subject, RDF::OT.actor, @uri.to_s]
+ writer << [subject, RDF::OT.message, @message.to_s]
+ writer << [subject, RDF::OT.statusCode, @http_code]
+ writer << [subject, RDF::OT.errorCode, self.class.to_s]
+
+ # cut backtrace
+ backtrace = caller.collect{|line| line unless line =~ /#{File.dirname(__FILE__)}/}.compact
+ cut_index = backtrace.find_index{|line| line.match /sinatra|minitest/}
+ cut_index ||= backtrace.size
+ cut_index -= 1
+ cut_index = backtrace.size-1 if cut_index < 0
+ details = backtrace[0..cut_index].join("\n")
+ details += "REST paramenters:\n#{@request.args.inspect}" if @request
+ writer << [subject, RDF::OT.errorCause, details]
+ end
+ rdf
+ end
+
end
end
@@ -61,6 +87,7 @@ module OpenTox
end
end
+=begin
# TODO: create reports directly from errors, requires modified task service
class ErrorReport
def initialize http_code, error
@@ -103,7 +130,6 @@ module OpenTox
rdf
end
-=begin
define_singleton_method "from_#{format}".to_sym do |rdf|
report = ErrorReport.new
RDF::Reader.for(format).new(rdf) do |reader|
@@ -111,7 +137,7 @@ module OpenTox
end
report
end
-=end
end
end
+=end
end
diff --git a/lib/opentox-client.rb b/lib/opentox-client.rb
index dec3512..0546634 100644
--- a/lib/opentox-client.rb
+++ b/lib/opentox-client.rb
@@ -7,6 +7,7 @@ require 'uri'
require 'yaml'
require 'json'
require 'logger'
+require "securerandom"
# define constants and global variables
#TODO: switch services to 1.2
@@ -17,6 +18,7 @@ RDF::OTA = RDF::Vocabulary.new 'http://www.opentox.org/algorithmTypes.owl#'
#CLASSES = ["Compound", "Feature", "Dataset", "Algorithm", "Model", "Validation", "Task", "ErrorReport", "Investigation"]
CLASSES = ["Generic", "Compound", "Feature", "Dataset", "Algorithm", "Model", "Validation", "Task", "Investigation"]
RDF_FORMATS = [:rdfxml,:ntriples,:turtle]
+#$default_rdf = "text/plain"
$default_rdf = "application/rdf+xml"
# Regular expressions for parsing classification data
diff --git a/lib/opentox.rb b/lib/opentox.rb
index 6ce439d..2682258 100644
--- a/lib/opentox.rb
+++ b/lib/opentox.rb
@@ -22,7 +22,8 @@ module OpenTox
# Load metadata from service
def pull
# TODO generic method for all formats
- parse_rdfxml RestClientWrapper.get(@uri,{},{:accept => $default_rdf, :subjectid => @subjectid})
+ #parse_rdfxml RestClientWrapper.get(@uri,{},{:accept => $default_rdf, :subjectid => @subjectid})
+ parse_ntriples RestClientWrapper.get(@uri,{},{:accept => "text/plain", :subjectid => @subjectid})
end
# Get object metadata
@@ -48,7 +49,7 @@ module OpenTox
# Save object at service
def save
#TODO: dynamic assignment
- post self.to_rdfxml, { :content_type => $default_rdf}
+ put self.to_rdfxml, { :content_type => $default_rdf}
end
RDF_FORMATS.each do |format|
@@ -111,7 +112,7 @@ module OpenTox
end
def create service_uri, subjectid=nil
- #uri = uri(SecureRandom.uuid)
+ #uri = File.join(service_uri,SecureRandom.uuid)
uri = RestClientWrapper.post(service_uri, {}, {:accept => 'text/uri-list', :subjectid => subjectid})
URI.task?(service_uri) ? from_uri(uri, subjectid, false) : from_uri(uri, subjectid)
end
@@ -126,7 +127,7 @@ module OpenTox
uri.chomp!
# TODO add waiting task
- if URI.task? uri and wait
+ if URI.task?(uri) and wait
t = OpenTox::Task.new(uri)
t.wait
uri = t.resultURI
diff --git a/lib/overwrite.rb b/lib/overwrite.rb
index d98769e..37c0bb3 100644
--- a/lib/overwrite.rb
+++ b/lib/overwrite.rb
@@ -15,7 +15,8 @@ module URI
end
def self.task? uri
- uri =~ /task/ and URI.valid? uri
+ #TODO remove localhost
+ (uri =~ /task/ or uri =~ /localhost/) and URI.valid? uri
end
def self.dataset? uri, subjectid=nil
diff --git a/lib/rest-client-wrapper.rb b/lib/rest-client-wrapper.rb
index 3071432..af1ba42 100644
--- a/lib/rest-client-wrapper.rb
+++ b/lib/rest-client-wrapper.rb
@@ -19,7 +19,7 @@ module OpenTox
@subjectid = headers[:subjectid] ? headers[:subjectid] : nil
bad_request_error "Invalid URI: '#{uri}'" unless URI.valid? uri
#TODO fix for internal installations
- #not_found_error "URI '#{uri}' not found." unless URI.accessible?(uri, @subjectid) unless URI.ssl?(uri)
+ not_found_error "URI '#{uri}' not found." unless URI.accessible?(uri, @subjectid) unless URI.ssl?(uri)
bad_request_error "Headers are not a hash: #{headers.inspect}" unless headers==nil or headers.is_a?(Hash)
# make sure that no header parameters are set in the payload
[:accept,:content_type,:subjectid].each do |header|
@@ -44,7 +44,9 @@ module OpenTox
if [301, 302, 307].include? response.code and request.method == :get
response.follow_redirection(request, result)
else
- raise OpenTox::RestCallError.new response.to_s, request, uri unless response.code < 400 or URI.task? uri
+ #TODO Reactivate for external services
+ #raise OpenTox::RestCallError.new response.to_s, request, uri unless response.code < 400 or URI.task? uri
+ rest_call_error response.to_s, request, uri unless response.code < 400 or URI.task? uri
response
end
end
diff --git a/lib/task.rb b/lib/task.rb
index bcf806e..4cdbb51 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -8,13 +8,27 @@ module OpenTox
def self.create service_uri, params={}
- task = Task.new RestClientWrapper.post(service_uri,params).chomp
+ uri = RDF::URI.new File.join(service_uri,SecureRandom.uuid)
+ #uri = RestClientWrapper.post service_uri
+ #puts uri
+ task = Task.new uri
+ #task.pull
+ #puts task.to_turtle
+ task.rdf << RDF::Statement.new(uri, RDF.type, RDF::OT.Task)
+ task.rdf << RDF::Statement.new(uri, RDF::DC.date, RDF::Literal.new(DateTime.now))
+ task.rdf << RDF::Statement.new(uri, RDF::OT.hasStatus, RDF::Literal.new("Running"))
+ params.each {|k,v| task.rdf << RDF::Statement.new(uri, k, v)}
+ task.save
pid = fork do
begin
result_uri = yield
task.completed result_uri
rescue
- RestClientWrapper.put(File.join(task.uri,'Error'),{:errorReport => $!.report.to_yaml}) if $!.respond_to? :report
+ if $!.respond_to? :to_ntriples
+ RestClientWrapper.put(File.join(task.uri,'Error'),:errorReport => $!.to_ntriples,:content_type => 'text/plain')
+ else
+ RestClientWrapper.put(File.join(task.uri,'Error')) #if $!.respond_to? :report
+ end
task.kill
end
end
@@ -58,7 +72,8 @@ module OpenTox
end
def completed(uri)
- #not_found_error "Result URI \"#{uri}\" does not exist." unless URI.accessible? uri
+ #TODO fix for https rewrites
+ not_found_error "Result URI \"#{uri}\" does not exist." unless URI.accessible? uri
RestClientWrapper.put(File.join(@uri,'Completed'),{:resultURI => uri})
end
@@ -68,7 +83,7 @@ module OpenTox
def wait
start_time = Time.new
due_to_time = start_time + DEFAULT_TASK_MAX_DURATION
- dur = 0
+ dur = 0.3
while running?
sleep dur
dur = [[(Time.new - start_time)/20.0,0.3].max,300.0].min
--
cgit v1.2.3
From 8b430fdfb285cbbb24116909c7fe69a424b522d2 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Thu, 3 May 2012 12:48:06 +0200
Subject: remote task tests working
---
lib/rest-client-wrapper.rb | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
(limited to 'lib')
diff --git a/lib/rest-client-wrapper.rb b/lib/rest-client-wrapper.rb
index af1ba42..d5d9c82 100644
--- a/lib/rest-client-wrapper.rb
+++ b/lib/rest-client-wrapper.rb
@@ -44,9 +44,7 @@ module OpenTox
if [301, 302, 307].include? response.code and request.method == :get
response.follow_redirection(request, result)
else
- #TODO Reactivate for external services
- #raise OpenTox::RestCallError.new response.to_s, request, uri unless response.code < 400 or URI.task? uri
- rest_call_error response.to_s, request, uri unless response.code < 400 or URI.task? uri
+ raise OpenTox::RestCallError.new response.to_s, request, uri unless response.code < 400 or URI.task? uri
response
end
end
--
cgit v1.2.3
From 3c68a43dae1ff97aaebc1bee87fcf4bdbc7c6dc9 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Thu, 3 May 2012 10:48:09 +0000
Subject: localhost removed as task uri
---
lib/overwrite.rb | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
(limited to 'lib')
diff --git a/lib/overwrite.rb b/lib/overwrite.rb
index 37c0bb3..d98769e 100644
--- a/lib/overwrite.rb
+++ b/lib/overwrite.rb
@@ -15,8 +15,7 @@ module URI
end
def self.task? uri
- #TODO remove localhost
- (uri =~ /task/ or uri =~ /localhost/) and URI.valid? uri
+ uri =~ /task/ and URI.valid? uri
end
def self.dataset? uri, subjectid=nil
--
cgit v1.2.3
From 8a5e3d69a16fc0c7d551e000270fe243ed121c85 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Fri, 4 May 2012 10:29:55 +0000
Subject: ntriples as default format, rdfxml as fallback
---
lib/error.rb | 53 ----------------------------------------------
lib/opentox-client.rb | 3 ---
lib/opentox.rb | 9 ++++----
lib/rest-client-wrapper.rb | 1 -
lib/task.rb | 12 +----------
5 files changed, 6 insertions(+), 72 deletions(-)
(limited to 'lib')
diff --git a/lib/error.rb b/lib/error.rb
index 58b9816..64b0fb1 100644
--- a/lib/error.rb
+++ b/lib/error.rb
@@ -87,57 +87,4 @@ module OpenTox
end
end
-=begin
- # TODO: create reports directly from errors, requires modified task service
- class ErrorReport
- def initialize http_code, error
- @http_code = http_code
- @report = {}
- @report[RDF::OT.actor] = error.uri.to_s
- @report[RDF::OT.message] = error.message.to_s
- @report[RDF::OT.statusCode] = @http_code
- @report[RDF::OT.errorCode] = error.class.to_s
-
- # cut backtrace
- backtrace = caller.collect{|line| line unless line =~ /#{File.dirname(__FILE__)}/}.compact
- cut_index = backtrace.find_index{|line| line.match /sinatra|minitest/}
- cut_index ||= backtrace.size
- cut_index -= 1
- cut_index = backtrace.size-1 if cut_index < 0
- @report[RDF::OT.errorDetails] = backtrace[0..cut_index].join("\n")
- @report[RDF::OT.errorDetails] += "REST paramenters:\n#{error.request.args.inspect}" if defined? error.request
- #@report[RDF::OT.message] += "\n" + error.response.body.to_s if defined? error.response
- # TODO fix Error cause
- # should point to another errorReport, but errorReports do not have URIs
- # create a separate service?
- #report[RDF::OT.errorCause] = @report if defined?(@report)
- end
-
- # define to_ and self.from_ methods for various rdf formats
- RDF_FORMATS.each do |format|
-
- send :define_method, "to_#{format}".to_sym do
- rdf = RDF::Writer.for(format).buffer do |writer|
- # TODO: not used for turtle
- # http://rdf.rubyforge.org/RDF/Writer.html#
- writer.prefix :ot, RDF::URI('http://www.opentox.org/api/1.2#')
- writer.prefix :ot1_1, RDF::URI('http://www.opentox.org/api/1.1#')
- subject = RDF::Node.new
- @report.each do |predicate,object|
- writer << [subject, predicate, object] if object
- end
- end
- rdf
- end
-
- define_singleton_method "from_#{format}".to_sym do |rdf|
- report = ErrorReport.new
- RDF::Reader.for(format).new(rdf) do |reader|
- reader.each_statement{ |statement| report.rdf << statement }
- end
- report
- end
- end
- end
-=end
end
diff --git a/lib/opentox-client.rb b/lib/opentox-client.rb
index 0546634..8c19225 100644
--- a/lib/opentox-client.rb
+++ b/lib/opentox-client.rb
@@ -15,11 +15,8 @@ RDF::OT = RDF::Vocabulary.new 'http://www.opentox.org/api/1.2#'
RDF::OT1 = RDF::Vocabulary.new 'http://www.opentox.org/api/1.1#'
RDF::OTA = RDF::Vocabulary.new 'http://www.opentox.org/algorithmTypes.owl#'
-#CLASSES = ["Compound", "Feature", "Dataset", "Algorithm", "Model", "Validation", "Task", "ErrorReport", "Investigation"]
CLASSES = ["Generic", "Compound", "Feature", "Dataset", "Algorithm", "Model", "Validation", "Task", "Investigation"]
RDF_FORMATS = [:rdfxml,:ntriples,:turtle]
-#$default_rdf = "text/plain"
-$default_rdf = "application/rdf+xml"
# Regular expressions for parsing classification data
TRUE_REGEXP = /^(true|active|1|1.0|tox|activating|carcinogen|mutagenic)$/i
diff --git a/lib/opentox.rb b/lib/opentox.rb
index 2682258..f79b51b 100644
--- a/lib/opentox.rb
+++ b/lib/opentox.rb
@@ -21,9 +21,9 @@ module OpenTox
# Load metadata from service
def pull
- # TODO generic method for all formats
- #parse_rdfxml RestClientWrapper.get(@uri,{},{:accept => $default_rdf, :subjectid => @subjectid})
parse_ntriples RestClientWrapper.get(@uri,{},{:accept => "text/plain", :subjectid => @subjectid})
+ rescue # fall back to rdfxml
+ parse_rdfxml RestClientWrapper.get(@uri,{},{:accept => "application/rdf+xml", :subjectid => @subjectid})
end
# Get object metadata
@@ -48,8 +48,9 @@ module OpenTox
# Save object at service
def save
- #TODO: dynamic assignment
- put self.to_rdfxml, { :content_type => $default_rdf}
+ put self.to_ntriples, { :content_type => "text/plain"}
+ rescue # fall back to rdfxml
+ put self.to_rdfxml, { :content_type => "application/rdf+xml"}
end
RDF_FORMATS.each do |format|
diff --git a/lib/rest-client-wrapper.rb b/lib/rest-client-wrapper.rb
index d5d9c82..479d5a5 100644
--- a/lib/rest-client-wrapper.rb
+++ b/lib/rest-client-wrapper.rb
@@ -18,7 +18,6 @@ module OpenTox
# check input
@subjectid = headers[:subjectid] ? headers[:subjectid] : nil
bad_request_error "Invalid URI: '#{uri}'" unless URI.valid? uri
- #TODO fix for internal installations
not_found_error "URI '#{uri}' not found." unless URI.accessible?(uri, @subjectid) unless URI.ssl?(uri)
bad_request_error "Headers are not a hash: #{headers.inspect}" unless headers==nil or headers.is_a?(Hash)
# make sure that no header parameters are set in the payload
diff --git a/lib/task.rb b/lib/task.rb
index 4cdbb51..ceb6fd9 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -9,11 +9,7 @@ module OpenTox
def self.create service_uri, params={}
uri = RDF::URI.new File.join(service_uri,SecureRandom.uuid)
- #uri = RestClientWrapper.post service_uri
- #puts uri
task = Task.new uri
- #task.pull
- #puts task.to_turtle
task.rdf << RDF::Statement.new(uri, RDF.type, RDF::OT.Task)
task.rdf << RDF::Statement.new(uri, RDF::DC.date, RDF::Literal.new(DateTime.now))
task.rdf << RDF::Statement.new(uri, RDF::OT.hasStatus, RDF::Literal.new("Running"))
@@ -27,7 +23,7 @@ module OpenTox
if $!.respond_to? :to_ntriples
RestClientWrapper.put(File.join(task.uri,'Error'),:errorReport => $!.to_ntriples,:content_type => 'text/plain')
else
- RestClientWrapper.put(File.join(task.uri,'Error')) #if $!.respond_to? :report
+ RestClientWrapper.put(File.join(task.uri,'Error'))
end
task.kill
end
@@ -72,7 +68,6 @@ module OpenTox
end
def completed(uri)
- #TODO fix for https rewrites
not_found_error "Result URI \"#{uri}\" does not exist." unless URI.accessible? uri
RestClientWrapper.put(File.join(@uri,'Completed'),{:resultURI => uri})
end
@@ -111,11 +106,6 @@ module OpenTox
code >= 400 and code != 503
end
- def errorReport
- # TODO: fix rdf output at task service
- not_implemented_error "RDF output of errorReports has to be fixed at task service"
- end
-
[:hasStatus, :resultURI].each do |method|
define_method method do
response = self.[](RDF::OT[method])
--
cgit v1.2.3
From 950fffe995027a8463459363a7e6bd069c34fbef Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Wed, 9 May 2012 10:29:07 +0000
Subject: subjectid for tasks, uri check on completion disabled
---
lib/task.rb | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
(limited to 'lib')
diff --git a/lib/task.rb b/lib/task.rb
index ceb6fd9..d45b0d2 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -6,10 +6,10 @@ module OpenTox
attr_accessor :pid, :observer_pid
- def self.create service_uri, params={}
+ def self.create service_uri, subjectid=nil, params={}
uri = RDF::URI.new File.join(service_uri,SecureRandom.uuid)
- task = Task.new uri
+ task = Task.new uri, subjectid
task.rdf << RDF::Statement.new(uri, RDF.type, RDF::OT.Task)
task.rdf << RDF::Statement.new(uri, RDF::DC.date, RDF::Literal.new(DateTime.now))
task.rdf << RDF::Statement.new(uri, RDF::OT.hasStatus, RDF::Literal.new("Running"))
@@ -68,7 +68,8 @@ module OpenTox
end
def completed(uri)
- not_found_error "Result URI \"#{uri}\" does not exist." unless URI.accessible? uri
+ #puts uri
+ #not_found_error "Result URI \"#{uri}\" does not exist." unless URI.accessible? uri, @subjectid
RestClientWrapper.put(File.join(@uri,'Completed'),{:resultURI => uri})
end
--
cgit v1.2.3
From 5f61cefdefc51a728147478820ffe04c5ec127d5 Mon Sep 17 00:00:00 2001
From: rautenberg
Date: Mon, 4 Jun 2012 16:14:07 +0200
Subject: remove URI.ssl and URI.accessable test
---
lib/rest-client-wrapper.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/rest-client-wrapper.rb b/lib/rest-client-wrapper.rb
index 479d5a5..5707831 100644
--- a/lib/rest-client-wrapper.rb
+++ b/lib/rest-client-wrapper.rb
@@ -18,7 +18,7 @@ module OpenTox
# check input
@subjectid = headers[:subjectid] ? headers[:subjectid] : nil
bad_request_error "Invalid URI: '#{uri}'" unless URI.valid? uri
- not_found_error "URI '#{uri}' not found." unless URI.accessible?(uri, @subjectid) unless URI.ssl?(uri)
+ #not_found_error "URI '#{uri}' not found." unless URI.accessible?(uri, @subjectid) unless URI.ssl?(uri)
bad_request_error "Headers are not a hash: #{headers.inspect}" unless headers==nil or headers.is_a?(Hash)
# make sure that no header parameters are set in the payload
[:accept,:content_type,:subjectid].each do |header|
--
cgit v1.2.3
From 9119cb4f3fbcedb5c233b0a1f3fe1398fcc0e193 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Thu, 28 Jun 2012 12:24:52 +0000
Subject: modified assignment operator
---
lib/opentox.rb | 24 +++++++++++++++++++++---
lib/overwrite.rb | 20 ++++++++++++++++++++
2 files changed, 41 insertions(+), 3 deletions(-)
(limited to 'lib')
diff --git a/lib/opentox.rb b/lib/opentox.rb
index f79b51b..6df16fa 100644
--- a/lib/opentox.rb
+++ b/lib/opentox.rb
@@ -46,11 +46,22 @@ module OpenTox
result
end
+ def []=(key,value)
+ uri = RDF::URI.new(@uri)
+ #@rdf.delete [uri,key,nil]
+ #result = @rdf.query([RDF::URI.new(@uri),key,nil]).collect{|statement| statement.object}
+ @rdf << [uri, key, value]
+ end
+
+ #def []<<(key,value)
+ #@rdf << [RDF::URI.new(@uri), key, value]
+ #end
+
# Save object at service
def save
put self.to_ntriples, { :content_type => "text/plain"}
- rescue # fall back to rdfxml
- put self.to_rdfxml, { :content_type => "application/rdf+xml"}
+ #rescue # fall back to rdfxml
+ #put self.to_rdfxml, { :content_type => "application/rdf+xml"}
end
RDF_FORMATS.each do |format|
@@ -113,8 +124,15 @@ module OpenTox
end
def create service_uri, subjectid=nil
+ bnode = RDF::Node.new
+ klass = "RDF::OT."+self.class.to_s.split('::').last
+ #puts self.class
+ #puts klass
+ #object = eval "#{~
+ @rdf << [bnode, RDF.type, klass]
#uri = File.join(service_uri,SecureRandom.uuid)
- uri = RestClientWrapper.post(service_uri, {}, {:accept => 'text/uri-list', :subjectid => subjectid})
+ uri = RestClientWrapper.post(service_uri, self.to_ntriples, {:content_type => 'text/plain', :accept => 'text/uri-list', :subjectid => subjectid})
+ #uri = RestClientWrapper.put(uri, {}, {:accept => 'text/uri-list', :subjectid => subjectid})
URI.task?(service_uri) ? from_uri(uri, subjectid, false) : from_uri(uri, subjectid)
end
diff --git a/lib/overwrite.rb b/lib/overwrite.rb
index d98769e..fa2128a 100644
--- a/lib/overwrite.rb
+++ b/lib/overwrite.rb
@@ -1,3 +1,23 @@
+class Object
+ # An object is blank if it's false, empty, or a whitespace string.
+ # For example, "", " ", +nil+, [], and {} are all blank.
+ def blank?
+ respond_to?(:empty?) ? empty? : !self
+ end
+
+ def numeric?
+ true if Float(self) rescue false
+ end
+end
+
+=begin
+module Enumerable
+ def duplicates
+ inject({}) {|h,v| h[v] += 1; h}.reject{|k,v| v==1}.keys
+ end
+end
+=end
+
class String
def underscore
self.gsub(/::/, '/').
--
cgit v1.2.3
From 5ecdec2682ac6b61912afe74123b6d3d7c15e771 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Thu, 28 Jun 2012 14:29:05 +0200
Subject: Dataset.data_entries fixed
---
lib/dataset.rb | 13 +++++++++----
lib/opentox.rb | 1 +
2 files changed, 10 insertions(+), 4 deletions(-)
(limited to 'lib')
diff --git a/lib/dataset.rb b/lib/dataset.rb
index 8032533..1367d3f 100644
--- a/lib/dataset.rb
+++ b/lib/dataset.rb
@@ -4,13 +4,18 @@ module OpenTox
class Dataset
def data_entries
- # TODO fix for api 1.2
data_entries = []
pull
@reload = false
- metadata[RDF::OT1.dataEntry].collect{|data_entry|
- data_entries << @rdf.to_hash[data_entry]
- }
+ begin
+ metadata[RDF::OT.dataEntry].collect{|data_entry| data_entries << @rdf.to_hash[data_entry] }
+ rescue
+ end
+ begin
+ # TODO: remove API 1.1
+ metadata[RDF::OT1.dataEntry].collect{|data_entry| data_entries << @rdf.to_hash[data_entry] }
+ rescue
+ end
@reload = true
data_entries
end
diff --git a/lib/opentox.rb b/lib/opentox.rb
index f79b51b..b282ed2 100644
--- a/lib/opentox.rb
+++ b/lib/opentox.rb
@@ -120,6 +120,7 @@ module OpenTox
def from_file service_uri, filename, subjectid=nil
file = File.new filename
+ # TODO: sdf files are incorrectly detected
from_uri RestClientWrapper.post(service_uri, {:file => file}, {:subjectid => subjectid, :content_type => file.mime_type, :accept => "text/uri-list"}), subjectid
end
--
cgit v1.2.3
From 6c657ac84268f2cac458eb43ec156a7a38a4f95a Mon Sep 17 00:00:00 2001
From: gebele
Date: Thu, 5 Jul 2012 15:06:34 +0400
Subject: expand methods :finished_at
---
lib/task.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/task.rb b/lib/task.rb
index d45b0d2..2ca481d 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -107,7 +107,7 @@ module OpenTox
code >= 400 and code != 503
end
- [:hasStatus, :resultURI].each do |method|
+ [:hasStatus, :resultURI, :finished_at].each do |method|
define_method method do
response = self.[](RDF::OT[method])
response = self.[](RDF::OT1[method]) unless response # API 1.1 compatibility
--
cgit v1.2.3
From d8e72c6ff7ce2b147b6a11d233b80bbc8f1760d9 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Fri, 6 Jul 2012 16:44:12 +0200
Subject: feature and task tests pass
---
lib/dataset.rb | 10 ++--
lib/opentox.rb | 141 +++++++++++++++++++++++----------------------------------
lib/task.rb | 27 ++++++-----
3 files changed, 75 insertions(+), 103 deletions(-)
(limited to 'lib')
diff --git a/lib/dataset.rb b/lib/dataset.rb
index 1367d3f..33e1571 100644
--- a/lib/dataset.rb
+++ b/lib/dataset.rb
@@ -5,18 +5,18 @@ module OpenTox
def data_entries
data_entries = []
- pull
- @reload = false
+ #pull
+ #@reload = false
begin
- metadata[RDF::OT.dataEntry].collect{|data_entry| data_entries << @rdf.to_hash[data_entry] }
+ self.[](RDF::OT.dataEntry).collect{|data_entry| data_entries << @rdf.to_hash[data_entry] }
rescue
end
begin
# TODO: remove API 1.1
- metadata[RDF::OT1.dataEntry].collect{|data_entry| data_entries << @rdf.to_hash[data_entry] }
+ self.[](RDF::OT1.dataEntry).collect{|data_entry| data_entries << @rdf.to_hash[data_entry] }
rescue
end
- @reload = true
+ #@reload = true
data_entries
end
diff --git a/lib/opentox.rb b/lib/opentox.rb
index b575e52..b0c786a 100644
--- a/lib/opentox.rb
+++ b/lib/opentox.rb
@@ -4,7 +4,7 @@ $logger.level = Logger::DEBUG
module OpenTox
- attr_accessor :uri, :subjectid, :rdf, :response, :reload
+ attr_accessor :uri, :subjectid, :rdf
# Ruby interface
@@ -13,55 +13,72 @@ module OpenTox
# @param [optional,String] subjectid
# @return [OpenTox] OpenTox object
def initialize uri=nil, subjectid=nil
- @uri = uri.to_s.chomp
- @subjectid = subjectid
- @reload = true
@rdf = RDF::Graph.new
+ uri ? @uri = uri.to_s.chomp : @uri = RDF::Node.uuid.to_s
+ append RDF.type, eval("RDF::OT."+self.class.to_s.split('::').last)
+ append RDF::DC.date, DateTime.now
+ @subjectid = subjectid
end
- # Load metadata from service
- def pull
- parse_ntriples RestClientWrapper.get(@uri,{},{:accept => "text/plain", :subjectid => @subjectid})
- rescue # fall back to rdfxml
- parse_rdfxml RestClientWrapper.get(@uri,{},{:accept => "application/rdf+xml", :subjectid => @subjectid})
+ # Object metadata
+ # @return [Hash] Object metadata
+ def metadata
+ # return plain strings instead of RDF objects
+ #puts @rdf.to_hash
+ @rdf.to_hash[RDF::URI.new(@uri)].inject({}) { |h, (predicate, values)| h[predicate.to_s] = values.collect{|v| v.to_s}; h }
end
- # Get object metadata
- # @return [Hash] Metadata
- def metadata
- pull if @reload # force update
- @rdf.to_hash[RDF::URI.new(@uri)]
+ # Metadata values
+ # @param [String] Predicate URI
+ # @return [Array, String] Predicate value(s)
+ def [](predicate)
+ metadata[predicate.to_s].size == 1 ? metadata[predicate.to_s].first : metadata[predicate.to_s]
+ end
+
+ # Set object metadata
+ # @param [String] Predicate URI
+ # @param [Array, String] Predicate value(s)
+ def []=(predicate,values)
+ @rdf.delete [RDF::URI.new(@uri.to_s),RDF::URI.new(predicate.to_s),nil]
+ append predicate.to_s, values
end
- # Get metadata values
- # @param [RDF] Key from RDF Vocabularies
- # @return [Array] Values for supplied key
- def [](key)
- pull if @reload # force update
- result = @rdf.query([RDF::URI.new(@uri),key,nil]).collect{|statement| statement.object}
- # TODO: convert to OpenTox objects??
- return nil if result and result.empty?
- return result.first.to_s if result.size == 1
- return result.collect{|r| r.to_s}
- result
+ # Append object metadata
+ # @param [String] Predicate URI
+ # @param [Array, String] Predicate value(s)
+ def append(predicate,values)
+ uri = RDF::URI.new @uri
+ predicate = RDF::URI.new predicate
+ [values].flatten.each { |value| @rdf << [uri, predicate, value] }
end
- def []=(key,value)
- uri = RDF::URI.new(@uri)
- #@rdf.delete [uri,key,nil]
- #result = @rdf.query([RDF::URI.new(@uri),key,nil]).collect{|statement| statement.object}
- @rdf << [uri, key, value]
+ # Get object from webservice
+ def get
+ parse_ntriples RestClientWrapper.get(@uri,{},{:accept => "text/plain", :subjectid => @subjectid})
+ rescue # fall back to rdfxml
+ parse_rdfxml RestClientWrapper.get(@uri,{},{:accept => "application/rdf+xml", :subjectid => @subjectid})
end
- #def []<<(key,value)
- #@rdf << [RDF::URI.new(@uri), key, value]
- #end
+ # Post object to webservice
+ def post service_uri
+ RestClientWrapper.post service_uri, to_ntriples, { :content_type => "text/plain", :subjectid => @subjectid}
+ rescue # fall back to rdfxml
+ RestClientWrapper.post service_uri, to_rdfxml, { :content_type => "application/rdf+xml", :subjectid => @subjectid}
+ end
- # Save object at service
- def save
- put self.to_ntriples, { :content_type => "text/plain"}
- #rescue # fall back to rdfxml
- #put self.to_rdfxml, { :content_type => "application/rdf+xml"}
+ # Save object at webservice
+ def put
+ append RDF::DC.modified, DateTime.now
+ begin
+ RestClientWrapper.put @uri.to_s, self.to_ntriples, { :content_type => "text/plain", :subjectid => @subjectid}
+ rescue # fall back to rdfxml
+ RestClientWrapper.put @uri.to_s, self.to_rdfxml, { :content_type => "application/rdf+xml", :subjectid => @subjectid}
+ end
+ end
+
+ # Delete object at webservice
+ def delete
+ @response = RestClientWrapper.delete(@uri.to_s,nil,{:subjectid => @subjectid})
end
RDF_FORMATS.each do |format|
@@ -83,38 +100,6 @@ module OpenTox
end
end
- def to_yaml
- @rdf.to_hash.to_yaml
- end
-
- def to_json
- to_hash.to_json
- end
-
- # REST API
- def get headers={}
- headers[:subjectid] ||= @subjectid
- headers[:accept] ||= 'application/rdf+xml'
- @response = RestClientWrapper.get @uri, {}, headers
- end
-
- def post payload={}, headers={}
- headers[:subjectid] ||= @subjectid
- headers[:accept] ||= 'application/rdf+xml'
- @response = RestClientWrapper.post(@uri.to_s, payload, headers)
- end
-
- def put payload={}, headers={}
- headers[:subjectid] ||= @subjectid
- headers[:accept] ||= 'application/rdf+xml'
- @response = RestClientWrapper.put(@uri.to_s, payload, headers)
- end
-
- def delete headers={}
- headers[:subjectid] ||= @subjectid
- @response = RestClientWrapper.delete(@uri.to_s,nil,headers)
- end
-
# class methods
module ClassMethods
@@ -123,22 +108,10 @@ module OpenTox
uris.collect{|uri| URI.task?(service_uri) ? from_uri(uri, subjectid, false) : from_uri(uri, subjectid)}
end
- def create service_uri, subjectid=nil
- bnode = RDF::Node.new
- klass = "RDF::OT."+self.class.to_s.split('::').last
- #puts self.class
- #puts klass
- #object = eval "#{~
- @rdf << [bnode, RDF.type, klass]
- #uri = File.join(service_uri,SecureRandom.uuid)
- uri = RestClientWrapper.post(service_uri, self.to_ntriples, {:content_type => 'text/plain', :accept => 'text/uri-list', :subjectid => subjectid})
- #uri = RestClientWrapper.put(uri, {}, {:accept => 'text/uri-list', :subjectid => subjectid})
- URI.task?(service_uri) ? from_uri(uri, subjectid, false) : from_uri(uri, subjectid)
- end
-
def from_file service_uri, filename, subjectid=nil
file = File.new filename
- # TODO: sdf files are incorrectly detected
+ # sdf files are incorrectly detected
+ file.mime_type = "chemical/x-mdl-sdfile" if File.extname(filename) == ".sdf"
from_uri RestClientWrapper.post(service_uri, {:file => file}, {:subjectid => subjectid, :content_type => file.mime_type, :accept => "text/uri-list"}), subjectid
end
diff --git a/lib/task.rb b/lib/task.rb
index d45b0d2..f3f7f6b 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -8,13 +8,11 @@ module OpenTox
def self.create service_uri, subjectid=nil, params={}
- uri = RDF::URI.new File.join(service_uri,SecureRandom.uuid)
+ uri = File.join(service_uri,SecureRandom.uuid)
task = Task.new uri, subjectid
- task.rdf << RDF::Statement.new(uri, RDF.type, RDF::OT.Task)
- task.rdf << RDF::Statement.new(uri, RDF::DC.date, RDF::Literal.new(DateTime.now))
- task.rdf << RDF::Statement.new(uri, RDF::OT.hasStatus, RDF::Literal.new("Running"))
- params.each {|k,v| task.rdf << RDF::Statement.new(uri, k, v)}
- task.save
+ task[RDF::OT.hasStatus] = "Running"
+ params.each { |k,v| task[k] = v }
+ task.put
pid = fork do
begin
result_uri = yield
@@ -53,24 +51,23 @@ module OpenTox
end
def description
- pull
- self.[](RDF::DC.description).uniq.first
+ self.[](RDF::DC.description)
end
def creator
- pull
- self.[](RDF::DC.creator).uniq.first
+ self.[](RDF::DC.creator)
end
def cancel
kill
- RestClientWrapper.put(File.join(@uri,'Cancelled'),{})
+ self.[]=(RDF::OT.hasStatus, "Cancelled")
+ put
end
def completed(uri)
- #puts uri
- #not_found_error "Result URI \"#{uri}\" does not exist." unless URI.accessible? uri, @subjectid
- RestClientWrapper.put(File.join(@uri,'Completed'),{:resultURI => uri})
+ self.[]=(RDF::OT.resultURI, uri)
+ self.[]=(RDF::OT.hasStatus, "Completed")
+ put
end
# waits for a task, unless time exceeds or state is no longer running
@@ -85,6 +82,7 @@ module OpenTox
dur = [[(Time.new - start_time)/20.0,0.3].max,300.0].min
time_out_error "max wait time exceeded ("+DEFAULT_TASK_MAX_DURATION.to_s+"sec), task: '"+@uri.to_s+"'" if (Time.new > due_to_time)
end
+ get
end
end
@@ -109,6 +107,7 @@ module OpenTox
[:hasStatus, :resultURI].each do |method|
define_method method do
+ get
response = self.[](RDF::OT[method])
response = self.[](RDF::OT1[method]) unless response # API 1.1 compatibility
response
--
cgit v1.2.3
From bf6834445feb6f93f0a20359462dbd1e7e89f4b8 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Thu, 12 Jul 2012 16:38:03 +0200
Subject: all opentox-client tests pass
---
lib/compound.rb | 12 ++---
lib/dataset.rb | 134 +++++++++++++++++++++++++++++++++++++++++++-------
lib/error.rb | 5 +-
lib/opentox-client.rb | 2 +
lib/opentox.rb | 80 +++++++++++++-----------------
5 files changed, 160 insertions(+), 73 deletions(-)
(limited to 'lib')
diff --git a/lib/compound.rb b/lib/compound.rb
index ce0fdbf..5992ee3 100644
--- a/lib/compound.rb
+++ b/lib/compound.rb
@@ -40,25 +40,25 @@ module OpenTox
# Get InChI
# @return [String] InChI string
def to_inchi
- get(:accept => 'chemical/x-inchi').to_s.chomp if @uri
+ RestClientWrapper.get(@uri,{},{:accept => 'chemical/x-inchi'}).chomp
end
# Get (canonical) smiles
# @return [String] Smiles string
def to_smiles
- get(:accept => 'chemical/x-daylight-smiles').chomp
+ RestClientWrapper.get(@uri,{},{:accept => 'chemical/x-daylight-smiles'}).chomp
end
# Get sdf
# @return [String] SDF string
def to_sdf
- get(:accept => 'chemical/x-mdl-sdfile').chomp
+ RestClientWrapper.get(@uri,{},{:accept => 'chemical/x-mdl-sdfile'}).chomp
end
# Get gif image
# @return [image/gif] Image data
def to_gif
- get("#{CACTUS_URI}#{to_inchi}/image")
+ RestClientWrapper.get("#{CACTUS_URI}#{to_inchi}/image")
end
# Get png image
@@ -66,7 +66,7 @@ module OpenTox
# image = compound.to_png
# @return [image/png] Image data
def to_png
- get(File.join @uri, "image")
+ RestClientWrapper.get(File.join @uri, "image")
end
# Get URI of compound image
@@ -81,7 +81,7 @@ module OpenTox
# @return [String] Compound names
def to_names
begin
- get("#{CACTUS_URI}#{to_inchi}/names").split("\n")
+ RestClientWrapper.get("#{CACTUS_URI}#{to_inchi}/names").split("\n")
rescue
"not available"
end
diff --git a/lib/dataset.rb b/lib/dataset.rb
index 33e1571..ed0ccdd 100644
--- a/lib/dataset.rb
+++ b/lib/dataset.rb
@@ -3,32 +3,128 @@ module OpenTox
# Ruby wrapper for OpenTox Dataset Webservices (http://opentox.org/dev/apis/api-1.2/dataset).
class Dataset
- def data_entries
- data_entries = []
- #pull
- #@reload = false
- begin
- self.[](RDF::OT.dataEntry).collect{|data_entry| data_entries << @rdf.to_hash[data_entry] }
- rescue
+ attr_accessor :features, :compounds, :data_entries
+
+ def initialize uri=nil, subjectid=nil
+ super uri, subjectid
+ @features = []
+ @compounds = []
+ @data_entries = []
+ append RDF.type, RDF::OT.OrderedDataset
+ end
+
+ def upload filename
+ file = File.new filename
+ RestClientWrapper.put(@uri, {:file => file}, {:subjectid => @subjectid})
+ end
+
+ def get
+ super
+ @features = []
+ @compounds = []
+ @data_entries = []
+ query = RDF::Query.new do
+ pattern [:uri, RDF.type, RDF::OT.OrderedDataset]
end
- begin
- # TODO: remove API 1.1
- self.[](RDF::OT1.dataEntry).collect{|data_entry| data_entries << @rdf.to_hash[data_entry] }
- rescue
+ if query.execute(@rdf).first # ordered dataset
+ query = RDF::Query.new do
+ pattern [:uri, RDF.type, RDF::OT.Compound]
+ pattern [:uri, RDF::OLO.index, :idx]
+ end
+ @compounds = query.execute(@rdf).sort_by{|s| s.idx}.collect{|s| OpenTox::Compound.new s.uri.to_s}
+ query = RDF::Query.new do
+ pattern [:uri, RDF.type, RDF::OT.Feature]
+ pattern [:uri, RDF::OLO.index, :idx]
+ end
+ @features = query.execute(@rdf).sort_by{|s| s.idx}.collect{|s| OpenTox::Feature.new(s.uri.to_s)}
+ numeric_features = @features.collect{|f| f.get; f[RDF.type].include? RDF::OT.NumericFeature}
+ @compounds.each_with_index do |compound,i|
+ query = RDF::Query.new do
+ pattern [:data_entry, RDF::OLO.index, i]
+ pattern [:data_entry, RDF::OT.values, :values]
+ pattern [:values, RDF::OT.feature, :feature]
+ pattern [:feature, RDF::OLO.index, :feature_idx]
+ pattern [:values, RDF::OT.value, :value]
+ end
+ values = query.execute(@rdf).sort_by{|s| s.feature_idx}.collect do |s|
+ numeric_features[s.feature_idx] ? s.value.to_s.to_f : s.value.to_s
+ end
+ @data_entries << values
+ end
+ else
+ query = RDF::Query.new do
+ pattern [:uri, RDF.type, RDF::OT.Feature]
+ end
+ @features = query.execute(@rdf).collect{|s| OpenTox::Feature.new(s.uri.to_s)}
+ query = RDF::Query.new do
+ pattern [:data_entry, RDF::OT.compound, :compound]
+ end
+ @compounds = query.execute(@rdf).sort_by{|s| s.data_entry}.collect{|s| OpenTox::Compound.new s.compound.to_s}
+ numeric_features = @features.collect{|f| f.get; f[RDF.type].include? RDF::OT.NumericFeature}
+ @compounds.each do |compound|
+ values = []
+ @features.each_with_index do |feature,i|
+ query = RDF::Query.new do
+ pattern [:data_entry, RDF::OT.compound, RDF::URI.new(compound.uri)]
+ pattern [:data_entry, RDF::OT.values, :values]
+ pattern [:values, RDF::OT.feature, RDF::URI.new(feature.uri)]
+ pattern [:values, RDF::OT.value, :value]
+ end
+ value = query.execute(@rdf).first.value.to_s
+ value = value.to_f if numeric_features[i]
+ values << value
+ end
+ @data_entries << values
+ end
end
- #@reload = true
- data_entries
end
- def compounds
- uri = File.join(@uri,"compounds")
- RestClientWrapper.get(uri,{},{:accept => "text/uri-list", :subjectid => @subjectid}).split("\n").collect{|uri| OpenTox::Compound.new uri}
+ def get_metadata
+ uri = File.join(@uri,"metadata")
+ begin
+ parse_ntriples RestClientWrapper.get(uri,{},{:accept => "text/plain", :subjectid => @subjectid})
+ rescue # fall back to rdfxml
+ parse_rdfxml RestClientWrapper.get(uri,{},{:accept => "application/rdf+xml", :subjectid => @subjectid})
+ end
+ metadata
end
- def features
- uri = File.join(@uri,"features")
- RestClientWrapper.get(uri,{},{:accept => "text/uri-list", :subjectid => @subjectid}).split("\n").collect{|uri| OpenTox::Feature.new uri}
+ def << data_entry
+ compound = data_entry.shift
+ bad_request_error "Dataset features are empty." unless features
+ bad_request_error "data_entry size does not match features size." unless data_entry.size == features.size
+ bad_request_error "First data_entry is not a OpenTox::Compound" unless compound.class == OpenTox::Compound
+ @compounds << compound
+ @data_entries << data_entry
end
+ RDF_FORMATS.each do |format|
+
+ # redefine rdf serialization methods
+ send :define_method, "to_#{format}".to_sym do
+ # TODO: check, might affect appending to unordered datasets
+ features.each_with_index do |feature,i|
+ @rdf << [RDF::URI.new(feature.uri), RDF::URI.new(RDF.type), RDF::URI.new(RDF::OT.Feature)]
+ @rdf << [RDF::URI.new(feature.uri), RDF::URI.new(RDF::OLO.index), RDF::Literal.new(i)]
+ end
+ compounds.each_with_index do |compound,i|
+ @rdf << [RDF::URI.new(compound.uri), RDF::URI.new(RDF.type), RDF::URI.new(RDF::OT.Compound)]
+ @rdf << [RDF::URI.new(compound.uri), RDF::URI.new(RDF::OLO.index), RDF::Literal.new(i)]
+ data_entry_node = RDF::Node.new
+ @rdf << [RDF::URI.new(@uri), RDF::URI.new(RDF::OT.dataEntry), data_entry_node]
+ @rdf << [data_entry_node, RDF::URI.new(RDF.type), RDF::URI.new(RDF::OT.DataEntry)]
+ @rdf << [data_entry_node, RDF::URI.new(RDF::OLO.index), RDF::Literal.new(i)]
+ @rdf << [data_entry_node, RDF::URI.new(RDF::OT.compound), RDF::URI.new(compound.uri)]
+ data_entries[i].each_with_index do |value,j|
+ value_node = RDF::Node.new
+ @rdf << [data_entry_node, RDF::URI.new(RDF::OT.values), value_node]
+ @rdf << [value_node, RDF::URI.new(RDF::OT.feature), RDF::URI.new(@features[j].uri)]
+ @rdf << [value_node, RDF::URI.new(RDF::OT.value), RDF::Literal.new(value)]
+ end
+ end
+ super()
+ end
+
+ end
end
end
diff --git a/lib/error.rb b/lib/error.rb
index 64b0fb1..51451e7 100644
--- a/lib/error.rb
+++ b/lib/error.rb
@@ -10,7 +10,7 @@ class RuntimeError
$logger.error "\n"+self.to_turtle
end
- # define to_ and self.from_ methods for various rdf formats
+ # define to_ methods for all RuntimeErrors and various rdf formats
RDF_FORMATS.each do |format|
send :define_method, "to_#{format}".to_sym do
@@ -22,7 +22,7 @@ class RuntimeError
subject = RDF::Node.new
writer << [subject, RDF.type, RDF::OT.ErrorReport]
writer << [subject, RDF::OT.actor, @uri.to_s]
- writer << [subject, RDF::OT.message, @message.to_s]
+ writer << [subject, RDF::OT.message, message.to_s]
writer << [subject, RDF::OT.statusCode, @http_code]
writer << [subject, RDF::OT.errorCode, self.class.to_s]
@@ -80,7 +80,6 @@ module OpenTox
class RestCallError < Error
attr_accessor :request#, :response
def initialize message, request, uri
- #def initialize request, response, message
@request = request
#@response = response
super 502, message, uri
diff --git a/lib/opentox-client.rb b/lib/opentox-client.rb
index 8c19225..ad7d3cc 100644
--- a/lib/opentox-client.rb
+++ b/lib/opentox-client.rb
@@ -2,6 +2,7 @@ require 'rubygems'
require "bundler/setup"
require 'rdf'
require 'rdf/raptor'
+require 'rdf/n3'
require "rest-client"
require 'uri'
require 'yaml'
@@ -14,6 +15,7 @@ require "securerandom"
RDF::OT = RDF::Vocabulary.new 'http://www.opentox.org/api/1.2#'
RDF::OT1 = RDF::Vocabulary.new 'http://www.opentox.org/api/1.1#'
RDF::OTA = RDF::Vocabulary.new 'http://www.opentox.org/algorithmTypes.owl#'
+RDF::OLO = RDF::Vocabulary.new 'http://purl.org/ontology/olo/core#'
CLASSES = ["Generic", "Compound", "Feature", "Dataset", "Algorithm", "Model", "Validation", "Task", "Investigation"]
RDF_FORMATS = [:rdfxml,:ntriples,:turtle]
diff --git a/lib/opentox.rb b/lib/opentox.rb
index b0c786a..9225bb0 100644
--- a/lib/opentox.rb
+++ b/lib/opentox.rb
@@ -14,7 +14,14 @@ module OpenTox
# @return [OpenTox] OpenTox object
def initialize uri=nil, subjectid=nil
@rdf = RDF::Graph.new
- uri ? @uri = uri.to_s.chomp : @uri = RDF::Node.uuid.to_s
+ if uri
+ @uri = uri.to_s.chomp
+ else
+ service = self.class.to_s.split('::').last.downcase
+ service_uri = eval("$#{service}[:uri]")
+ bad_request_error "$#{service}[:uri] variable not set. Please set $#{service}[:uri] or use an explicit uri as first constructor argument " unless service_uri
+ @uri = File.join service_uri, SecureRandom.uuid
+ end
append RDF.type, eval("RDF::OT."+self.class.to_s.split('::').last)
append RDF::DC.date, DateTime.now
@subjectid = subjectid
@@ -24,7 +31,6 @@ module OpenTox
# @return [Hash] Object metadata
def metadata
# return plain strings instead of RDF objects
- #puts @rdf.to_hash
@rdf.to_hash[RDF::URI.new(@uri)].inject({}) { |h, (predicate, values)| h[predicate.to_s] = values.collect{|v| v.to_s}; h }
end
@@ -32,6 +38,7 @@ module OpenTox
# @param [String] Predicate URI
# @return [Array, String] Predicate value(s)
def [](predicate)
+ return nil if metadata[predicate.to_s].nil?
metadata[predicate.to_s].size == 1 ? metadata[predicate.to_s].first : metadata[predicate.to_s]
end
@@ -55,30 +62,30 @@ module OpenTox
# Get object from webservice
def get
parse_ntriples RestClientWrapper.get(@uri,{},{:accept => "text/plain", :subjectid => @subjectid})
- rescue # fall back to rdfxml
- parse_rdfxml RestClientWrapper.get(@uri,{},{:accept => "application/rdf+xml", :subjectid => @subjectid})
+ #rescue # fall back to rdfxml
+ #parse_rdfxml RestClientWrapper.get(@uri,{},{:accept => "application/rdf+xml", :subjectid => @subjectid})
end
# Post object to webservice
def post service_uri
RestClientWrapper.post service_uri, to_ntriples, { :content_type => "text/plain", :subjectid => @subjectid}
- rescue # fall back to rdfxml
- RestClientWrapper.post service_uri, to_rdfxml, { :content_type => "application/rdf+xml", :subjectid => @subjectid}
+ #rescue # fall back to rdfxml
+ #RestClientWrapper.post service_uri, to_rdfxml, { :content_type => "application/rdf+xml", :subjectid => @subjectid}
end
# Save object at webservice
def put
append RDF::DC.modified, DateTime.now
- begin
+ #begin
RestClientWrapper.put @uri.to_s, self.to_ntriples, { :content_type => "text/plain", :subjectid => @subjectid}
- rescue # fall back to rdfxml
- RestClientWrapper.put @uri.to_s, self.to_rdfxml, { :content_type => "application/rdf+xml", :subjectid => @subjectid}
- end
+ #rescue # fall back to rdfxml
+ #RestClientWrapper.put @uri.to_s, self.to_rdfxml, { :content_type => "application/rdf+xml", :subjectid => @subjectid}
+ #end
end
# Delete object at webservice
def delete
- @response = RestClientWrapper.delete(@uri.to_s,nil,{:subjectid => @subjectid})
+ RestClientWrapper.delete(@uri.to_s,nil,{:subjectid => @subjectid})
end
RDF_FORMATS.each do |format|
@@ -100,42 +107,20 @@ module OpenTox
end
end
- # class methods
- module ClassMethods
-
- def all service_uri, subjectid=nil
- uris = RestClientWrapper.get(service_uri, {}, :accept => 'text/uri-list').split("\n").compact
- uris.collect{|uri| URI.task?(service_uri) ? from_uri(uri, subjectid, false) : from_uri(uri, subjectid)}
+ def to_turtle # redefine to use prefixes (not supported by RDF::Writer)
+ prefixes = {:rdf => "http://www.w3.org/1999/02/22-rdf-syntax-ns#"}
+ ['OT', 'DC', 'XSD', 'OLO'].each{|p| prefixes[p.downcase.to_sym] = eval("RDF::#{p}.to_s") }
+ turtle = RDF::N3::Writer.for(:turtle).buffer(:prefixes => prefixes) do |writer|
+ @rdf.each{|statement| writer << statement}
end
+ end
- def from_file service_uri, filename, subjectid=nil
- file = File.new filename
- # sdf files are incorrectly detected
- file.mime_type = "chemical/x-mdl-sdfile" if File.extname(filename) == ".sdf"
- from_uri RestClientWrapper.post(service_uri, {:file => file}, {:subjectid => subjectid, :content_type => file.mime_type, :accept => "text/uri-list"}), subjectid
+ {:title => RDF::DC.title, :dexcription => RDF::DC.description}.each do |method,predicate|
+ send :define_method, method do
+ self.[](predicate)
end
-
- private
- def from_uri uri, subjectid=nil, wait=true
-
- uri.chomp!
- # TODO add waiting task
- if URI.task?(uri) and wait
- t = OpenTox::Task.new(uri)
- t.wait
- uri = t.resultURI
- end
-
- # guess class from uri, this is potentially unsafe, but polling metadata from large uri lists is way too slow (and not all service provide RDF.type in their metadata)
- result = CLASSES.collect{|s| s if uri =~ /#{s.downcase}/}.compact
- if result.size == 1
- klass = result.first
- else
- klass = OpenTox::Generic.new(uri)[RDF.type]
- internal_server_error "Cannot determine class from URI '#{uri} (Candidate classes are #{result.inspect}) or matadata." unless klass
- end
- # initialize with/without subjectid
- subjectid ? eval("#{self}.new(\"#{uri}\", \"#{subjectid}\")") : eval("#{self}.new(\"#{uri}\")")
+ send :define_method, "#{method}=" do |value|
+ self.[]=(predicate,value)
end
end
@@ -143,7 +128,12 @@ module OpenTox
CLASSES.each do |klass|
c = Class.new do
include OpenTox
- extend OpenTox::ClassMethods
+ #extend OpenTox::ClassMethods
+
+ def self.all service_uri, subjectid=nil
+ uris = RestClientWrapper.get(service_uri, {}, :accept => 'text/uri-list').split("\n").compact
+ uris.collect{|uri| self.new(uri, subjectid)}
+ end
end
OpenTox.const_set klass,c
end
--
cgit v1.2.3
From 66dae77b92308bb09781948ad4caf90b770d1ef8 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Fri, 13 Jul 2012 12:24:37 +0200
Subject: wait for tasks in post/put requests
---
lib/dataset.rb | 6 +++---
lib/opentox.rb | 8 +++++---
lib/task.rb | 6 +++---
3 files changed, 11 insertions(+), 9 deletions(-)
(limited to 'lib')
diff --git a/lib/dataset.rb b/lib/dataset.rb
index ed0ccdd..a6c22d0 100644
--- a/lib/dataset.rb
+++ b/lib/dataset.rb
@@ -13,9 +13,9 @@ module OpenTox
append RDF.type, RDF::OT.OrderedDataset
end
- def upload filename
- file = File.new filename
- RestClientWrapper.put(@uri, {:file => file}, {:subjectid => @subjectid})
+ def upload filename, wait=true
+ uri = RestClientWrapper.put(@uri, {:file => File.new(filename)}, {:subjectid => @subjectid})
+ OpenTox::Task.new(uri).wait if URI.task?(uri) and wait
end
def get
diff --git a/lib/opentox.rb b/lib/opentox.rb
index 9225bb0..019699b 100644
--- a/lib/opentox.rb
+++ b/lib/opentox.rb
@@ -67,20 +67,22 @@ module OpenTox
end
# Post object to webservice
- def post service_uri
- RestClientWrapper.post service_uri, to_ntriples, { :content_type => "text/plain", :subjectid => @subjectid}
+ def post service_uri, wait=true
+ uri = RestClientWrapper.post service_uri, to_ntriples, { :content_type => "text/plain", :subjectid => @subjectid}
+ OpenTox::Task.new(uri).wait if URI.task?(uri) and wait
#rescue # fall back to rdfxml
#RestClientWrapper.post service_uri, to_rdfxml, { :content_type => "application/rdf+xml", :subjectid => @subjectid}
end
# Save object at webservice
- def put
+ def put wait=true
append RDF::DC.modified, DateTime.now
#begin
RestClientWrapper.put @uri.to_s, self.to_ntriples, { :content_type => "text/plain", :subjectid => @subjectid}
#rescue # fall back to rdfxml
#RestClientWrapper.put @uri.to_s, self.to_rdfxml, { :content_type => "application/rdf+xml", :subjectid => @subjectid}
#end
+ OpenTox::Task.new(uri).wait if URI.task?(uri) and wait
end
# Delete object at webservice
diff --git a/lib/task.rb b/lib/task.rb
index f3f7f6b..4f446b7 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -12,7 +12,7 @@ module OpenTox
task = Task.new uri, subjectid
task[RDF::OT.hasStatus] = "Running"
params.each { |k,v| task[k] = v }
- task.put
+ task.put false
pid = fork do
begin
result_uri = yield
@@ -61,13 +61,13 @@ module OpenTox
def cancel
kill
self.[]=(RDF::OT.hasStatus, "Cancelled")
- put
+ put false
end
def completed(uri)
self.[]=(RDF::OT.resultURI, uri)
self.[]=(RDF::OT.hasStatus, "Completed")
- put
+ put false
end
# waits for a task, unless time exceeds or state is no longer running
--
cgit v1.2.3
From a214c802868e05a5ea90a03c894cf7ef0206da28 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Fri, 13 Jul 2012 12:30:41 +0200
Subject: wait for tasks also in get requests
---
lib/opentox.rb | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
(limited to 'lib')
diff --git a/lib/opentox.rb b/lib/opentox.rb
index 019699b..2e0f05a 100644
--- a/lib/opentox.rb
+++ b/lib/opentox.rb
@@ -60,8 +60,13 @@ module OpenTox
end
# Get object from webservice
- def get
- parse_ntriples RestClientWrapper.get(@uri,{},{:accept => "text/plain", :subjectid => @subjectid})
+ def get wait=true
+ response = RestClientWrapper.get(@uri,{},{:accept => "text/plain", :subjectid => @subjectid})
+ if URI.task?(response) and wait
+ t = OpenTox::Task.new(uri).wait
+ response = RestClientWrapper.get(t.resultURI,{},{:accept => "text/plain", :subjectid => @subjectid})
+ end
+ parse_ntriples response
#rescue # fall back to rdfxml
#parse_rdfxml RestClientWrapper.get(@uri,{},{:accept => "application/rdf+xml", :subjectid => @subjectid})
end
--
cgit v1.2.3
From 095decd233ac6d138a412c459735c1376cf25958 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Fri, 13 Jul 2012 13:28:06 +0200
Subject: duplicates method for Enumerable
---
lib/overwrite.rb | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
(limited to 'lib')
diff --git a/lib/overwrite.rb b/lib/overwrite.rb
index fa2128a..137fec8 100644
--- a/lib/overwrite.rb
+++ b/lib/overwrite.rb
@@ -10,13 +10,11 @@ class Object
end
end
-=begin
module Enumerable
def duplicates
- inject({}) {|h,v| h[v] += 1; h}.reject{|k,v| v==1}.keys
+ inject({}) {|h,v| h[v]=h[v].to_i+1; h}.reject{|k,v| v==1}.keys
end
end
-=end
class String
def underscore
--
cgit v1.2.3
From 76144341d800cec80cbb063b8c1acf6da19fad5d Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Fri, 13 Jul 2012 17:12:44 +0200
Subject: csv handling of empty cells fixed
---
lib/dataset.rb | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
(limited to 'lib')
diff --git a/lib/dataset.rb b/lib/dataset.rb
index a6c22d0..e0f2d5a 100644
--- a/lib/dataset.rb
+++ b/lib/dataset.rb
@@ -18,6 +18,15 @@ module OpenTox
OpenTox::Task.new(uri).wait if URI.task?(uri) and wait
end
+ def to_csv
+ CSV.generate do |csv|
+ csv << ["SMILES"] + @features.collect{|f| f.title}
+ @compounds.each_with_index do |c,i|
+ csv << [c.to_smiles] + @data_entries[i]
+ end
+ end
+ end
+
def get
super
@features = []
@@ -47,9 +56,9 @@ module OpenTox
pattern [:values, RDF::OT.value, :value]
end
values = query.execute(@rdf).sort_by{|s| s.feature_idx}.collect do |s|
- numeric_features[s.feature_idx] ? s.value.to_s.to_f : s.value.to_s
+ (numeric_features[s.feature_idx] and s.value.to_s != "") ? s.value.to_s.to_f : s.value.to_s
end
- @data_entries << values
+ @data_entries << values.collect{|v| v == "" ? nil : v}
end
else
query = RDF::Query.new do
@@ -71,7 +80,7 @@ module OpenTox
pattern [:values, RDF::OT.value, :value]
end
value = query.execute(@rdf).first.value.to_s
- value = value.to_f if numeric_features[i]
+ value = value.to_f if numeric_features[i] and !value.nil?
values << value
end
@data_entries << values
--
cgit v1.2.3
From 81f0924c654875a738b646ad951a28f906e0a97c Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Wed, 18 Jul 2012 09:59:21 +0200
Subject: rest call error handling fixed
---
lib/error.rb | 4 +++-
lib/overwrite.rb | 1 -
lib/rest-client-wrapper.rb | 24 +++++++++++++++++++++++-
3 files changed, 26 insertions(+), 3 deletions(-)
(limited to 'lib')
diff --git a/lib/error.rb b/lib/error.rb
index 51451e7..3017c7f 100644
--- a/lib/error.rb
+++ b/lib/error.rb
@@ -33,7 +33,6 @@ class RuntimeError
cut_index -= 1
cut_index = backtrace.size-1 if cut_index < 0
details = backtrace[0..cut_index].join("\n")
- details += "REST paramenters:\n#{@request.args.inspect}" if @request
writer << [subject, RDF::OT.errorCause, details]
end
rdf
@@ -59,6 +58,7 @@ module OpenTox
"LockedError" => 423,
"InternalServerError" => 500,
"NotImplementedError" => 501,
+ "RestCallError" => 501,
"ServiceUnavailableError" => 503,
"TimeOutError" => 504,
}.each do |klass,code|
@@ -76,6 +76,7 @@ module OpenTox
end
end
+=begin
# Errors received from RestClientWrapper calls
class RestCallError < Error
attr_accessor :request#, :response
@@ -85,5 +86,6 @@ module OpenTox
super 502, message, uri
end
end
+=end
end
diff --git a/lib/overwrite.rb b/lib/overwrite.rb
index 137fec8..0a55ce2 100644
--- a/lib/overwrite.rb
+++ b/lib/overwrite.rb
@@ -93,4 +93,3 @@ module Kernel
end
end
-
diff --git a/lib/rest-client-wrapper.rb b/lib/rest-client-wrapper.rb
index 5707831..e89c90d 100644
--- a/lib/rest-client-wrapper.rb
+++ b/lib/rest-client-wrapper.rb
@@ -42,8 +42,30 @@ module OpenTox
@response = @request.execute do |response, request, result|
if [301, 302, 307].include? response.code and request.method == :get
response.follow_redirection(request, result)
+ elsif response.code >= 400 and !URI.task?(uri)
+ message = response.to_s
+ message += "\nREST paramenters:\n#{request.args.inspect}"
+ case response.code
+ when 400
+ bad_request_error message, uri
+ when 401
+ not_authorized_error message, uri
+ when 404
+ not_found_error message, uri
+ when 433
+ locked_error message, uri
+ when 500
+ internal_server_error message, uri
+ when 501
+ not_implemented_error message, uri
+ when 503
+ service_unavailable_error message, uri
+ when 504
+ time_out_error message, uri
+ else
+ rest_call_error message, uri
+ end
else
- raise OpenTox::RestCallError.new response.to_s, request, uri unless response.code < 400 or URI.task? uri
response
end
end
--
cgit v1.2.3
From b3d32c18947b659dfa98b066931fb8912f7dc102 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Wed, 18 Jul 2012 16:27:21 +0200
Subject: dataset-large tests pass
---
lib/error.rb | 12 ------------
lib/opentox.rb | 37 +++++++++++++++++++++++--------------
lib/overwrite.rb | 4 ++--
3 files changed, 25 insertions(+), 28 deletions(-)
(limited to 'lib')
diff --git a/lib/error.rb b/lib/error.rb
index 3017c7f..d1abe52 100644
--- a/lib/error.rb
+++ b/lib/error.rb
@@ -76,16 +76,4 @@ module OpenTox
end
end
-=begin
- # Errors received from RestClientWrapper calls
- class RestCallError < Error
- attr_accessor :request#, :response
- def initialize message, request, uri
- @request = request
- #@response = response
- super 502, message, uri
- end
- end
-=end
-
end
diff --git a/lib/opentox.rb b/lib/opentox.rb
index 2e0f05a..825531c 100644
--- a/lib/opentox.rb
+++ b/lib/opentox.rb
@@ -60,34 +60,29 @@ module OpenTox
end
# Get object from webservice
- def get wait=true
+ def get
+ # TODO: RDFXML
response = RestClientWrapper.get(@uri,{},{:accept => "text/plain", :subjectid => @subjectid})
- if URI.task?(response) and wait
- t = OpenTox::Task.new(uri).wait
+ if URI.task?(response)
+ wait_for_task response
response = RestClientWrapper.get(t.resultURI,{},{:accept => "text/plain", :subjectid => @subjectid})
end
parse_ntriples response
- #rescue # fall back to rdfxml
- #parse_rdfxml RestClientWrapper.get(@uri,{},{:accept => "application/rdf+xml", :subjectid => @subjectid})
end
# Post object to webservice
def post service_uri, wait=true
+ # TODO: RDFXML
uri = RestClientWrapper.post service_uri, to_ntriples, { :content_type => "text/plain", :subjectid => @subjectid}
- OpenTox::Task.new(uri).wait if URI.task?(uri) and wait
- #rescue # fall back to rdfxml
- #RestClientWrapper.post service_uri, to_rdfxml, { :content_type => "application/rdf+xml", :subjectid => @subjectid}
+ wait_for_task uri if wait
end
# Save object at webservice
def put wait=true
+ # TODO: RDFXML
append RDF::DC.modified, DateTime.now
- #begin
- RestClientWrapper.put @uri.to_s, self.to_ntriples, { :content_type => "text/plain", :subjectid => @subjectid}
- #rescue # fall back to rdfxml
- #RestClientWrapper.put @uri.to_s, self.to_rdfxml, { :content_type => "application/rdf+xml", :subjectid => @subjectid}
- #end
- OpenTox::Task.new(uri).wait if URI.task?(uri) and wait
+ uri = RestClientWrapper.put @uri.to_s, self.to_ntriples, { :content_type => "text/plain", :subjectid => @subjectid}
+ wait_for_task uri if wait
end
# Delete object at webservice
@@ -95,6 +90,20 @@ module OpenTox
RestClientWrapper.delete(@uri.to_s,nil,{:subjectid => @subjectid})
end
+ def wait_for_task uri
+ if URI.task?(uri)
+ t = OpenTox::Task.new uri
+ t.wait
+ if t.completed?
+ uri = t.resultURI
+ else
+ #TODO raise correct error
+ internal_server_error "Task #{uri} failed with #{$!.inspect}"
+ end
+ end
+ uri
+ end
+
RDF_FORMATS.each do |format|
# rdf parse methods for all formats e.g. parse_rdfxml
diff --git a/lib/overwrite.rb b/lib/overwrite.rb
index 0a55ce2..785fbcd 100644
--- a/lib/overwrite.rb
+++ b/lib/overwrite.rb
@@ -86,10 +86,10 @@ module Kernel
stdout = stdout_stream.read
stderr = stderr_stream.read
end
- internal_server_error "`" + cmd + "` failed.\n" + stdout + stderr if !status.success?
+ internal_server_error "`" + cmd + "` failed.\n" + stdout + stderr unless status.success?
return stdout
rescue
- internal_server_error $!.message
+ internal_server_error $!.message
end
end
--
cgit v1.2.3
From 2aa0cf90210d179f802c6755298217380543b70c Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Wed, 18 Jul 2012 19:20:38 +0200
Subject: toxbank policy tests pass
---
lib/opentox.rb | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
(limited to 'lib')
diff --git a/lib/opentox.rb b/lib/opentox.rb
index 825531c..800874f 100644
--- a/lib/opentox.rb
+++ b/lib/opentox.rb
@@ -60,14 +60,14 @@ module OpenTox
end
# Get object from webservice
- def get
- # TODO: RDFXML
- response = RestClientWrapper.get(@uri,{},{:accept => "text/plain", :subjectid => @subjectid})
+ def get mime_type="text/plain"
+ response = RestClientWrapper.get(@uri,{},{:accept => mime_type, :subjectid => @subjectid})
if URI.task?(response)
wait_for_task response
- response = RestClientWrapper.get(t.resultURI,{},{:accept => "text/plain", :subjectid => @subjectid})
+ response = RestClientWrapper.get(t.resultURI,{},{:accept => mime_type, :subjectid => @subjectid})
end
- parse_ntriples response
+ parse_ntriples response if mime_type == "text/plain"
+ parse_rdfxml response if mime_type == "application/rdf+xml"
end
# Post object to webservice
--
cgit v1.2.3
From 65c67111098ba37171ac12f6215c20c2a321d1de Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Wed, 18 Jul 2012 21:37:21 +0200
Subject: code cleanup in opentox.rb
---
lib/opentox.rb | 1 -
1 file changed, 1 deletion(-)
(limited to 'lib')
diff --git a/lib/opentox.rb b/lib/opentox.rb
index 800874f..d3b73fb 100644
--- a/lib/opentox.rb
+++ b/lib/opentox.rb
@@ -144,7 +144,6 @@ module OpenTox
CLASSES.each do |klass|
c = Class.new do
include OpenTox
- #extend OpenTox::ClassMethods
def self.all service_uri, subjectid=nil
uris = RestClientWrapper.get(service_uri, {}, :accept => 'text/uri-list').split("\n").compact
--
cgit v1.2.3
From fc0397cd0d51df4fe7c23f601c2f211c2ebfbf77 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Thu, 26 Jul 2012 16:23:44 +0200
Subject: parameter settting for algorithms and models
---
lib/model.rb | 5 +++--
lib/opentox-client.rb | 24 ++++++++++++++----------
lib/opentox.rb | 30 +++++++++++++++++++++++++++++-
3 files changed, 46 insertions(+), 13 deletions(-)
(limited to 'lib')
diff --git a/lib/model.rb b/lib/model.rb
index 95aa9ff..c104e64 100644
--- a/lib/model.rb
+++ b/lib/model.rb
@@ -6,8 +6,9 @@ module OpenTox
# @param [Hash] params Parameters for OpenTox model
# @param [optional,OpenTox::Task] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
# @return [text/uri-list] Task or resource URI
- def run params=nil
- post params, {:accept => 'text/uri-list'}
+ def run params=nil, wait=true
+ uri = RestClientWrapper.post @uri, params, { :content_type => "text/uri-list", :subjectid => @subjectid}
+ wait_for_task uri if wait
end
end
diff --git a/lib/opentox-client.rb b/lib/opentox-client.rb
index ad7d3cc..276d378 100644
--- a/lib/opentox-client.rb
+++ b/lib/opentox-client.rb
@@ -24,13 +24,17 @@ RDF_FORMATS = [:rdfxml,:ntriples,:turtle]
TRUE_REGEXP = /^(true|active|1|1.0|tox|activating|carcinogen|mutagenic)$/i
FALSE_REGEXP = /^(false|inactive|0|0.0|low tox|deactivating|non-carcinogen|non-mutagenic)$/i
-require File.join(File.dirname(__FILE__),"overwrite.rb")
-require File.join(File.dirname(__FILE__),"error.rb")
-require File.join(File.dirname(__FILE__),"rest-client-wrapper.rb")
-require File.join(File.dirname(__FILE__),"authorization.rb")
-require File.join(File.dirname(__FILE__),"policy.rb")
-require File.join(File.dirname(__FILE__),"otlogger.rb") # avoid require conflicts with logger
-require File.join(File.dirname(__FILE__),"opentox.rb")
-require File.join(File.dirname(__FILE__),"task.rb")
-require File.join(File.dirname(__FILE__),"compound.rb")
-require File.join(File.dirname(__FILE__),"dataset.rb")
+[
+ "overwrite.rb",
+ "error.rb",
+ "rest-client-wrapper.rb",
+ "authorization.rb",
+ "policy.rb",
+ "otlogger.rb",
+ "opentox.rb",
+ "task.rb",
+ "compound.rb",
+ "dataset.rb",
+ "model.rb",
+].each{ |f| require File.join(File.dirname(__FILE__),f) }
+
diff --git a/lib/opentox.rb b/lib/opentox.rb
index d3b73fb..2c4578f 100644
--- a/lib/opentox.rb
+++ b/lib/opentox.rb
@@ -50,6 +50,30 @@ module OpenTox
append predicate.to_s, values
end
+ def parameters
+ params = {}
+ query = RDF::Query.new({
+ :parameter => {
+ RDF.type => RDF::OT.Parameter,
+ :property => :value,
+ }
+ })
+ query.execute(@rdf).each do |solution|
+ params[solution.parameter] = {} unless params[solution.parameter]
+ params[solution.parameter][solution.property.to_s] = solution.value.to_s
+ end
+ params.values
+ end
+
+ def parameters=(parameters)
+ parameters.each do |param|
+ p_node = RDF::Node.new
+ @rdf << [RDF::URI.new(@uri), RDF::OT.parameters, p_node]
+ @rdf << [p_node, RDF.type, RDF::OT.Parameter]
+ param.each{ |p,o| @rdf << [p_node, p, o] }
+ end
+ end
+
# Append object metadata
# @param [String] Predicate URI
# @param [Array, String] Predicate value(s)
@@ -131,7 +155,11 @@ module OpenTox
end
end
- {:title => RDF::DC.title, :dexcription => RDF::DC.description}.each do |method,predicate|
+ {
+ :title => RDF::DC.title,
+ :dexcription => RDF::DC.description,
+ :type => RDF.type
+ }.each do |method,predicate|
send :define_method, method do
self.[](predicate)
end
--
cgit v1.2.3
From 32ad3c8f6e1e16cfe9fd59a47df6b560ffb13ddd Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Wed, 1 Aug 2012 14:56:08 +0200
Subject: task error handling improved
---
lib/compound.rb | 2 +-
lib/error.rb | 56 +++++++++++++++++++++++++---------------------
lib/opentox.rb | 12 +++++-----
lib/rest-client-wrapper.rb | 6 ++---
lib/task.rb | 17 ++++++++++++--
5 files changed, 55 insertions(+), 38 deletions(-)
(limited to 'lib')
diff --git a/lib/compound.rb b/lib/compound.rb
index 5992ee3..7d84a3c 100644
--- a/lib/compound.rb
+++ b/lib/compound.rb
@@ -83,7 +83,7 @@ module OpenTox
begin
RestClientWrapper.get("#{CACTUS_URI}#{to_inchi}/names").split("\n")
rescue
- "not available"
+ "CACTVS service not responding."
end
end
diff --git a/lib/error.rb b/lib/error.rb
index d1abe52..84918b7 100644
--- a/lib/error.rb
+++ b/lib/error.rb
@@ -7,43 +7,49 @@ class RuntimeError
super message
@uri = uri
@http_code ||= 500
- $logger.error "\n"+self.to_turtle
+ @rdf = RDF::Graph.new
+ subject = RDF::Node.new
+ @rdf << [subject, RDF.type, RDF::OT.ErrorReport]
+ @rdf << [subject, RDF::OT.actor, @uri.to_s]
+ @rdf << [subject, RDF::OT.message, message.to_s]
+ @rdf << [subject, RDF::OT.statusCode, @http_code]
+ @rdf << [subject, RDF::OT.errorCode, self.class.to_s]
+ @rdf << [subject, RDF::OT.errorCause, short_backtrace]
+ $logger.error("\n"+self.to_turtle)
end
- # define to_ methods for all RuntimeErrors and various rdf formats
- RDF_FORMATS.each do |format|
+ def short_backtrace
+ backtrace = caller.collect{|line| line unless line =~ /#{File.dirname(__FILE__)}/}.compact
+ cut_index = backtrace.find_index{|line| line.match /sinatra|minitest/}
+ cut_index ||= backtrace.size
+ cut_index -= 1
+ cut_index = backtrace.size-1 if cut_index < 0
+ backtrace[0..cut_index].join("\n")
+ end
+ RDF_FORMATS.each do |format|
+ # rdf serialization methods for all formats e.g. to_rdfxml
send :define_method, "to_#{format}".to_sym do
- rdf = RDF::Writer.for(format).buffer do |writer|
- # TODO: not used for turtle
- # http://rdf.rubyforge.org/RDF/Writer.html#
- writer.prefix :ot, RDF::URI('http://www.opentox.org/api/1.2#')
- writer.prefix :ot1_1, RDF::URI('http://www.opentox.org/api/1.1#')
- subject = RDF::Node.new
- writer << [subject, RDF.type, RDF::OT.ErrorReport]
- writer << [subject, RDF::OT.actor, @uri.to_s]
- writer << [subject, RDF::OT.message, message.to_s]
- writer << [subject, RDF::OT.statusCode, @http_code]
- writer << [subject, RDF::OT.errorCode, self.class.to_s]
-
- # cut backtrace
- backtrace = caller.collect{|line| line unless line =~ /#{File.dirname(__FILE__)}/}.compact
- cut_index = backtrace.find_index{|line| line.match /sinatra|minitest/}
- cut_index ||= backtrace.size
- cut_index -= 1
- cut_index = backtrace.size-1 if cut_index < 0
- details = backtrace[0..cut_index].join("\n")
- writer << [subject, RDF::OT.errorCause, details]
+ RDF::Writer.for(format).buffer do |writer|
+ @rdf.each{|statement| writer << statement}
end
- rdf
end
+ end
+ def to_turtle # redefine to use prefixes (not supported by RDF::Writer)
+ prefixes = {:rdf => "http://www.w3.org/1999/02/22-rdf-syntax-ns#"}
+ ['OT', 'DC', 'XSD', 'OLO'].each{|p| prefixes[p.downcase.to_sym] = eval("RDF::#{p}.to_s") }
+ RDF::N3::Writer.for(:turtle).buffer(:prefixes => prefixes) do |writer|
+ @rdf.each{|statement| writer << statement}
+ end
end
+
end
module OpenTox
class Error < RuntimeError
+
def initialize code, message, uri=nil
@http_code = code
super message, uri
@@ -72,7 +78,7 @@ module OpenTox
# define global methods for raising errors, eg. bad_request_error
Object.send(:define_method, klass.underscore.to_sym) do |message,uri=nil|
- raise c, message, uri
+ raise c.new(message, uri)
end
end
diff --git a/lib/opentox.rb b/lib/opentox.rb
index 2c4578f..80644db 100644
--- a/lib/opentox.rb
+++ b/lib/opentox.rb
@@ -118,12 +118,11 @@ module OpenTox
if URI.task?(uri)
t = OpenTox::Task.new uri
t.wait
- if t.completed?
- uri = t.resultURI
- else
+ unless t.completed?
#TODO raise correct error
- internal_server_error "Task #{uri} failed with #{$!.inspect}"
+ #internal_server_error "Task #{uri} failed with #{$!.inspect}"
end
+ uri = t.resultURI
end
uri
end
@@ -140,17 +139,16 @@ module OpenTox
# rdf serialization methods for all formats e.g. to_rdfxml
send :define_method, "to_#{format}".to_sym do
- rdf = RDF::Writer.for(format).buffer do |writer|
+ RDF::Writer.for(format).buffer do |writer|
@rdf.each{|statement| writer << statement}
end
- rdf
end
end
def to_turtle # redefine to use prefixes (not supported by RDF::Writer)
prefixes = {:rdf => "http://www.w3.org/1999/02/22-rdf-syntax-ns#"}
['OT', 'DC', 'XSD', 'OLO'].each{|p| prefixes[p.downcase.to_sym] = eval("RDF::#{p}.to_s") }
- turtle = RDF::N3::Writer.for(:turtle).buffer(:prefixes => prefixes) do |writer|
+ RDF::N3::Writer.for(:turtle).buffer(:prefixes => prefixes) do |writer|
@rdf.each{|statement| writer << statement}
end
end
diff --git a/lib/rest-client-wrapper.rb b/lib/rest-client-wrapper.rb
index e89c90d..387a01b 100644
--- a/lib/rest-client-wrapper.rb
+++ b/lib/rest-client-wrapper.rb
@@ -17,9 +17,9 @@ module OpenTox
# check input
@subjectid = headers[:subjectid] ? headers[:subjectid] : nil
- bad_request_error "Invalid URI: '#{uri}'" unless URI.valid? uri
- #not_found_error "URI '#{uri}' not found." unless URI.accessible?(uri, @subjectid) unless URI.ssl?(uri)
- bad_request_error "Headers are not a hash: #{headers.inspect}" unless headers==nil or headers.is_a?(Hash)
+ bad_request_error "Invalid URI: '#{uri}'", uri unless URI.valid? uri
+ #not_found_error "URI '#{uri}' not found.", uri unless URI.accessible?(uri, @subjectid) unless URI.ssl?(uri)
+ bad_request_error "Headers are not a hash: #{headers.inspect}", uri unless headers==nil or headers.is_a?(Hash)
# make sure that no header parameters are set in the payload
[:accept,:content_type,:subjectid].each do |header|
if defined? $aa || URI(uri).host == URI($aa[:uri]).host
diff --git a/lib/task.rb b/lib/task.rb
index 0b0aea2..42bc84b 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -47,7 +47,7 @@ module OpenTox
def kill
Process.kill(9,@pid)
Process.kill(9,@observer_pid)
- rescue # no need to raise an exeption if processes are not running
+ rescue # no need to raise an exception if processes are not running
end
def description
@@ -82,7 +82,6 @@ module OpenTox
dur = [[(Time.new - start_time)/20.0,0.3].max,300.0].min
time_out_error "max wait time exceeded ("+DEFAULT_TASK_MAX_DURATION.to_s+"sec), task: '"+@uri.to_s+"'" if (Time.new > due_to_time)
end
- get
end
end
@@ -114,6 +113,20 @@ module OpenTox
end
end
+ def error_report
+ report = {}
+ query = RDF::Query.new({
+ :report => {
+ RDF.type => RDF::OT.ErrorReport,
+ :property => :value,
+ }
+ })
+ query.execute(@rdf).each do |solution|
+ report[solution.property] = solution.value.to_s
+ end
+ report
+ end
+
#TODO: subtasks (only for progress)
end
--
cgit v1.2.3
From 75b1d2a98c17d8ef86c3a7a974e1be5444c9fb20 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Thu, 2 Aug 2012 23:33:11 +0200
Subject: error handling improved
---
lib/error.rb | 22 ++++++----------------
lib/opentox-client.rb | 2 +-
lib/rest-client-wrapper.rb | 43 ++++++++++++++++++++-----------------------
3 files changed, 27 insertions(+), 40 deletions(-)
(limited to 'lib')
diff --git a/lib/error.rb b/lib/error.rb
index 84918b7..e58ed5d 100644
--- a/lib/error.rb
+++ b/lib/error.rb
@@ -5,12 +5,12 @@ class RuntimeError
attr_accessor :http_code, :uri
def initialize message, uri=nil
super message
- @uri = uri
+ @uri = uri.to_s.sub(%r{//.*:.*@},'//') # remove credentials from uri
@http_code ||= 500
@rdf = RDF::Graph.new
subject = RDF::Node.new
@rdf << [subject, RDF.type, RDF::OT.ErrorReport]
- @rdf << [subject, RDF::OT.actor, @uri.to_s]
+ @rdf << [subject, RDF::OT.actor, @uri]
@rdf << [subject, RDF::OT.message, message.to_s]
@rdf << [subject, RDF::OT.statusCode, @http_code]
@rdf << [subject, RDF::OT.errorCode, self.class.to_s]
@@ -57,27 +57,17 @@ module OpenTox
end
# OpenTox errors
- {
- "BadRequestError" => 400,
- "NotAuthorizedError" => 401,
- "NotFoundError" => 404,
- "LockedError" => 423,
- "InternalServerError" => 500,
- "NotImplementedError" => 501,
- "RestCallError" => 501,
- "ServiceUnavailableError" => 503,
- "TimeOutError" => 504,
- }.each do |klass,code|
+ RestClientWrapper.known_errors.each do |error|
# create error classes
c = Class.new Error do
define_method :initialize do |message, uri=nil|
- super code, message, uri
+ super error[:code], message, uri
end
end
- OpenTox.const_set klass,c
+ OpenTox.const_set error[:class],c
# define global methods for raising errors, eg. bad_request_error
- Object.send(:define_method, klass.underscore.to_sym) do |message,uri=nil|
+ Object.send(:define_method, error[:method]) do |message,uri=nil|
raise c.new(message, uri)
end
end
diff --git a/lib/opentox-client.rb b/lib/opentox-client.rb
index 276d378..5f5a106 100644
--- a/lib/opentox-client.rb
+++ b/lib/opentox-client.rb
@@ -26,8 +26,8 @@ FALSE_REGEXP = /^(false|inactive|0|0.0|low tox|deactivating|non-carcinogen|non-m
[
"overwrite.rb",
- "error.rb",
"rest-client-wrapper.rb",
+ "error.rb",
"authorization.rb",
"policy.rb",
"otlogger.rb",
diff --git a/lib/rest-client-wrapper.rb b/lib/rest-client-wrapper.rb
index 387a01b..67a6264 100644
--- a/lib/rest-client-wrapper.rb
+++ b/lib/rest-client-wrapper.rb
@@ -18,13 +18,13 @@ module OpenTox
# check input
@subjectid = headers[:subjectid] ? headers[:subjectid] : nil
bad_request_error "Invalid URI: '#{uri}'", uri unless URI.valid? uri
- #not_found_error "URI '#{uri}' not found.", uri unless URI.accessible?(uri, @subjectid) unless URI.ssl?(uri)
+ #resource_not_found_error "URI '#{uri}' not found.", uri unless URI.accessible?(uri, @subjectid) unless URI.ssl?(uri)
bad_request_error "Headers are not a hash: #{headers.inspect}", uri unless headers==nil or headers.is_a?(Hash)
# make sure that no header parameters are set in the payload
[:accept,:content_type,:subjectid].each do |header|
if defined? $aa || URI(uri).host == URI($aa[:uri]).host
else
- bad_request_error "#{header} should be submitted in the headers" if payload and payload.is_a?(Hash) and payload[header]
+ bad_request_error "#{header} should be submitted in the headers", uri if payload and payload.is_a?(Hash) and payload[header]
end
end
@@ -44,27 +44,11 @@ module OpenTox
response.follow_redirection(request, result)
elsif response.code >= 400 and !URI.task?(uri)
message = response.to_s
- message += "\nREST paramenters:\n#{request.args.inspect}"
- case response.code
- when 400
- bad_request_error message, uri
- when 401
- not_authorized_error message, uri
- when 404
- not_found_error message, uri
- when 433
- locked_error message, uri
- when 500
- internal_server_error message, uri
- when 501
- not_implemented_error message, uri
- when 503
- service_unavailable_error message, uri
- when 504
- time_out_error message, uri
- else
- rest_call_error message, uri
- end
+ parameters = request.args
+ parameters[:headers][:subjectid] = "REMOVED" if parameters[:headers] and parameters[:headers][:subjectid]
+ message += "\nREST paramenters:\n#{parameters.inspect}"
+ error = known_errors.collect{|e| e if e[:code] == response.code}.compact.first
+ Object.method(error[:method]).call message, uri # call error method
else
response
end
@@ -72,5 +56,18 @@ module OpenTox
end
end
+ def self.known_errors
+ errors = []
+ RestClient::STATUSES.each do |code,k|
+ if code >= 400
+ method = k.underscore.gsub(/ |'/,'_')
+ method += "_error" unless method.match(/_error$/)
+ klass = method.split("_").collect{|s| s.capitalize}.join("")
+ errors << {:code => code, :method => method.to_sym, :class => klass}
+ end
+ end
+ errors
+ end
+
end
end
--
cgit v1.2.3
From f965db794d27cf5f298fb2fc276da1cf829cd985 Mon Sep 17 00:00:00 2001
From: rautenberg
Date: Tue, 7 Aug 2012 09:33:45 +0200
Subject: resource_not_found_error when authentication is impossible
---
lib/authorization.rb | 16 +++++++++-------
1 file changed, 9 insertions(+), 7 deletions(-)
(limited to 'lib')
diff --git a/lib/authorization.rb b/lib/authorization.rb
index fd20f68..438c7c6 100644
--- a/lib/authorization.rb
+++ b/lib/authorization.rb
@@ -5,7 +5,7 @@ module OpenTox
#@example Authentication
# require "opentox-client"
# OpenTox::Authorization::AA = "https://opensso.in-silico.ch" #if not set in .opentox/conf/[environment].yaml
- # token = OpenTox::Authorization.authenticate("username", "password")
+ # subjectid = OpenTox::Authorization.authenticate("username", "password")
#@see http://www.opentox.org/dev/apis/api-1.2/AA OpenTox A&A API 1.2 specification
module Authorization
@@ -65,6 +65,7 @@ module OpenTox
out = RestClientWrapper.post("#{AA}/auth/authenticate",{:username=>user, :password => pw}).sub("token.id=","").sub("\n","")
return out
rescue
+ resource_not_found_error "#{out.inspect}"
return nil
end
end
@@ -87,11 +88,12 @@ module OpenTox
# @return [Boolean, nil] returns true, false or nil (if authorization-request fails).
def self.authorize(uri, action, subjectid)
return true if !AA
- begin
- return true if RestClientWrapper.post("#{AA}/auth/authorize",{:uri => uri, :action => action, :subjectid => subjectid})== "boolean=true\n"
- rescue
- return nil
- end
+ #begin
+ return true if RestClientWrapper.post("#{AA}/auth/authorize",{:uri => uri, :action => action, :subjectid => subjectid})== "boolean=true\n"
+ return false
+ #rescue
+ # return nil
+ #end
end
#Checks if a token is a valid token
@@ -101,7 +103,7 @@ module OpenTox
return true if !AA
begin
return true if RestClientWrapper.post("#{AA}/auth/isTokenValid",:tokenid => subjectid) == "boolean=true\n"
- rescue
+ rescue #do rescue because openSSO throws 401
return false
end
return false
--
cgit v1.2.3
From 36ddfa15a91ddea1ed468c9cef4834fa5aebdbdd Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Mon, 20 Aug 2012 14:33:48 +0200
Subject: new compound serialisation methods
---
lib/dataset.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/dataset.rb b/lib/dataset.rb
index e0f2d5a..4816b5a 100644
--- a/lib/dataset.rb
+++ b/lib/dataset.rb
@@ -22,7 +22,7 @@ module OpenTox
CSV.generate do |csv|
csv << ["SMILES"] + @features.collect{|f| f.title}
@compounds.each_with_index do |c,i|
- csv << [c.to_smiles] + @data_entries[i]
+ csv << [c.smiles] + @data_entries[i]
end
end
end
--
cgit v1.2.3
From fdad1b78a4ec89c160bff710f0374614c22cda56 Mon Sep 17 00:00:00 2001
From: Christoph Helma
Date: Mon, 20 Aug 2012 14:36:39 +0200
Subject: cached compound representations, initial pubchem and chembl methods
---
lib/compound.rb | 56 ++++++++++++++++++++++++++++++++++++++------------------
1 file changed, 38 insertions(+), 18 deletions(-)
(limited to 'lib')
diff --git a/lib/compound.rb b/lib/compound.rb
index 7d84a3c..127a6ee 100644
--- a/lib/compound.rb
+++ b/lib/compound.rb
@@ -11,6 +11,7 @@ module OpenTox
# @param [String] smiles Smiles string
# @return [OpenTox::Compound] Compound
def self.from_smiles service_uri, smiles, subjectid=nil
+ @smiles = smiles
Compound.new RestClientWrapper.post(service_uri, smiles, {:content_type => 'chemical/x-daylight-smiles', :subjectid => subjectid})
end
@@ -18,6 +19,7 @@ module OpenTox
# @param [String] smiles InChI string
# @return [OpenTox::Compound] Compound
def self.from_inchi service_uri, inchi, subjectid=nil
+ @inchi = inchi
Compound.new RestClientWrapper.post(service_uri, inchi, {:content_type => 'chemical/x-inchi', :subjectid => subjectid})
end
@@ -33,60 +35,78 @@ module OpenTox
# compound = OpenTox::Compound.from_name("Benzene")
# @param [String] name name can be also an InChI/InChiKey, CAS number, etc
# @return [OpenTox::Compound] Compound
+ #
def self.from_name service_uri, name, subjectid=nil
- Compound.new RestClientWrapper.post(service_uri, name, {:content_type => 'text/plain', :subjectid => subjectid})
+ @inchi = RestClientWrapper.get File.join(CACTUS_URI,URI.escape(name),"stdinchi")
+ Compound.new RestClientWrapper.post(service_uri, @inchi, {:content_type => 'chemical/x-inchi', :subjectid => subjectid})
end
# Get InChI
# @return [String] InChI string
- def to_inchi
- RestClientWrapper.get(@uri,{},{:accept => 'chemical/x-inchi'}).chomp
+ def inchi
+ @inchi ||= RestClientWrapper.get(@uri,{},{:accept => 'chemical/x-inchi'}).chomp
+ end
+
+ # Get InChIKey
+ # @return [String] InChI string
+ def inchikey
+ @inchikey ||= RestClientWrapper.get(@uri,{},{:accept => 'chemical/x-inchikey'}).chomp
end
# Get (canonical) smiles
# @return [String] Smiles string
- def to_smiles
- RestClientWrapper.get(@uri,{},{:accept => 'chemical/x-daylight-smiles'}).chomp
+ def smiles
+ @smiles ||= RestClientWrapper.get(@uri,{},{:accept => 'chemical/x-daylight-smiles'}).chomp
end
# Get sdf
# @return [String] SDF string
- def to_sdf
+ def sdf
RestClientWrapper.get(@uri,{},{:accept => 'chemical/x-mdl-sdfile'}).chomp
end
# Get gif image
# @return [image/gif] Image data
- def to_gif
- RestClientWrapper.get("#{CACTUS_URI}#{to_inchi}/image")
+ def gif
+ RestClientWrapper.get File.join(CACTUS_URI,inchi,"image")
end
# Get png image
# @example
- # image = compound.to_png
+ # image = compound.png
# @return [image/png] Image data
- def to_png
+ def png
RestClientWrapper.get(File.join @uri, "image")
end
# Get URI of compound image
# @return [String] Compound image URI
- def to_image_uri
+ def image_uri
File.join @uri, "image"
end
# Get all known compound names. Relies on an external service for name lookups.
# @example
- # names = compound.to_names
+ # names = compound.names
# @return [String] Compound names
- def to_names
- begin
- RestClientWrapper.get("#{CACTUS_URI}#{to_inchi}/names").split("\n")
- rescue
- "CACTVS service not responding."
- end
+ def names
+ RestClientWrapper.get("#{CACTUS_URI}#{inchi}/names").split("\n")
end
+ def cid
+ pug_uri = "http://pubchem.ncbi.nlm.nih.gov/rest/pug/"
+ @cid ||= RestClientWrapper.post(File.join(pug_uri, "compound", "inchi", "cids", "TXT"),{:inchi => inchi}).strip
+ end
+
+ def chebi
+ end
+
+ def chemblid
+ # https://www.ebi.ac.uk/chembldb/ws#individualCompoundByInChiKey
+ uri = "http://www.ebi.ac.uk/chemblws/compounds/smiles/#{smiles}.json"
+ @chemblid = JSON.parse(RestClientWrapper.get(uri))["compounds"].first["chemblId"]
+ end
+
=begin
# Match a smarts string
# @example
--
cgit v1.2.3
From 607be1ffb0a001e4a2bf9cae2babd44b4d898d25 Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Thu, 6 Sep 2012 16:13:47 +0200
Subject: Fixed post
---
lib/algorithm.rb | 2 +-
lib/opentox-client.rb | 1 +
lib/opentox.rb | 4 ++--
3 files changed, 4 insertions(+), 3 deletions(-)
(limited to 'lib')
diff --git a/lib/algorithm.rb b/lib/algorithm.rb
index 4986c40..0c633f2 100644
--- a/lib/algorithm.rb
+++ b/lib/algorithm.rb
@@ -8,7 +8,7 @@ module OpenTox
# @param [optional,OpenTox::Task] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
# @return [String] URI of new resource (dataset, model, ...)
def run params=nil
- post params, {:accept => 'text/uri-list'}
+ post params
end
end
diff --git a/lib/opentox-client.rb b/lib/opentox-client.rb
index 5f5a106..d08d07a 100644
--- a/lib/opentox-client.rb
+++ b/lib/opentox-client.rb
@@ -36,5 +36,6 @@ FALSE_REGEXP = /^(false|inactive|0|0.0|low tox|deactivating|non-carcinogen|non-m
"compound.rb",
"dataset.rb",
"model.rb",
+ "algorithm.rb"
].each{ |f| require File.join(File.dirname(__FILE__),f) }
diff --git a/lib/opentox.rb b/lib/opentox.rb
index 80644db..faa7b58 100644
--- a/lib/opentox.rb
+++ b/lib/opentox.rb
@@ -95,9 +95,9 @@ module OpenTox
end
# Post object to webservice
- def post service_uri, wait=true
+ def post params=nil, wait=true
# TODO: RDFXML
- uri = RestClientWrapper.post service_uri, to_ntriples, { :content_type => "text/plain", :subjectid => @subjectid}
+ uri = RestClientWrapper.post @uri.to_s, params, { :content_type => "text/plain", :subjectid => @subjectid}
wait_for_task uri if wait
end
--
cgit v1.2.3
From 781e7f714130dcd054d5d437f9c9f95c02cf9f7f Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Thu, 6 Sep 2012 16:59:57 +0200
Subject: Added match routines
---
lib/compound.rb | 39 +++++++++++++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)
(limited to 'lib')
diff --git a/lib/compound.rb b/lib/compound.rb
index 127a6ee..19d00fb 100644
--- a/lib/compound.rb
+++ b/lib/compound.rb
@@ -186,5 +186,44 @@ module OpenTox
end
end
=end
+
+ # Match an array of smarts strings, returns array with matching smarts
+ # @example
+ # compound = Compound.from_name("Benzene")
+ # compound.match(['cc','cN']) # returns ['cc']
+ # @param [Array] smarts_array Array with Smarts strings
+ # @return [Array] Array with matching Smarts strings
+ def match(smarts_array)
+ obconversion = OpenBabel::OBConversion.new
+ obmol = OpenBabel::OBMol.new
+ obconversion.set_in_format('inchi')
+ obconversion.read_string(obmol,inchi)
+ smarts_pattern = OpenBabel::OBSmartsPattern.new
+ smarts_array.collect { |smarts|
+ smarts_pattern.init(smarts)
+ smarts if smarts_pattern.match(obmol)
+ }.compact
+ end
+
+ # Match an array of smarts strings, returns hash with matching smarts as key and number of non-unique hits as value
+ # @param [Array] smarts_array Array with Smarts strings
+ # @return [Hash] Hash with matching smarts as key and number of non-unique hits as value
+ def match_hits(smarts_array)
+ obconversion = OpenBabel::OBConversion.new
+ obmol = OpenBabel::OBMol.new
+ obconversion.set_in_format('inchi')
+ obconversion.read_string(obmol,inchi)
+ smarts_pattern = OpenBabel::OBSmartsPattern.new
+ smarts_hits = {}
+ smarts_array.collect do |smarts|
+ smarts_pattern.init(smarts)
+ if smarts_pattern.match(obmol)
+ hits = smarts_pattern.get_map_list
+ smarts_hits[smarts] = hits.to_a.size
+ end
+ end
+ return smarts_hits
+ end
+
end
end
--
cgit v1.2.3
From fcb0574da3d9e52ad68669b7c84e0a8e029ad240 Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Tue, 11 Sep 2012 12:57:00 +0200
Subject: Updated match routines
---
lib/compound.rb | 43 +++++++++++++++++++++----------------------
1 file changed, 21 insertions(+), 22 deletions(-)
(limited to 'lib')
diff --git a/lib/compound.rb b/lib/compound.rb
index 19d00fb..da16c85 100644
--- a/lib/compound.rb
+++ b/lib/compound.rb
@@ -187,28 +187,18 @@ module OpenTox
end
=end
- # Match an array of smarts strings, returns array with matching smarts
- # @example
- # compound = Compound.from_name("Benzene")
- # compound.match(['cc','cN']) # returns ['cc']
- # @param [Array] smarts_array Array with Smarts strings
- # @return [Array] Array with matching Smarts strings
- def match(smarts_array)
- obconversion = OpenBabel::OBConversion.new
- obmol = OpenBabel::OBMol.new
- obconversion.set_in_format('inchi')
- obconversion.read_string(obmol,inchi)
- smarts_pattern = OpenBabel::OBSmartsPattern.new
- smarts_array.collect { |smarts|
- smarts_pattern.init(smarts)
- smarts if smarts_pattern.match(obmol)
- }.compact
- end
- # Match an array of smarts strings, returns hash with matching smarts as key and number of non-unique hits as value
+
+ # Match an array of smarts strings, returns hash
+ # Keys: matching smarts, values: number of non-unique hits, or 1
# @param [Array] smarts_array Array with Smarts strings
- # @return [Hash] Hash with matching smarts as key and number of non-unique hits as value
- def match_hits(smarts_array)
+ # @param [Boolean] Whether non-unique hits or 1 should be produced
+ # @return [Array] Array with matching Smarts strings
+ # @example {
+ # compound = Compound.from_name("Benzene")
+ # compound.match(['cc','cN']) # returns { 'cc' => 12, 'cN' => 0 }
+ # }
+ def match_hits(smarts_array, use_hits=true)
obconversion = OpenBabel::OBConversion.new
obmol = OpenBabel::OBMol.new
obconversion.set_in_format('inchi')
@@ -218,12 +208,21 @@ module OpenTox
smarts_array.collect do |smarts|
smarts_pattern.init(smarts)
if smarts_pattern.match(obmol)
- hits = smarts_pattern.get_map_list
- smarts_hits[smarts] = hits.to_a.size
+ if use_hits
+ hits = smarts_pattern.get_map_list
+ smarts_hits[smarts] = hits.to_a.size
+ else
+ smarts_hits[smarts] = 1
+ end
end
end
return smarts_hits
end
+ # Provided for backward compatibility
+ def match(smarts_array)
+ match_hits(smarts_array,false)
+ end
+
end
end
--
cgit v1.2.3
From b4ba72cd339f4067ab411dbd51beabf22a2e23e2 Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Thu, 13 Sep 2012 15:16:38 +0200
Subject: Array overwrite methods
---
lib/overwrite.rb | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
(limited to 'lib')
diff --git a/lib/overwrite.rb b/lib/overwrite.rb
index 785fbcd..574d922 100644
--- a/lib/overwrite.rb
+++ b/lib/overwrite.rb
@@ -93,3 +93,30 @@ module Kernel
end
end
+
+
+class Array
+
+ # Sum of an array for Arrays
+ # @param [Array] Array of arrays
+ # @return [Integer] Sum of size of array elements
+ def sum_size
+ self.inject(0) { |s,a|
+ if a.respond_to?('size')
+ s+=a.size
+ else
+ internal_server_error "No size available: #{a.inspect}"
+ end
+ }
+ end
+
+ # For symbolic features
+ # @param [Array] Array to test.
+ # @return [Boolean] Whether the array has just one unique value.
+ def zero_variance?
+ return self.uniq.size == 1
+ end
+
+
+end
+
--
cgit v1.2.3
From 9eb282dbe9a15fd7066e8dab793c33ac12976f2f Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Mon, 1 Oct 2012 13:45:33 +0200
Subject: Added force-no-query parameter
---
lib/dataset.rb | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
(limited to 'lib')
diff --git a/lib/dataset.rb b/lib/dataset.rb
index 4816b5a..8c855a9 100644
--- a/lib/dataset.rb
+++ b/lib/dataset.rb
@@ -27,8 +27,8 @@ module OpenTox
end
end
- def get
- super
+ def get(force_no_backend_query=false)
+ super() unless (force_no_backend_query and @rdf.size>0)
@features = []
@compounds = []
@data_entries = []
--
cgit v1.2.3
From f393427d352d68467d8f2010f0a1c7b9990b7bb1 Mon Sep 17 00:00:00 2001
From: rautenberg
Date: Fri, 5 Oct 2012 12:33:53 +0200
Subject: methode to check URI-owner
---
lib/authorization.rb | 7 +++++++
1 file changed, 7 insertions(+)
(limited to 'lib')
diff --git a/lib/authorization.rb b/lib/authorization.rb
index 438c7c6..1fe5c51 100644
--- a/lib/authorization.rb
+++ b/lib/authorization.rb
@@ -164,6 +164,13 @@ module OpenTox
end
end
+ #Returns true or false if owner (who created the first policy) of an URI
+ # @param [String, String]uri,subjectid
+ # return [Boolean]true,false status of ownership of the URI
+ def self.uri_owner?(uri, subjectid)
+ get_uri_owner(uri, subjectid) == get_user(subjectid)
+ end
+
#Checks if a policy exists to a URI. Requires URI and token.
# @param [String, String]uri,subjectid
# return [Boolean]
--
cgit v1.2.3
From fb278d6d54b81e64ca81a76cccdfd0c71ac5f394 Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Wed, 10 Oct 2012 15:01:25 +0200
Subject: Fixed uri on force_no_lookup
---
lib/dataset.rb | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
(limited to 'lib')
diff --git a/lib/dataset.rb b/lib/dataset.rb
index 8c855a9..c52952f 100644
--- a/lib/dataset.rb
+++ b/lib/dataset.rb
@@ -35,7 +35,9 @@ module OpenTox
query = RDF::Query.new do
pattern [:uri, RDF.type, RDF::OT.OrderedDataset]
end
- if query.execute(@rdf).first # ordered dataset
+ s=query.execute(@rdf)
+ if s.first # ordered dataset
+ @uri = s[0].uri.to_s if force_no_backend_query # AM: must rewrite URI
query = RDF::Query.new do
pattern [:uri, RDF.type, RDF::OT.Compound]
pattern [:uri, RDF::OLO.index, :idx]
@@ -101,7 +103,7 @@ module OpenTox
def << data_entry
compound = data_entry.shift
bad_request_error "Dataset features are empty." unless features
- bad_request_error "data_entry size does not match features size." unless data_entry.size == features.size
+ bad_request_error "data_entry size '#{data_entry.size}' does not match features size '#{features.size}'." unless data_entry.size == features.size
bad_request_error "First data_entry is not a OpenTox::Compound" unless compound.class == OpenTox::Compound
@compounds << compound
@data_entries << data_entry
--
cgit v1.2.3
From f1028bbed9f5b00391c66bf843eb95a39253ccf4 Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Thu, 11 Oct 2012 15:16:44 +0200
Subject: Fixed RestClientWrapper description
---
lib/rest-client-wrapper.rb | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
(limited to 'lib')
diff --git a/lib/rest-client-wrapper.rb b/lib/rest-client-wrapper.rb
index 67a6264..1258339 100644
--- a/lib/rest-client-wrapper.rb
+++ b/lib/rest-client-wrapper.rb
@@ -6,7 +6,7 @@ module OpenTox
# REST methods
# Raises OpenTox::Error if call fails (rescued in overwrite.rb -> halt 502)
- # Waits for Task to finish and returns result URI of Task per default
+ # Does not wait for task to finish and returns task uri
# @param [String] destination URI
# @param [optional,Hash|String] Payload data posted to the service
# @param [optional,Hash] Headers with params like :accept, :content_type, :subjectid
@@ -46,7 +46,7 @@ module OpenTox
message = response.to_s
parameters = request.args
parameters[:headers][:subjectid] = "REMOVED" if parameters[:headers] and parameters[:headers][:subjectid]
- message += "\nREST paramenters:\n#{parameters.inspect}"
+ message += "\nREST parameters:\n#{parameters.inspect}"
error = known_errors.collect{|e| e if e[:code] == response.code}.compact.first
Object.method(error[:method]).call message, uri # call error method
else
--
cgit v1.2.3
From d182e4f3d666ad2586161c2ae84775148d3c11ad Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Fri, 19 Oct 2012 15:57:11 +0200
Subject: Support for subgraphs as numeric values
---
lib/dataset.rb | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
(limited to 'lib')
diff --git a/lib/dataset.rb b/lib/dataset.rb
index c52952f..85b942a 100644
--- a/lib/dataset.rb
+++ b/lib/dataset.rb
@@ -48,7 +48,10 @@ module OpenTox
pattern [:uri, RDF::OLO.index, :idx]
end
@features = query.execute(@rdf).sort_by{|s| s.idx}.collect{|s| OpenTox::Feature.new(s.uri.to_s)}
- numeric_features = @features.collect{|f| f.get; f[RDF.type].include? RDF::OT.NumericFeature}
+ numeric_features = @features.collect{|f|
+ f.get
+ f[RDF.type].include?(RDF::OT.NumericFeature) or f[RDF.type].include?(RDF::OT.Substructure)
+ }
@compounds.each_with_index do |compound,i|
query = RDF::Query.new do
pattern [:data_entry, RDF::OLO.index, i]
@@ -58,7 +61,7 @@ module OpenTox
pattern [:values, RDF::OT.value, :value]
end
values = query.execute(@rdf).sort_by{|s| s.feature_idx}.collect do |s|
- (numeric_features[s.feature_idx] and s.value.to_s != "") ? s.value.to_s.to_f : s.value.to_s
+ (numeric_features[s.feature_idx] and s.value.to_s != "") ? s.value.to_s.to_f : s.value.to_s
end
@data_entries << values.collect{|v| v == "" ? nil : v}
end
--
cgit v1.2.3
From 9c8b20a910d316c19d24e79dcf52868b6b8383b7 Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Wed, 24 Oct 2012 16:35:09 +0200
Subject: Merged shims
---
lib/opentox-client.rb | 3 ++
lib/utils/diag.rb | 11 +++++
lib/utils/html.rb | 49 +++++++++++++++++++++
lib/utils/shims/dataset.rb | 104 +++++++++++++++++++++++++++++++++++++++++++++
lib/utils/shims/feature.rb | 87 +++++++++++++++++++++++++++++++++++++
lib/utils/shims/opentox.rb | 51 ++++++++++++++++++++++
lib/utils/shims/task.rb | 22 ++++++++++
7 files changed, 327 insertions(+)
create mode 100644 lib/utils/diag.rb
create mode 100644 lib/utils/html.rb
create mode 100644 lib/utils/shims/dataset.rb
create mode 100644 lib/utils/shims/feature.rb
create mode 100644 lib/utils/shims/opentox.rb
create mode 100644 lib/utils/shims/task.rb
(limited to 'lib')
diff --git a/lib/opentox-client.rb b/lib/opentox-client.rb
index d08d07a..67e0ce7 100644
--- a/lib/opentox-client.rb
+++ b/lib/opentox-client.rb
@@ -39,3 +39,6 @@ FALSE_REGEXP = /^(false|inactive|0|0.0|low tox|deactivating|non-carcinogen|non-m
"algorithm.rb"
].each{ |f| require File.join(File.dirname(__FILE__),f) }
+Dir["#{File.dirname(__FILE__)}/utils/shims/*.rb"].each { |f| require f } # Shims for legacy code
+Dir["#{File.dirname(__FILE__)}/utils/*.rb"].each { |f| require f } # Utils for Libs
+
diff --git a/lib/utils/diag.rb b/lib/utils/diag.rb
new file mode 100644
index 0000000..fd37945
--- /dev/null
+++ b/lib/utils/diag.rb
@@ -0,0 +1,11 @@
+=begin
+* Name: diag.rb
+* Description: Diagnostic tools
+* Author: Andreas Maunz
+* Date: 10/2012
+=end
+
+# Print a diagnostic message
+def uri_list
+ puts "My load path is:\n#{$LOAD_PATH.join("\n")} \nI have loaded #{$LOADED_FEATURES.size} objects.\n\n"
+end
diff --git a/lib/utils/html.rb b/lib/utils/html.rb
new file mode 100644
index 0000000..91dfc64
--- /dev/null
+++ b/lib/utils/html.rb
@@ -0,0 +1,49 @@
+#OT_LOGO = File.join(CONFIG[:services]["opentox-validation"],"resources/ot-logo.png")
+
+=begin
+* Name: html.rb
+* Description: Tools to provide html output
+* Author: Andreas Maunz
+* Date: 10/2012
+=end
+
+# AM: needed since this gem has a nested directory structure
+
+class String
+ # encloses URI in text with with link tag
+ # @return [String] new text with marked links
+ def link_urls
+ regex = Regexp.new '(https?:\/\/[\S]+)([>"])'
+ self.gsub( regex, '\1\2' )
+ end
+end
+
+module OpenTox
+
+ # produces a html page for making web services browser friendly
+ # format of text (=string params) is preserved (e.g. line breaks)
+ # urls are marked as links
+ #
+ # @param [String] text this is the actual content,
+ # @param [optional,String] related_links info on related resources
+ # @param [optional,String] description general info
+ # @param [optional,Array] post_command, infos for the post operation, object defined below
+ # @return [String] html page
+ def self.text_to_html( text, subjectid=nil, related_links=nil, description=nil, post_command=nil )
+
+ # TODO add title as parameter
+ title = nil #$sinatra.url_for($sinatra.request.env['PATH_INFO'], :full) if $sinatra
+ html = ""
+ html += ""+title+"" if title
+ #html += "<\/img>"
+
+ html += "
Description
"+description.link_urls+"
" if description
+ html += "
Related links
"+related_links.link_urls+"
" if related_links
+ html += "
Content
" if description || related_links
+ html += "
"
+ html += text.link_urls
+ html += "
"
+ html
+ end
+
+end
diff --git a/lib/utils/shims/dataset.rb b/lib/utils/shims/dataset.rb
new file mode 100644
index 0000000..75948e0
--- /dev/null
+++ b/lib/utils/shims/dataset.rb
@@ -0,0 +1,104 @@
+=begin
+* Name: dataset.rb
+* Description: Dataset shims
+* Author: Andreas Maunz
+* Date: 10/2012
+=end
+
+module OpenTox
+
+ # Shims for the Dataset Class
+ class Dataset
+
+ attr_accessor :feature_positions, :compound_positions
+
+ # Load a dataset from URI
+ # @param [String] Dataset URI
+ # @return [OpenTox::Dataset] Dataset object
+ def self.find(uri, subjectid=nil)
+ return nil unless uri
+ ds = OpenTox::Dataset.new uri, subjectid
+ ds.get
+ ds
+ end
+
+
+
+ ### Index Structures
+
+ # Create value map
+ # @param [OpenTox::Feature] A feature
+ # @return [Hash] A hash with keys 1...feature.training_classes.size and values training classes
+ def value_map(feature)
+ training_classes = feature.accept_values
+ training_classes.each_index.inject({}) { |h,idx| h[idx+1]=training_classes[idx]; h }
+ end
+
+ # Create feature positions map
+ # @return [Hash] A hash with keys feature uris and values feature positions
+ def build_feature_positions
+ unless @feature_positions
+ @feature_positions = @features.each_index.inject({}) { |h,idx|
+ internal_server_error "Duplicate Feature '#{@features[idx].uri}' in dataset '#{@uri}'" if h[@features[idx].uri]
+ h[@features[idx].uri] = idx
+ h
+ }
+ end
+ end
+
+ # Create compounds positions map
+ # @return [Hash] A hash with keys compound uris and values compound position arrays
+ def build_compound_positions
+ unless @compound_positions
+ @compound_positions = @compounds.each_index.inject({}) { |h,idx|
+ inchi=OpenTox::Compound.new(@compounds[idx].uri).inchi
+ h[inchi] = [] unless h[inchi]
+ h[inchi] << idx if inchi =~ /InChI/
+ h
+ }
+ end
+ end
+
+
+ ### Associative Search Operations
+
+ # Search a dataset for a feature given its URI
+ # @param [String] Feature URI
+ # @return [OpenTox::Feature] Feature object, or nil if not present
+ def find_feature(uri)
+ build_feature_positions
+ res = @features[@feature_positions[uri]] if @feature_positions[uri]
+ res
+ end
+
+ # Search a dataset for a compound given its URI
+ # @param [String] Compound URI
+ # @return [OpenTox::Compound] Array of compound objects, or nil if not present
+ def find_compound(uri)
+ build_compound_positions
+ inchi = OpenTox::Compound.new(uri).inchi
+ res = @compounds[@compound_positions[inchi]] if inchi =~ /InChI/ and @compound_positions[inchi]
+ res
+ end
+
+ # Search a dataset for a data entry given compound URI and feature URI
+ # @param [String] Compound URI
+ # @param [String] Feature URI
+ # @return [Object] Data entry, or nil if not present
+ def find_data_entry(compound_uri, feature_uri)
+ build_compound_positions
+ build_feature_positions
+ inchi = OpenTox::Compound.new(compound_uri).inchi
+ if @compound_positions[inchi] && @feature_positions[feature_uri]
+ res = []
+ @compound_positions[inchi].each { |idx|
+ res << data_entries[idx][@feature_positions[feature_uri]]
+ }
+ end
+ res
+ end
+
+ end
+
+
+end
diff --git a/lib/utils/shims/feature.rb b/lib/utils/shims/feature.rb
new file mode 100644
index 0000000..297748b
--- /dev/null
+++ b/lib/utils/shims/feature.rb
@@ -0,0 +1,87 @@
+=begin
+* Name: feature.rb
+* Description: Feature shims
+* Author: Andreas Maunz
+* Date: 10/2012
+=end
+
+module OpenTox
+
+ # Shims for the feature class
+ class Feature
+
+ # Load a feature from URI
+ # @param [String] Feature URI
+ # @return [OpenTox::Feature] Feature object with the full data
+ def self.find(uri, subjectid=nil)
+ return nil unless uri
+ f = OpenTox::Feature.new uri, subjectid
+ f.get
+ f
+ end
+
+ # Load or create a feature given its title and metadata
+ # Create it if: a) not present, or b) present, but differs in metadata
+ # Newly created features are stored at the backend
+ # @param[String] title Feature title
+ # @param[Hash] metadata Feature metadata
+ # @return [OpenTox::Feature] Feature object with the full data, or nil
+ def self.find_by_title(title, metadata)
+ metadata[RDF.type] = [] unless metadata[RDF.type]
+ metadata[RDF.type] << RDF::OT.Feature unless metadata[RDF.type].include?(RDF::OT.Feature)
+ metadata[RDF::DC.title] = title unless (metadata[RDF::DC.title])
+ feature = feature_new = OpenTox::Feature.new File.join($feature[:uri], SecureRandom.uuid), @subjectid
+ feature_new.metadata = metadata
+ sparql = "SELECT DISTINCT ?feature WHERE { ?feature <#{RDF.type}> <#{RDF::OT['feature'.capitalize]}>. ?feature <#{RDF::DC.title}> '#{title.to_s}' }"
+ feature_uris = OpenTox::Backend::FourStore.query(sparql,"text/uri-list").split("\n")
+ features_equal = false # relevant also when no features found
+ feature_uris.each_with_index { |feature_uri,idx|
+ feature_existing = OpenTox::Feature.find(feature_uri, @subjectid)
+ if (feature_new.metadata.size+1 == feature_existing.metadata.size) # +1 due to title
+ features_equal = metadata.keys.collect { |predicate|
+ unless ( predicate == RDF::DC.title )
+ if feature_new[predicate].class == feature_existing[predicate].class
+ case feature_new[predicate].class.to_s
+ when "Array" then (feature_new[predicate].sort == feature_existing[predicate].sort)
+ else (feature_new[predicate] == feature_existing[predicate])
+ end
+ end
+ else
+ true
+ end
+ }.uniq == [true]
+ end
+ (feature=feature_existing and break) if features_equal
+ }
+ unless features_equal
+ feature_new.put
+ end
+ feature
+ end
+
+ # Find out feature type
+ # Classification takes precedence
+ # @return [String] Feature type
+ def feature_type
+ bad_request_error "rdf type of feature '#{@uri}' not set" unless self[RDF.type]
+ if self[RDF.type].include?(OT.NominalFeature)
+ "classification"
+ elsif [RDF.type].to_a.flatten.include?(OT.NumericFeature)
+ "regression"
+ else
+ "unknown"
+ end
+ end
+
+ # Get accept values
+ # @param[String] Feature URI
+ # @return[Array] Accept values
+ def accept_values
+ accept_values = self[OT.acceptValue]
+ accept_values.sort if accept_values
+ accept_values
+ end
+
+ end
+
+end
diff --git a/lib/utils/shims/opentox.rb b/lib/utils/shims/opentox.rb
new file mode 100644
index 0000000..c10d535
--- /dev/null
+++ b/lib/utils/shims/opentox.rb
@@ -0,0 +1,51 @@
+=begin
+* Name: opentox.rb
+* Description: Architecture shims
+* Author: Andreas Maunz
+* Date: 10/2012
+=end
+
+# This avoids having to prefix everything with "RDF::" (e.g. "RDF::DC").
+# So that we can use our old code mostly as is.
+include RDF
+
+module OpenTox
+
+ # Help function to provide the metadata= functionality.
+ # Downward compatible to opentox-ruby.
+ # @param [Hash] Key-Value pairs with the metadata
+ # @return self
+ def metadata=(hsh)
+ hsh.each {|k,v|
+ self[k]=v
+ }
+ end
+
+
+ ### Index Structures
+
+ # Create parameter positions map
+ # @return [Hash] A hash with keys parameter names and values parameter positions
+ def build_parameter_positions
+ unless @parameter_positions
+ @parameters = parameters
+ @parameter_positions = @parameters.each_index.inject({}) { |h,idx|
+ h[@parameters[idx][DC.title.to_s]] = idx
+ h
+ }
+ end
+ end
+
+
+ ### Associative Search Operations
+
+ # Search a model for a given parameter
+ # @param[String] The parameter title
+ # @return[Object] The parameter value
+ def find_parameter_value(title)
+ build_parameter_positions
+ res = @parameters[@parameter_positions[title]][OT.paramValue.to_s] if @parameter_positions[title]
+ res
+ end
+
+end
diff --git a/lib/utils/shims/task.rb b/lib/utils/shims/task.rb
new file mode 100644
index 0000000..cb73e72
--- /dev/null
+++ b/lib/utils/shims/task.rb
@@ -0,0 +1,22 @@
+=begin
+* Name: task.rb
+* Description: Task shims
+* Author: Andreas Maunz
+* Date: 10/2012
+=end
+
+
+module OpenTox
+
+ # Shims for the Task class
+ class Task
+
+ # Check status of a task
+ # @return [String] Status
+ def status
+ self[RDF::OT.hasStatus]
+ end
+
+ end
+
+end
--
cgit v1.2.3
From 66ae34a7f1fcf01767d94f8c11a0ab2842e19112 Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Fri, 26 Oct 2012 10:17:13 +0200
Subject: Improved ds read performance (see http://goo.gl/ajKQn)
---
lib/dataset.rb | 34 +++++++++++++++++++++++-----------
1 file changed, 23 insertions(+), 11 deletions(-)
(limited to 'lib')
diff --git a/lib/dataset.rb b/lib/dataset.rb
index 85b942a..286c3cb 100644
--- a/lib/dataset.rb
+++ b/lib/dataset.rb
@@ -52,19 +52,31 @@ module OpenTox
f.get
f[RDF.type].include?(RDF::OT.NumericFeature) or f[RDF.type].include?(RDF::OT.Substructure)
}
- @compounds.each_with_index do |compound,i|
- query = RDF::Query.new do
- pattern [:data_entry, RDF::OLO.index, i]
- pattern [:data_entry, RDF::OT.values, :values]
- pattern [:values, RDF::OT.feature, :feature]
- pattern [:feature, RDF::OLO.index, :feature_idx]
- pattern [:values, RDF::OT.value, :value]
+ query = RDF::Query.new do
+ pattern [:data_entry, RDF::OLO.index, :cidx] # compound index: now a free variable
+ pattern [:data_entry, RDF::OT.values, :vals]
+ pattern [:vals, RDF::OT.feature, :f]
+ pattern [:f, RDF::OLO.index, :fidx]
+ pattern [:vals, RDF::OT.value, :val]
+ end
+ clim=(@compounds.size-1)
+ cidx=0
+ fidx=0
+ num=numeric_features[fidx]
+ @data_entries = (Array.new(@compounds.size*@features.size)).each_slice(@features.size).to_a # init to nil
+ query.execute(@rdf).order_by(:fidx, :cidx).each { |entry| # order by feature index as to compute numeric status less frequently
+ val = entry.val.to_s
+ unless val.blank?
+ @data_entries[cidx][fidx] = (num ? val.to_f : val)
end
- values = query.execute(@rdf).sort_by{|s| s.feature_idx}.collect do |s|
- (numeric_features[s.feature_idx] and s.value.to_s != "") ? s.value.to_s.to_f : s.value.to_s
+ if (cidx < clim)
+ cidx+=1
+ else
+ cidx=0
+ fidx+=1
+ num=numeric_features[fidx]
end
- @data_entries << values.collect{|v| v == "" ? nil : v}
- end
+ }
else
query = RDF::Query.new do
pattern [:uri, RDF.type, RDF::OT.Feature]
--
cgit v1.2.3
From f519c7cf4ef23289dd3511fc00312dbed2b56d09 Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Fri, 26 Oct 2012 14:45:52 +0200
Subject: Added shims for SPARQL retrieval
---
lib/utils/shims/dataset.rb | 37 +++++++++++++++++++++++++++++++++++++
1 file changed, 37 insertions(+)
(limited to 'lib')
diff --git a/lib/utils/shims/dataset.rb b/lib/utils/shims/dataset.rb
index 75948e0..b5faf18 100644
--- a/lib/utils/shims/dataset.rb
+++ b/lib/utils/shims/dataset.rb
@@ -23,6 +23,43 @@ module OpenTox
end
+ # Load features via SPARQL (fast)
+ # @param [String] Dataset URI
+ # @return [Array] Features in order
+ def self.find_features(uri)
+ sparql = "SELECT DISTINCT ?s FROM <#{uri}> WHERE {
+ ?s <#{RDF.type}> <#{RDF::OT.Feature}> ;
+ <#{RDF::OLO.index}> ?fidx
+ } ORDER BY ?fidx"
+ OpenTox::Backend::FourStore.query(sparql, "text/uri-list").split("\n").collect { |uri| OpenTox::Feature.new uri.strip }
+ end
+
+ # Load compounds via SPARQL (fast)
+ # @param [String] Dataset URI
+ # @return [Array] Compounds in order
+ def self.find_compounds(uri)
+ sparql = "SELECT DISTINCT ?compound FROM <#{uri}> WHERE {
+ ?s <#{RDF.type}> <#{RDF::OT.DataEntry}> ;
+ <#{RDF::OLO.index}> ?cidx;
+ <#{RDF::OT.compound}> ?compound
+ } ORDER BY ?cidx"
+ OpenTox::Backend::FourStore.query(sparql, "text/uri-list").split("\n").collect { |uri| OpenTox::Compound.new uri.strip }
+ end
+
+ # Load data entries via SPARQL (fast)
+ # @param [String] Dataset uri
+ # @return [Array] Data entries, ordered primarily over rows and secondarily over cols
+ def self.find_data_entries(uri)
+ sparql = "SELECT ?value FROM <#{uri}> WHERE {
+ ?data_entry <#{RDF::OLO.index}> ?cidx ;
+ <#{RDF::OT.values}> ?v .
+ ?v <#{RDF::OT.feature}> ?f;
+ <#{RDF::OT.value}> ?value .
+ ?f <#{RDF::OLO.index}> ?fidx.
+ } ORDER BY ?cidx ?fidx"
+ OpenTox::Backend::FourStore.query(sparql,"text/uri-list").split("\n").collect { |val| val.strip }
+ end
+
### Index Structures
--
cgit v1.2.3
From b55f670feb82dff3c782b4f86bf90ac1212a0361 Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Fri, 26 Oct 2012 16:11:43 +0200
Subject: Separate libs for sparql and rdf
---
lib/dataset.rb | 32 +++++++++--------------------
lib/opentox-client.rb | 2 ++
lib/utils/rdf/dataset.rb | 48 ++++++++++++++++++++++++++++++++++++++++++++
lib/utils/shims/dataset.rb | 38 -----------------------------------
lib/utils/sparql/dataset.rb | 49 +++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 109 insertions(+), 60 deletions(-)
create mode 100644 lib/utils/rdf/dataset.rb
create mode 100644 lib/utils/sparql/dataset.rb
(limited to 'lib')
diff --git a/lib/dataset.rb b/lib/dataset.rb
index 286c3cb..e700ad0 100644
--- a/lib/dataset.rb
+++ b/lib/dataset.rb
@@ -36,36 +36,22 @@ module OpenTox
pattern [:uri, RDF.type, RDF::OT.OrderedDataset]
end
s=query.execute(@rdf)
- if s.first # ordered dataset
+
+ # AM: read ordered dataset from RDF
+ if s.first
@uri = s[0].uri.to_s if force_no_backend_query # AM: must rewrite URI
- query = RDF::Query.new do
- pattern [:uri, RDF.type, RDF::OT.Compound]
- pattern [:uri, RDF::OLO.index, :idx]
- end
- @compounds = query.execute(@rdf).sort_by{|s| s.idx}.collect{|s| OpenTox::Compound.new s.uri.to_s}
- query = RDF::Query.new do
- pattern [:uri, RDF.type, RDF::OT.Feature]
- pattern [:uri, RDF::OLO.index, :idx]
- end
- @features = query.execute(@rdf).sort_by{|s| s.idx}.collect{|s| OpenTox::Feature.new(s.uri.to_s)}
+ @compounds = OpenTox::Dataset.find_compounds_rdf(@rdf)
+ @features = OpenTox::Dataset.find_features_rdf(@rdf)
numeric_features = @features.collect{|f|
f.get
f[RDF.type].include?(RDF::OT.NumericFeature) or f[RDF.type].include?(RDF::OT.Substructure)
}
- query = RDF::Query.new do
- pattern [:data_entry, RDF::OLO.index, :cidx] # compound index: now a free variable
- pattern [:data_entry, RDF::OT.values, :vals]
- pattern [:vals, RDF::OT.feature, :f]
- pattern [:f, RDF::OLO.index, :fidx]
- pattern [:vals, RDF::OT.value, :val]
- end
+ table = OpenTox::Dataset.find_data_entries_rdf(@rdf)
clim=(@compounds.size-1)
- cidx=0
- fidx=0
+ cidx = fidx = 0
num=numeric_features[fidx]
@data_entries = (Array.new(@compounds.size*@features.size)).each_slice(@features.size).to_a # init to nil
- query.execute(@rdf).order_by(:fidx, :cidx).each { |entry| # order by feature index as to compute numeric status less frequently
- val = entry.val.to_s
+ table.each { |val|
unless val.blank?
@data_entries[cidx][fidx] = (num ? val.to_f : val)
end
@@ -77,6 +63,8 @@ module OpenTox
num=numeric_features[fidx]
end
}
+
+ # AM: read unordered dataset from RDF
else
query = RDF::Query.new do
pattern [:uri, RDF.type, RDF::OT.Feature]
diff --git a/lib/opentox-client.rb b/lib/opentox-client.rb
index 67e0ce7..8b56411 100644
--- a/lib/opentox-client.rb
+++ b/lib/opentox-client.rb
@@ -40,5 +40,7 @@ FALSE_REGEXP = /^(false|inactive|0|0.0|low tox|deactivating|non-carcinogen|non-m
].each{ |f| require File.join(File.dirname(__FILE__),f) }
Dir["#{File.dirname(__FILE__)}/utils/shims/*.rb"].each { |f| require f } # Shims for legacy code
+Dir["#{File.dirname(__FILE__)}/utils/sparql/*.rb"].each { |f| require f } # SPARQL code
+Dir["#{File.dirname(__FILE__)}/utils/rdf/*.rb"].each { |f| require f } # RDF code
Dir["#{File.dirname(__FILE__)}/utils/*.rb"].each { |f| require f } # Utils for Libs
diff --git a/lib/utils/rdf/dataset.rb b/lib/utils/rdf/dataset.rb
new file mode 100644
index 0000000..5cfb827
--- /dev/null
+++ b/lib/utils/rdf/dataset.rb
@@ -0,0 +1,48 @@
+=begin
+* Name: dataset.rb
+* Description: Dataset RDF tools
+* Author: Andreas Maunz
+* Date: 10/2012
+=end
+
+module OpenTox
+ class Dataset
+
+ # Load features via RDF (slow)
+ # @param [String] Dataset URI
+ # @return [Array] Features in order
+ def self.find_features_rdf(rdf)
+ query = RDF::Query.new do
+ pattern [:uri, RDF.type, RDF::OT.Feature]
+ pattern [:uri, RDF::OLO.index, :idx]
+ end
+ query.execute(rdf).sort_by{|s| s.idx}.collect{|s| OpenTox::Feature.new(s.uri.to_s)}
+ end
+
+ # Load compounds via RDF (slow)
+ # @param [String] Dataset URI
+ # @return [Array] Compounds in order
+ def self.find_compounds_rdf(rdf)
+ query = RDF::Query.new do
+ pattern [:uri, RDF.type, RDF::OT.Compound]
+ pattern [:uri, RDF::OLO.index, :idx]
+ end
+ query.execute(rdf).sort_by{|s| s.idx}.collect{|s| OpenTox::Compound.new(s.uri.to_s)}
+ end
+
+ # Load data entries via RDF (slow)
+ # @param [String] Dataset uri
+ # @return [Array] Data entries, ordered primarily over rows and secondarily over cols
+ def self.find_data_entries_rdf(rdf)
+ query = RDF::Query.new do
+ pattern [:data_entry, RDF::OLO.index, :cidx] # compound index: now a free variable
+ pattern [:data_entry, RDF::OT.values, :vals]
+ pattern [:vals, RDF::OT.feature, :f]
+ pattern [:f, RDF::OLO.index, :fidx]
+ pattern [:vals, RDF::OT.value, :val]
+ end
+ query.execute(rdf).order_by(:fidx, :cidx).collect { |s| s.val.to_s }
+ end
+
+ end
+end
diff --git a/lib/utils/shims/dataset.rb b/lib/utils/shims/dataset.rb
index b5faf18..912510c 100644
--- a/lib/utils/shims/dataset.rb
+++ b/lib/utils/shims/dataset.rb
@@ -23,44 +23,6 @@ module OpenTox
end
- # Load features via SPARQL (fast)
- # @param [String] Dataset URI
- # @return [Array] Features in order
- def self.find_features(uri)
- sparql = "SELECT DISTINCT ?s FROM <#{uri}> WHERE {
- ?s <#{RDF.type}> <#{RDF::OT.Feature}> ;
- <#{RDF::OLO.index}> ?fidx
- } ORDER BY ?fidx"
- OpenTox::Backend::FourStore.query(sparql, "text/uri-list").split("\n").collect { |uri| OpenTox::Feature.new uri.strip }
- end
-
- # Load compounds via SPARQL (fast)
- # @param [String] Dataset URI
- # @return [Array] Compounds in order
- def self.find_compounds(uri)
- sparql = "SELECT DISTINCT ?compound FROM <#{uri}> WHERE {
- ?s <#{RDF.type}> <#{RDF::OT.DataEntry}> ;
- <#{RDF::OLO.index}> ?cidx;
- <#{RDF::OT.compound}> ?compound
- } ORDER BY ?cidx"
- OpenTox::Backend::FourStore.query(sparql, "text/uri-list").split("\n").collect { |uri| OpenTox::Compound.new uri.strip }
- end
-
- # Load data entries via SPARQL (fast)
- # @param [String] Dataset uri
- # @return [Array] Data entries, ordered primarily over rows and secondarily over cols
- def self.find_data_entries(uri)
- sparql = "SELECT ?value FROM <#{uri}> WHERE {
- ?data_entry <#{RDF::OLO.index}> ?cidx ;
- <#{RDF::OT.values}> ?v .
- ?v <#{RDF::OT.feature}> ?f;
- <#{RDF::OT.value}> ?value .
- ?f <#{RDF::OLO.index}> ?fidx.
- } ORDER BY ?cidx ?fidx"
- OpenTox::Backend::FourStore.query(sparql,"text/uri-list").split("\n").collect { |val| val.strip }
- end
-
-
### Index Structures
# Create value map
diff --git a/lib/utils/sparql/dataset.rb b/lib/utils/sparql/dataset.rb
new file mode 100644
index 0000000..e781f08
--- /dev/null
+++ b/lib/utils/sparql/dataset.rb
@@ -0,0 +1,49 @@
+=begin
+* Name: dataset.rb
+* Description: Dataset SPARQL tools
+* Author: Andreas Maunz
+* Date: 10/2012
+=end
+
+module OpenTox
+ class Dataset
+
+ # Load features via SPARQL (fast)
+ # @param [String] Dataset URI
+ # @return [Array] Features in order
+ def self.find_features_sparql(uri)
+ sparql = "SELECT DISTINCT ?s FROM <#{uri}> WHERE {
+ ?s <#{RDF.type}> <#{RDF::OT.Feature}> ;
+ <#{RDF::OLO.index}> ?fidx
+ } ORDER BY ?fidx"
+ OpenTox::Backend::FourStore.query(sparql, "text/uri-list").split("\n").collect { |uri| OpenTox::Feature.new uri.strip }
+ end
+
+ # Load compounds via SPARQL (fast)
+ # @param [String] Dataset URI
+ # @return [Array] Compounds in order
+ def self.find_compounds_sparql(uri)
+ sparql = "SELECT DISTINCT ?compound FROM <#{uri}> WHERE {
+ ?s <#{RDF.type}> <#{RDF::OT.DataEntry}> ;
+ <#{RDF::OLO.index}> ?cidx;
+ <#{RDF::OT.compound}> ?compound
+ } ORDER BY ?cidx"
+ OpenTox::Backend::FourStore.query(sparql, "text/uri-list").split("\n").collect { |uri| OpenTox::Compound.new uri.strip }
+ end
+
+ # Load data entries via SPARQL (fast)
+ # @param [String] Dataset uri
+ # @return [Array] Data entries, ordered primarily over rows and secondarily over cols
+ def self.find_data_entries_sparql(uri)
+ sparql = "SELECT ?value FROM <#{uri}> WHERE {
+ ?data_entry <#{RDF::OLO.index}> ?cidx ;
+ <#{RDF::OT.values}> ?v .
+ ?v <#{RDF::OT.feature}> ?f;
+ <#{RDF::OT.value}> ?value .
+ ?f <#{RDF::OLO.index}> ?fidx.
+ } ORDER BY ?cidx ?fidx"
+ OpenTox::Backend::FourStore.query(sparql,"text/uri-list").split("\n").collect { |val| val.strip }
+ end
+
+ end
+end
--
cgit v1.2.3
From 19582925f0496e4cb07e71ead8aea1261abf0bc8 Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Mon, 29 Oct 2012 16:44:03 +0100
Subject: sparql property request function
---
lib/utils/rdf/dataset.rb | 12 ++++++------
lib/utils/sparql/dataset.rb | 39 +++++++++++++++++++++++++++++++++------
2 files changed, 39 insertions(+), 12 deletions(-)
(limited to 'lib')
diff --git a/lib/utils/rdf/dataset.rb b/lib/utils/rdf/dataset.rb
index 5cfb827..b2deeb8 100644
--- a/lib/utils/rdf/dataset.rb
+++ b/lib/utils/rdf/dataset.rb
@@ -9,8 +9,8 @@ module OpenTox
class Dataset
# Load features via RDF (slow)
- # @param [String] Dataset URI
- # @return [Array] Features in order
+ # @param [String] uri Dataset URI
+ # @return [Array] features Features in order
def self.find_features_rdf(rdf)
query = RDF::Query.new do
pattern [:uri, RDF.type, RDF::OT.Feature]
@@ -20,8 +20,8 @@ module OpenTox
end
# Load compounds via RDF (slow)
- # @param [String] Dataset URI
- # @return [Array] Compounds in order
+ # @param [String] uri Dataset URI
+ # @return [Array] compounds Compounds in order
def self.find_compounds_rdf(rdf)
query = RDF::Query.new do
pattern [:uri, RDF.type, RDF::OT.Compound]
@@ -31,8 +31,8 @@ module OpenTox
end
# Load data entries via RDF (slow)
- # @param [String] Dataset uri
- # @return [Array] Data entries, ordered primarily over rows and secondarily over cols
+ # @param [String] uri Dataset uri
+ # @return [Array] entries Data entries, ordered primarily over rows and secondarily over cols
def self.find_data_entries_rdf(rdf)
query = RDF::Query.new do
pattern [:data_entry, RDF::OLO.index, :cidx] # compound index: now a free variable
diff --git a/lib/utils/sparql/dataset.rb b/lib/utils/sparql/dataset.rb
index e781f08..ecc0321 100644
--- a/lib/utils/sparql/dataset.rb
+++ b/lib/utils/sparql/dataset.rb
@@ -9,8 +9,8 @@ module OpenTox
class Dataset
# Load features via SPARQL (fast)
- # @param [String] Dataset URI
- # @return [Array] Features in order
+ # @param [String] uri Dataset URI
+ # @return [Array] features OpenTox::Features in order
def self.find_features_sparql(uri)
sparql = "SELECT DISTINCT ?s FROM <#{uri}> WHERE {
?s <#{RDF.type}> <#{RDF::OT.Feature}> ;
@@ -19,9 +19,36 @@ module OpenTox
OpenTox::Backend::FourStore.query(sparql, "text/uri-list").split("\n").collect { |uri| OpenTox::Feature.new uri.strip }
end
+ # Load properties via SPARQL (fast)
+ # @param [Array] uris URIs (assumed ordered)
+ # @param [Hash] properties Properties (keys: user-defined identifier, values: rdf identifier as strings)
+ # @return [Array] types Properties in order of URIs
+ def self.find_props_sparql(uris, props)
+ selects = props.keys
+ conditions = selects.collect{ |k|
+ "<#{props[k]}> ?#{k.to_s}"
+ }
+ h={}
+ uris.each{ |uri|
+ sparql = "SELECT ?id #{selects.collect{|k| "?#{k.to_s}"}.join(" ")} FROM <#{uri}> WHERE { ?id #{conditions.join(";")} }"
+ res = OpenTox::Backend::FourStore.query(sparql, "text/uri-list")
+ res.split("\n").inject(h){ |h,row|
+ values = row.split("\t")
+ id=values.shift
+ h[id] = {}
+ values.each_with_index { |val,idx|
+ h[id][selects[idx]] = [] unless h[id][selects[idx]]
+ h[id][selects[idx]] << val.to_s
+ }
+ h
+ }
+ }
+ h
+ end
+
# Load compounds via SPARQL (fast)
- # @param [String] Dataset URI
- # @return [Array] Compounds in order
+ # @param [String] uri Dataset URI
+ # @return [Array] compounds Compounds in order
def self.find_compounds_sparql(uri)
sparql = "SELECT DISTINCT ?compound FROM <#{uri}> WHERE {
?s <#{RDF.type}> <#{RDF::OT.DataEntry}> ;
@@ -32,8 +59,8 @@ module OpenTox
end
# Load data entries via SPARQL (fast)
- # @param [String] Dataset uri
- # @return [Array] Data entries, ordered primarily over rows and secondarily over cols
+ # @param [String] uri Dataset uri
+ # @return [Array] entries Data entries, ordered primarily over rows and secondarily over cols
def self.find_data_entries_sparql(uri)
sparql = "SELECT ?value FROM <#{uri}> WHERE {
?data_entry <#{RDF::OLO.index}> ?cidx ;
--
cgit v1.2.3
From 931e7f00c8a5df5d5c8ea4ae6d8fdd841ec63c90 Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Tue, 30 Oct 2012 16:02:28 +0100
Subject: Loading entries by sparql (mv'd 4store.rb), ordered status via rdf
---
lib/4store.rb | 122 ++++++++++++++++++++++++++++++++++++++++++++
lib/dataset.rb | 19 ++++---
lib/opentox-client.rb | 3 +-
lib/utils/rdf/dataset.rb | 15 +++++-
lib/utils/sparql/dataset.rb | 4 +-
5 files changed, 151 insertions(+), 12 deletions(-)
create mode 100644 lib/4store.rb
(limited to 'lib')
diff --git a/lib/4store.rb b/lib/4store.rb
new file mode 100644
index 0000000..3ed081d
--- /dev/null
+++ b/lib/4store.rb
@@ -0,0 +1,122 @@
+module OpenTox
+ module Backend
+ class FourStore
+
+ @@accept_formats = [ "application/rdf+xml", "text/turtle", "text/plain", "text/uri-list", "text/html", 'application/sparql-results+xml' ]
+ @@content_type_formats = [ "application/rdf+xml", "text/turtle", "text/plain" ]
+
+ def self.list mime_type
+ mime_type = "text/html" if mime_type.match(%r{\*/\*})
+ bad_request_error "'#{mime_type}' is not a supported mime type. Please specify one of #{@@accept_formats.join(", ")} in the Accept Header." unless @@accept_formats.include? mime_type
+ if mime_type =~ /uri-list/
+ sparql = "SELECT DISTINCT ?g WHERE {GRAPH ?g {?s <#{RDF.type}> <#{klass}>; ?p ?o. } }"
+ else
+ sparql = "CONSTRUCT {?s ?p ?o.} WHERE {?s <#{RDF.type}> <#{klass}>; ?p ?o. }"
+ end
+ query sparql, mime_type
+ end
+
+ def self.get uri, mime_type
+ mime_type = "text/html" if mime_type.match(%r{\*/\*})
+ bad_request_error "'#{mime_type}' is not a supported mime type. Please specify one of #{@@accept_formats.join(", ")} in the Accept Header." unless @@accept_formats.include? mime_type
+ sparql = "CONSTRUCT {?s ?p ?o.} FROM <#{uri}> WHERE { ?s ?p ?o. }"
+ rdf = query sparql, mime_type
+ resource_not_found_error "#{uri} not found." if rdf.empty?
+ rdf
+ end
+
+ def self.post uri, rdf, mime_type
+ bad_request_error "'#{mime_type}' is not a supported content type. Please use one of #{@@content_type_formats.join(", ")}." unless @@content_type_formats.include? mime_type or mime_type == "multipart/form-data"
+ bad_request_error "Reqest body empty." unless rdf
+ mime_type = "application/x-turtle" if mime_type == "text/plain" # ntriples is turtle in 4store
+ begin
+ RestClient.post File.join(four_store_uri,"data")+"/", :data => rdf, :graph => uri, "mime-type" => mime_type
+ rescue
+ bad_request_error $!.message, File.join(four_store_uri,"data")+"/"
+ end
+ end
+
+ def self.put uri, rdf, mime_type
+ bad_request_error "'#{mime_type}' is not a supported content type. Please use one of #{@@content_type_formats.join(", ")}." unless @@content_type_formats.include? mime_type
+ bad_request_error "Reqest body empty." unless rdf
+ mime_type = "application/x-turtle" if mime_type == "text/plain"
+ #begin
+ RestClientWrapper.put File.join(four_store_uri,"data",uri), rdf, :content_type => mime_type
+ #rescue
+ #bad_request_error $!.message, File.join(four_store_uri,"data",uri)
+ #end
+ end
+
+ def self.delete uri
+ RestClientWrapper.delete data_uri(uri)
+ end
+
+ def self.update sparql
+ RestClient.post(update_uri, :update => sparql )
+ end
+
+ def self.query sparql, mime_type
+ if sparql =~ /SELECT/i
+# return list unless mime_type
+ case mime_type
+ when 'application/sparql-results+xml'
+ RestClient.get(sparql_uri, :params => { :query => sparql }, :accept => mime_type).body
+ when "text/uri-list"
+ RestClient.get(sparql_uri, :params => { :query => sparql }, :accept => "text/plain").body.gsub(/"|<|>/,'').split("\n").drop(1).join("\n")
+ else
+ bad_request_error "#{mime_type} is not a supported mime type for SELECT statements."
+ end
+ elsif sparql =~ /CONSTRUCT/i
+ case mime_type
+ when "text/plain", "application/rdf+xml"
+ RestClient.get(sparql_uri, :params => { :query => sparql }, :accept => mime_type).body
+ when /html|turtle/
+ # TODO: fix and improve
+ nt = RestClient.get(sparql_uri, :params => { :query => sparql }, :accept => "text/plain").body # 4store returns ntriples for turtle
+
+ rdf = RDF::Graph.new
+ RDF::Reader.for(:ntriples).new(nt) do |reader|
+ reader.each_statement { |statement| rdf << statement }
+ end
+ prefixes = {:rdf => "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"}
+ ['OT', 'DC', 'XSD', 'OLO'].each{|p| prefixes[p.downcase.to_sym] = eval("RDF::#{p}.to_s") }
+ # TODO: fails for large datasets?? multi_cell_call
+ turtle = RDF::N3::Writer.for(:turtle).buffer(:prefixes => prefixes) do |writer|
+ rdf.each{|statement| writer << statement}
+ end
+ regex = Regexp.new '(https?:\/\/[\S]+)([>"])'
+ turtle = "" + turtle.gsub( regex, '\1\2' ).gsub(/\n/,' ') + "" if mime_type =~ /html/ and !turtle.empty?
+ turtle
+ end
+ else
+ # TODO: check if this prevents SPARQL injections
+ bad_request_error "Only SELECT and CONSTRUCT are accepted SPARQL statements."
+ end
+ rescue
+ bad_request_error $!.message, sparql_uri
+ end
+
+ def self.klass
+ RDF::OT[SERVICE.capitalize]
+ end
+
+ def self.four_store_uri
+ # credentials are removed from uri in error.rb
+ $four_store[:uri].sub(%r{//},"//#{$four_store[:user]}:#{$four_store[:password]}@")
+ end
+
+ def self.sparql_uri
+ File.join(four_store_uri, "sparql") + '/'
+ end
+
+ def self.update_uri
+ File.join(four_store_uri, "update") + '/'
+ end
+
+ def self.data_uri uri
+ File.join(four_store_uri, "data","?graph=#{uri}")
+ end
+
+ end
+ end
+end
diff --git a/lib/dataset.rb b/lib/dataset.rb
index e700ad0..8d135a6 100644
--- a/lib/dataset.rb
+++ b/lib/dataset.rb
@@ -28,25 +28,28 @@ module OpenTox
end
def get(force_no_backend_query=false)
- super() unless (force_no_backend_query and @rdf.size>0)
+ have_rdf = (force_no_backend_query and @rdf.size>0)
+ super() unless have_rdf
+ ordered = (have_rdf or OpenTox::Dataset.ordered?(@uri))
@features = []
@compounds = []
@data_entries = []
- query = RDF::Query.new do
- pattern [:uri, RDF.type, RDF::OT.OrderedDataset]
- end
- s=query.execute(@rdf)
# AM: read ordered dataset from RDF
- if s.first
- @uri = s[0].uri.to_s if force_no_backend_query # AM: must rewrite URI
+ if ordered
+ @uri = s[0].uri.to_s if have_rdf # AM: must rewrite URI
@compounds = OpenTox::Dataset.find_compounds_rdf(@rdf)
@features = OpenTox::Dataset.find_features_rdf(@rdf)
numeric_features = @features.collect{|f|
f.get
f[RDF.type].include?(RDF::OT.NumericFeature) or f[RDF.type].include?(RDF::OT.Substructure)
}
- table = OpenTox::Dataset.find_data_entries_rdf(@rdf)
+ if have_rdf
+ table = OpenTox::Dataset.find_data_entries_rdf(@rdf)
+ else
+ values = OpenTox::Dataset.find_data_entries_sparql(@uri)
+ table = values + Array.new(@compounds.size*@features.size-values.size, "")
+ end
clim=(@compounds.size-1)
cidx = fidx = 0
num=numeric_features[fidx]
diff --git a/lib/opentox-client.rb b/lib/opentox-client.rb
index 8b56411..ac7f4e6 100644
--- a/lib/opentox-client.rb
+++ b/lib/opentox-client.rb
@@ -36,7 +36,8 @@ FALSE_REGEXP = /^(false|inactive|0|0.0|low tox|deactivating|non-carcinogen|non-m
"compound.rb",
"dataset.rb",
"model.rb",
- "algorithm.rb"
+ "algorithm.rb",
+ "4store.rb"
].each{ |f| require File.join(File.dirname(__FILE__),f) }
Dir["#{File.dirname(__FILE__)}/utils/shims/*.rb"].each { |f| require f } # Shims for legacy code
diff --git a/lib/utils/rdf/dataset.rb b/lib/utils/rdf/dataset.rb
index b2deeb8..ab720d7 100644
--- a/lib/utils/rdf/dataset.rb
+++ b/lib/utils/rdf/dataset.rb
@@ -32,7 +32,7 @@ module OpenTox
# Load data entries via RDF (slow)
# @param [String] uri Dataset uri
- # @return [Array] entries Data entries, ordered primarily over rows and secondarily over cols
+ # @return [Array] entries Data entries, ordered primarily over cols and secondarily over rows
def self.find_data_entries_rdf(rdf)
query = RDF::Query.new do
pattern [:data_entry, RDF::OLO.index, :cidx] # compound index: now a free variable
@@ -44,5 +44,18 @@ module OpenTox
query.execute(rdf).order_by(:fidx, :cidx).collect { |s| s.val.to_s }
end
+ # Query a dataset URI for ordered status
+ # by loading its metadata (OpenTox compliant)
+ # @param [String] uri Dataset uri
+ # @return [TrueClass,FalseClass] status Whether the dataset is ordered
+ def self.ordered?(uri)
+ ds = OpenTox::Dataset.new # dummy
+ ds.parse_rdfxml(RestClient.get([uri,"metadata"].join("/"),{:accept => "application/rdf+xml"}))
+ query = RDF::Query.new do
+ pattern [:dataset, RDF.type, RDF::OT.OrderedDataset]
+ end
+ query.execute(ds.rdf).size>0
+ end
+
end
end
diff --git a/lib/utils/sparql/dataset.rb b/lib/utils/sparql/dataset.rb
index ecc0321..7ba57ee 100644
--- a/lib/utils/sparql/dataset.rb
+++ b/lib/utils/sparql/dataset.rb
@@ -60,7 +60,7 @@ module OpenTox
# Load data entries via SPARQL (fast)
# @param [String] uri Dataset uri
- # @return [Array] entries Data entries, ordered primarily over rows and secondarily over cols
+ # @return [Array] entries Data entries, ordered primarily over cols and secondarily over rows
def self.find_data_entries_sparql(uri)
sparql = "SELECT ?value FROM <#{uri}> WHERE {
?data_entry <#{RDF::OLO.index}> ?cidx ;
@@ -68,7 +68,7 @@ module OpenTox
?v <#{RDF::OT.feature}> ?f;
<#{RDF::OT.value}> ?value .
?f <#{RDF::OLO.index}> ?fidx.
- } ORDER BY ?cidx ?fidx"
+ } ORDER BY ?fidx ?cidx"
OpenTox::Backend::FourStore.query(sparql,"text/uri-list").split("\n").collect { |val| val.strip }
end
--
cgit v1.2.3
From 3c7161c8c7ff4193245eb4a7b428712def99b22e Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Tue, 30 Oct 2012 16:51:22 +0100
Subject: rdf tools turned to dynamic
---
lib/dataset.rb | 6 +++---
lib/utils/rdf/dataset.rb | 12 ++++++------
2 files changed, 9 insertions(+), 9 deletions(-)
(limited to 'lib')
diff --git a/lib/dataset.rb b/lib/dataset.rb
index 8d135a6..4351dc5 100644
--- a/lib/dataset.rb
+++ b/lib/dataset.rb
@@ -38,14 +38,14 @@ module OpenTox
# AM: read ordered dataset from RDF
if ordered
@uri = s[0].uri.to_s if have_rdf # AM: must rewrite URI
- @compounds = OpenTox::Dataset.find_compounds_rdf(@rdf)
- @features = OpenTox::Dataset.find_features_rdf(@rdf)
+ @compounds = find_compounds_rdf
+ @features = find_features_rdf
numeric_features = @features.collect{|f|
f.get
f[RDF.type].include?(RDF::OT.NumericFeature) or f[RDF.type].include?(RDF::OT.Substructure)
}
if have_rdf
- table = OpenTox::Dataset.find_data_entries_rdf(@rdf)
+ table = find_data_entries_rdf
else
values = OpenTox::Dataset.find_data_entries_sparql(@uri)
table = values + Array.new(@compounds.size*@features.size-values.size, "")
diff --git a/lib/utils/rdf/dataset.rb b/lib/utils/rdf/dataset.rb
index ab720d7..e101b67 100644
--- a/lib/utils/rdf/dataset.rb
+++ b/lib/utils/rdf/dataset.rb
@@ -11,29 +11,29 @@ module OpenTox
# Load features via RDF (slow)
# @param [String] uri Dataset URI
# @return [Array] features Features in order
- def self.find_features_rdf(rdf)
+ def find_features_rdf
query = RDF::Query.new do
pattern [:uri, RDF.type, RDF::OT.Feature]
pattern [:uri, RDF::OLO.index, :idx]
end
- query.execute(rdf).sort_by{|s| s.idx}.collect{|s| OpenTox::Feature.new(s.uri.to_s)}
+ query.execute(@rdf).sort_by{|s| s.idx}.collect{|s| OpenTox::Feature.new(s.uri.to_s)}
end
# Load compounds via RDF (slow)
# @param [String] uri Dataset URI
# @return [Array] compounds Compounds in order
- def self.find_compounds_rdf(rdf)
+ def find_compounds_rdf
query = RDF::Query.new do
pattern [:uri, RDF.type, RDF::OT.Compound]
pattern [:uri, RDF::OLO.index, :idx]
end
- query.execute(rdf).sort_by{|s| s.idx}.collect{|s| OpenTox::Compound.new(s.uri.to_s)}
+ query.execute(@rdf).sort_by{|s| s.idx}.collect{|s| OpenTox::Compound.new(s.uri.to_s)}
end
# Load data entries via RDF (slow)
# @param [String] uri Dataset uri
# @return [Array] entries Data entries, ordered primarily over cols and secondarily over rows
- def self.find_data_entries_rdf(rdf)
+ def find_data_entries_rdf
query = RDF::Query.new do
pattern [:data_entry, RDF::OLO.index, :cidx] # compound index: now a free variable
pattern [:data_entry, RDF::OT.values, :vals]
@@ -41,7 +41,7 @@ module OpenTox
pattern [:f, RDF::OLO.index, :fidx]
pattern [:vals, RDF::OT.value, :val]
end
- query.execute(rdf).order_by(:fidx, :cidx).collect { |s| s.val.to_s }
+ query.execute(@rdf).order_by(:fidx, :cidx).collect { |s| s.val.to_s }
end
# Query a dataset URI for ordered status
--
cgit v1.2.3
From 8a2b749ccef94b229a32ec716c93388f5c7495d7 Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Wed, 31 Oct 2012 15:35:34 +0100
Subject: Fixed get for dataset from RDF
---
lib/dataset.rb | 12 ++++++++----
lib/opentox.rb | 4 ++--
lib/utils/rdf/dataset.rb | 14 +++++++++++++-
3 files changed, 23 insertions(+), 7 deletions(-)
(limited to 'lib')
diff --git a/lib/dataset.rb b/lib/dataset.rb
index 4351dc5..288e4d3 100644
--- a/lib/dataset.rb
+++ b/lib/dataset.rb
@@ -29,17 +29,21 @@ module OpenTox
def get(force_no_backend_query=false)
have_rdf = (force_no_backend_query and @rdf.size>0)
- super() unless have_rdf
ordered = (have_rdf or OpenTox::Dataset.ordered?(@uri))
+ super() if (!have_rdf and !ordered)
@features = []
@compounds = []
@data_entries = []
# AM: read ordered dataset from RDF
if ordered
- @uri = s[0].uri.to_s if have_rdf # AM: must rewrite URI
- @compounds = find_compounds_rdf
- @features = find_features_rdf
+ # Read only some data as rdf
+ unless have_rdf
+ self.parse_rdfxml( RestClient.get([@uri,"allnde"].join("/"),{:accept => "application/rdf+xml"}), true )
+ end
+ @compounds = self.find_compounds_rdf
+ @features = self.find_features_rdf
+
numeric_features = @features.collect{|f|
f.get
f[RDF.type].include?(RDF::OT.NumericFeature) or f[RDF.type].include?(RDF::OT.Substructure)
diff --git a/lib/opentox.rb b/lib/opentox.rb
index faa7b58..0f29c30 100644
--- a/lib/opentox.rb
+++ b/lib/opentox.rb
@@ -130,8 +130,8 @@ module OpenTox
RDF_FORMATS.each do |format|
# rdf parse methods for all formats e.g. parse_rdfxml
- send :define_method, "parse_#{format}".to_sym do |rdf|
- @rdf = RDF::Graph.new
+ send :define_method, "parse_#{format}".to_sym do |rdf,init=true|
+ @rdf = RDF::Graph.new if init
RDF::Reader.for(format).new(rdf) do |reader|
reader.each_statement{ |statement| @rdf << statement }
end
diff --git a/lib/utils/rdf/dataset.rb b/lib/utils/rdf/dataset.rb
index e101b67..2cb32a9 100644
--- a/lib/utils/rdf/dataset.rb
+++ b/lib/utils/rdf/dataset.rb
@@ -47,7 +47,7 @@ module OpenTox
# Query a dataset URI for ordered status
# by loading its metadata (OpenTox compliant)
# @param [String] uri Dataset uri
- # @return [TrueClass,FalseClass] status Whether the dataset is ordered
+ # @return [TrueClass, FalseClass] status Whether the dataset is ordered
def self.ordered?(uri)
ds = OpenTox::Dataset.new # dummy
ds.parse_rdfxml(RestClient.get([uri,"metadata"].join("/"),{:accept => "application/rdf+xml"}))
@@ -57,5 +57,17 @@ module OpenTox
query.execute(ds.rdf).size>0
end
+ # Load dataset URI from given RDF (slow)
+ # @param [String] rdf RDF
+ # @return [String] uri URI
+ def self.uri_from_rdf(rdf)
+ ds = OpenTox::Dataset.new # dummy
+ ds.parse_rdfxml(rdf)
+ query = RDF::Query.new do
+ pattern [:dataset, RDF.type, RDF::OT.Dataset]
+ end
+ query.execute(ds.rdf).collect { |s| s.dataset.to_s }[0]
+ end
+
end
end
--
cgit v1.2.3
From 461a20d9071ad80f334d7a3d8c334e2e085821d2 Mon Sep 17 00:00:00 2001
From: Andreas Maunz
Date: Wed, 31 Oct 2012 17:19:20 +0100
Subject: Compounds removed from allnde target
---
lib/dataset.rb | 17 ++++++++++++++---
lib/utils/sparql/dataset.rb | 5 ++---
2 files changed, 16 insertions(+), 6 deletions(-)
(limited to 'lib')
diff --git a/lib/dataset.rb b/lib/dataset.rb
index 288e4d3..4ce5fc4 100644
--- a/lib/dataset.rb
+++ b/lib/dataset.rb
@@ -37,23 +37,34 @@ module OpenTox
# AM: read ordered dataset from RDF
if ordered
+
# Read only some data as rdf
unless have_rdf
self.parse_rdfxml( RestClient.get([@uri,"allnde"].join("/"),{:accept => "application/rdf+xml"}), true )
end
- @compounds = self.find_compounds_rdf
- @features = self.find_features_rdf
+ # Features
+ @features = self.find_features_rdf
numeric_features = @features.collect{|f|
f.get
f[RDF.type].include?(RDF::OT.NumericFeature) or f[RDF.type].include?(RDF::OT.Substructure)
}
+
+ # Compounds
+ if have_rdf
+ @compounds = self.find_compounds_rdf
+ else
+ @compounds = RestClient.get([@uri,"compounds"].join("/"),{:accept => "text/uri-list"}).split("\n").collect { |cmpd| OpenTox::Compound.new cmpd }
+ end
+
+ # Data Entries
if have_rdf
- table = find_data_entries_rdf
+ table = self.find_data_entries_rdf
else
values = OpenTox::Dataset.find_data_entries_sparql(@uri)
table = values + Array.new(@compounds.size*@features.size-values.size, "")
end
+
clim=(@compounds.size-1)
cidx = fidx = 0
num=numeric_features[fidx]
diff --git a/lib/utils/sparql/dataset.rb b/lib/utils/sparql/dataset.rb
index 7ba57ee..ecf55b6 100644
--- a/lib/utils/sparql/dataset.rb
+++ b/lib/utils/sparql/dataset.rb
@@ -51,9 +51,8 @@ module OpenTox
# @return [Array] compounds Compounds in order
def self.find_compounds_sparql(uri)
sparql = "SELECT DISTINCT ?compound FROM <#{uri}> WHERE {
- ?s <#{RDF.type}> <#{RDF::OT.DataEntry}> ;
- <#{RDF::OLO.index}> ?cidx;
- <#{RDF::OT.compound}> ?compound
+ ?compound <#{RDF.type}> <#{RDF::OT.Compound}> ;
+ <#{RDF::OLO.index}> ?cidx;
} ORDER BY ?cidx"
OpenTox::Backend::FourStore.query(sparql, "text/uri-list").split("\n").collect { |uri| OpenTox::Compound.new uri.strip }
end
--
cgit v1.2.3
From fbc1b7b37d2888594e5c1e28621cb4d8039228c9 Mon Sep 17 00:00:00 2001
From: gebele
Date: Wed, 7 Nov 2012 10:46:27 +0100
Subject: added method created_at
---
lib/task.rb | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/task.rb b/lib/task.rb
index 42bc84b..23e6e9e 100644
--- a/lib/task.rb
+++ b/lib/task.rb
@@ -10,6 +10,7 @@ module OpenTox
uri = File.join(service_uri,SecureRandom.uuid)
task = Task.new uri, subjectid
+ task[RDF::OT.created_at] = DateTime.now
task[RDF::OT.hasStatus] = "Running"
params.each { |k,v| task[k] = v }
task.put false
@@ -61,12 +62,14 @@ module OpenTox
def cancel
kill
self.[]=(RDF::OT.hasStatus, "Cancelled")
+ self.[]=(RDF::OT.finished_at, DateTime.now)
put false
end
def completed(uri)
self.[]=(RDF::OT.resultURI, uri)
self.[]=(RDF::OT.hasStatus, "Completed")
+ self.[]=(RDF::OT.finished_at, DateTime.now)
put false
end
@@ -104,7 +107,7 @@ module OpenTox
code >= 400 and code != 503
end
- [:hasStatus, :resultURI, :finished_at].each do |method|
+ [:hasStatus, :resultURI, :created_at, :finished_at].each do |method|
define_method method do
get
response = self.[](RDF::OT[method])
--
cgit v1.2.3
From 7e27259d5db7349e0e29762244298c986146ca37 Mon Sep 17 00:00:00 2001
From: mguetlein
Date: Fri, 7 Dec 2012 16:59:56 +0100
Subject: extend html support
get request in service root now returns uri-list
accept header for html requests is fixed in before-method
fix link parsing in to_html method
add png image to to_html method
---
lib/4store.rb | 9 ++++-----
lib/utils/html.rb | 9 ++++++---
lib/utils/shims/feature.rb | 2 +-
3 files changed, 11 insertions(+), 9 deletions(-)
(limited to 'lib')
diff --git a/lib/4store.rb b/lib/4store.rb
index 3ed081d..5a2714b 100644
--- a/lib/4store.rb
+++ b/lib/4store.rb
@@ -6,9 +6,8 @@ module OpenTox
@@content_type_formats = [ "application/rdf+xml", "text/turtle", "text/plain" ]
def self.list mime_type
- mime_type = "text/html" if mime_type.match(%r{\*/\*})
bad_request_error "'#{mime_type}' is not a supported mime type. Please specify one of #{@@accept_formats.join(", ")} in the Accept Header." unless @@accept_formats.include? mime_type
- if mime_type =~ /uri-list/
+ if mime_type =~ /(uri-list|html)/
sparql = "SELECT DISTINCT ?g WHERE {GRAPH ?g {?s <#{RDF.type}> <#{klass}>; ?p ?o. } }"
else
sparql = "CONSTRUCT {?s ?p ?o.} WHERE {?s <#{RDF.type}> <#{klass}>; ?p ?o. }"
@@ -17,7 +16,6 @@ module OpenTox
end
def self.get uri, mime_type
- mime_type = "text/html" if mime_type.match(%r{\*/\*})
bad_request_error "'#{mime_type}' is not a supported mime type. Please specify one of #{@@accept_formats.join(", ")} in the Accept Header." unless @@accept_formats.include? mime_type
sparql = "CONSTRUCT {?s ?p ?o.} FROM <#{uri}> WHERE { ?s ?p ?o. }"
rdf = query sparql, mime_type
@@ -61,8 +59,9 @@ module OpenTox
case mime_type
when 'application/sparql-results+xml'
RestClient.get(sparql_uri, :params => { :query => sparql }, :accept => mime_type).body
- when "text/uri-list"
- RestClient.get(sparql_uri, :params => { :query => sparql }, :accept => "text/plain").body.gsub(/"|<|>/,'').split("\n").drop(1).join("\n")
+ when /(uri-list|html)/
+ uri_list = RestClient.get(sparql_uri, :params => { :query => sparql }, :accept => "text/plain").body.gsub(/"|<|>/,'').split("\n").drop(1).join("\n")
+ uri_list = OpenTox.text_to_html(uri_list) if mime_type=~/html/
else
bad_request_error "#{mime_type} is not a supported mime type for SELECT statements."
end
diff --git a/lib/utils/html.rb b/lib/utils/html.rb
index 91dfc64..d74f357 100644
--- a/lib/utils/html.rb
+++ b/lib/utils/html.rb
@@ -7,15 +7,17 @@
* Date: 10/2012
=end
+require "base64"
+
# AM: needed since this gem has a nested directory structure
class String
# encloses URI in text with with link tag
# @return [String] new text with marked links
def link_urls
- regex = Regexp.new '(https?:\/\/[\S]+)([>"])'
- self.gsub( regex, '\1\2' )
+ self.gsub(/(?i)http(s?):\/\/[^\r\n\s']*/, '\0')
end
+
end
module OpenTox
@@ -29,7 +31,7 @@ module OpenTox
# @param [optional,String] description general info
# @param [optional,Array] post_command, infos for the post operation, object defined below
# @return [String] html page
- def self.text_to_html( text, subjectid=nil, related_links=nil, description=nil, post_command=nil )
+ def self.text_to_html( text, subjectid=nil, related_links=nil, description=nil, post_command=nil, png_image=nil )
# TODO add title as parameter
title = nil #$sinatra.url_for($sinatra.request.env['PATH_INFO'], :full) if $sinatra
@@ -41,6 +43,7 @@ module OpenTox
html += "
Related links
"+related_links.link_urls+"
" if related_links
html += "
Content
" if description || related_links
html += "
"
+ html += "\n" if png_image
html += text.link_urls
html += "