opentox-client 0.0.1pre

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/lib/opentox.rb ADDED
@@ -0,0 +1,145 @@
1
+ # defaults to stderr, may be changed to file output (e.g in opentox-service)
2
+ $logger = OTLogger.new(STDERR)
3
+ $logger.level = Logger::DEBUG
4
+
5
+ module OpenTox
6
+
7
+ attr_accessor :uri, :subjectid, :rdf, :response
8
+
9
+ # Ruby interface
10
+
11
+ # Create a new OpenTox object (does not load data from service)
12
+ # @param [optional,String] URI
13
+ # @param [optional,String] subjectid
14
+ # @return [OpenTox] OpenTox object
15
+ def initialize uri=nil, subjectid=nil
16
+ @uri = uri.to_s.chomp
17
+ @subjectid = subjectid
18
+ @rdf = RDF::Graph.new
19
+ end
20
+
21
+ # Load metadata from service
22
+ def pull
23
+ kind_of?(OpenTox::Dataset) ? uri = File.join(@uri,"metadata") : uri = @uri
24
+ # TODO generic method for all formats
25
+ parse_rdfxml RestClientWrapper.get(uri,{},{:accept => $default_rdf, :subjectid => @subjectid})
26
+ end
27
+
28
+ # Get object metadata
29
+ # @return [Hash] Metadata
30
+ def metadata
31
+ pull if @rdf.empty?
32
+ metadata = {}
33
+ @rdf.query([RDF::URI.new(@uri),nil,nil]).collect do |statement|
34
+ metadata[statement.predicate] ||= []
35
+ metadata[statement.predicate] << statement.object
36
+ end
37
+ metadata
38
+ end
39
+
40
+ # Get metadata values
41
+ # @param [RDF] Key from RDF Vocabularies
42
+ # @return [Array] Values for supplied key
43
+ def [](key)
44
+ pull if @rdf.empty?
45
+ @rdf.query([RDF::URI.new(@uri),key,nil]).collect{|statement| statement.object}
46
+ end
47
+
48
+ # Save object at service
49
+ def save
50
+ #TODO: dynamic assignment
51
+ post self.to_rdfxml, { :content_type => $default_rdf}
52
+ end
53
+
54
+ RDF_FORMATS.each do |format|
55
+
56
+ # rdf parse methods for all formats e.g. parse_rdfxml
57
+ send :define_method, "parse_#{format}".to_sym do |rdf|
58
+ @rdf = RDF::Graph.new
59
+ RDF::Reader.for(format).new(rdf) do |reader|
60
+ reader.each_statement{ |statement| @rdf << statement }
61
+ end
62
+ end
63
+
64
+ # rdf serialization methods for all formats e.g. to_rdfxml
65
+ send :define_method, "to_#{format}".to_sym do
66
+ rdf = RDF::Writer.for(format).buffer do |writer|
67
+ @rdf.each{|statement| writer << statement}
68
+ end
69
+ rdf
70
+ end
71
+ end
72
+
73
+ # REST API
74
+ def get headers={}
75
+ headers[:subjectid] ||= @subjectid
76
+ headers[:accept] ||= 'application/rdf+xml'
77
+ @response = RestClientWrapper.get @uri, {}, headers
78
+ end
79
+
80
+ def post payload={}, headers={}
81
+ headers[:subjectid] ||= @subjectid
82
+ headers[:accept] ||= 'application/rdf+xml'
83
+ @response = RestClientWrapper.post(@uri.to_s, payload, headers)
84
+ end
85
+
86
+ def put payload={}, headers={}
87
+ headers[:subjectid] ||= @subjectid
88
+ headers[:accept] ||= 'application/rdf+xml'
89
+ @response = RestClientWrapper.put(@uri.to_s, payload, headers)
90
+ end
91
+
92
+ def delete headers={}
93
+ headers[:subjectid] ||= @subjectid
94
+ @response = RestClientWrapper.delete(@uri.to_s,nil,headers)
95
+ end
96
+
97
+ # class methods
98
+ module ClassMethods
99
+
100
+ def all service_uri, subjectid=nil
101
+ uris = RestClientWrapper.get(service_uri, {}, :accept => 'text/uri-list').split("\n").compact
102
+ uris.collect{|uri| URI.task?(service_uri) ? from_uri(uri, subjectid, false) : from_uri(uri, subjectid)}
103
+ end
104
+
105
+ def create service_uri, subjectid=nil
106
+ uri = RestClientWrapper.post(service_uri, {}, {:accept => 'text/uri-list', :subjectid => subjectid})
107
+ URI.task?(service_uri) ? from_uri(uri, subjectid, false) : from_uri(uri, subjectid)
108
+ end
109
+
110
+ def from_file service_uri, filename, subjectid=nil
111
+ file = File.new filename
112
+ from_uri RestClientWrapper.post(service_uri, {:file => file}, {:subjectid => subjectid, :content_type => file.mime_type, :accept => "text/uri-list"}), subjectid
113
+ end
114
+
115
+ private
116
+ def from_uri uri, subjectid=nil, wait=true
117
+
118
+ uri.chomp!
119
+ # TODO add waiting task
120
+ if URI.task? uri and wait
121
+ t = OpenTox::Task.new(uri)
122
+ t.wait
123
+ uri = t.resultURI
124
+ end
125
+
126
+ # 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)
127
+ result = CLASSES.collect{|s| s if uri =~ /#{s.downcase}/}.compact
128
+ internal_server_error "Cannot determine class from URI: '#{uri}.\nCandidate classes are #{result.inspect}" unless result.size == 1
129
+ klass = result.first
130
+ # initialize with/without subjectid
131
+ subjectid ? eval("#{self}.new(\"#{uri}\", #{subjectid})") : eval("#{self}.new(\"#{uri}\")")
132
+ end
133
+ end
134
+
135
+ # create default OpenTox classes
136
+ CLASSES.each do |klass|
137
+ c = Class.new do
138
+ include OpenTox
139
+ extend OpenTox::ClassMethods
140
+ end
141
+ OpenTox.const_set klass,c
142
+ end
143
+
144
+ end
145
+
data/lib/otlogger.rb ADDED
@@ -0,0 +1,45 @@
1
+ class OTLogger < Logger
2
+
3
+ def pwd
4
+ path = Dir.pwd.to_s
5
+ index = path.rindex(/\//)
6
+ return path if index==nil
7
+ path[(index+1)..-1]
8
+ end
9
+
10
+ def trace()
11
+ lines = caller(0)
12
+ n = 2
13
+ line = lines[n]
14
+
15
+ while (line =~ /error.rb/ or line =~ /create/ or line =~ /#{File.basename(__FILE__)}/)
16
+ n += 1
17
+ line = lines[n]
18
+ end
19
+
20
+ index = line.rindex(/\/.*\.rb/)
21
+ return line if index==nil
22
+ line[index..-1]
23
+ end
24
+
25
+ def format(msg)
26
+ pwd.ljust(18)+" :: "+msg.to_s+" :: "+trace
27
+ end
28
+
29
+ def debug(msg)
30
+ super format(msg)
31
+ end
32
+
33
+ def info(msg)
34
+ super format(msg)
35
+ end
36
+
37
+ def warn(msg)
38
+ super format(msg)
39
+ end
40
+
41
+ def error(msg)
42
+ super format(msg)
43
+ end
44
+
45
+ end
data/lib/overwrite.rb ADDED
@@ -0,0 +1,90 @@
1
+ class String
2
+ def underscore
3
+ self.gsub(/::/, '/').
4
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
5
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
6
+ tr("-", "_").
7
+ downcase
8
+ end
9
+ end
10
+
11
+ module URI
12
+
13
+ def self.compound? uri
14
+ uri =~ /compound/ and URI.valid? uri
15
+ end
16
+
17
+ def self.task? uri
18
+ uri =~ /task/ and URI.valid? uri
19
+ end
20
+
21
+ def self.dataset? uri, subjectid=nil
22
+ uri =~ /dataset/ and URI.accessible? uri, subjectid=nil
23
+ end
24
+
25
+ def self.model? uri, subjectid=nil
26
+ uri =~ /model/ and URI.accessible? uri, subjectid=nil
27
+ end
28
+
29
+ def self.accessible? uri, subjectid=nil
30
+ if URI.task? uri or URI.compound? uri
31
+ # just try to get a response, valid tasks may return codes > 400
32
+ Net::HTTP.get_response(URI.parse(uri))
33
+ true
34
+ else
35
+ Net::HTTP.get_response(URI.parse(uri)).code.to_i < 400
36
+ end
37
+ rescue
38
+ false
39
+ end
40
+
41
+ def self.valid? uri
42
+ u = URI::parse(uri)
43
+ u.scheme!=nil and u.host!=nil
44
+ rescue URI::InvalidURIError
45
+ false
46
+ end
47
+
48
+ end
49
+
50
+ class File
51
+ def mime_type
52
+ `file -ib #{self.path}`.chomp
53
+ end
54
+ end
55
+
56
+ # overwrite backtick operator to catch system errors
57
+ module Kernel
58
+
59
+ # Override raises an error if _cmd_ returns a non-zero exit status.
60
+ # Returns stdout if _cmd_ succeeds. Note that these are simply concatenated; STDERR is not inline.
61
+ def ` cmd
62
+ stdout, stderr = ''
63
+ status = Open4::popen4(cmd) do |pid, stdin_stream, stdout_stream, stderr_stream|
64
+ stdout = stdout_stream.read
65
+ stderr = stderr_stream.read
66
+ end
67
+ raise stderr.strip if !status.success?
68
+ return stdout
69
+ rescue Exception
70
+ internal_server_error $!
71
+ end
72
+
73
+ alias_method :system!, :system
74
+
75
+ def system cmd
76
+ `#{cmd}`
77
+ return true
78
+ end
79
+ end
80
+
81
+ class Array
82
+ def short_backtrace
83
+ short = []
84
+ each do |c|
85
+ break if c =~ /sinatra\/base/
86
+ short << c
87
+ end
88
+ short.join("\n")
89
+ end
90
+ end
data/lib/policy.rb ADDED
@@ -0,0 +1,261 @@
1
+ module OpenTox
2
+ require "rexml/document"
3
+
4
+ #Module for policy-processing
5
+ # @see also http://www.opentox.org/dev/apis/api-1.2/AA for opentox API specs
6
+ # Class Policies corresponds to <policies> container of an xml-policy-fle
7
+ class Policies
8
+
9
+ attr_accessor :name, :policies
10
+
11
+ def initialize()
12
+ @policies = {}
13
+ end
14
+
15
+ #create new policy instance with name
16
+ # @param [String]name of the policy
17
+ def new_policy(name)
18
+ @policies[name] = Policy.new(name)
19
+ end
20
+
21
+ #drop a specific policy in a policies instance
22
+ # @param [String]name of the policy
23
+ # @return [Boolean]
24
+ def drop_policy(name)
25
+ return true if @policies.delete(name)
26
+ end
27
+
28
+ #drop all policies in a policies instance
29
+ def drop_policies
30
+ @policies.each do |name, policy|
31
+ drop_policy(name)
32
+ end
33
+ return true
34
+ end
35
+
36
+ # @return [Array] set of arrays affected by policies
37
+ def uris
38
+ @policies.collect{ |k,v| v.uris }.flatten.uniq
39
+ end
40
+
41
+ #drop all policies in a policies instance
42
+ def names
43
+ out = []
44
+ @policies.each do |name, policy|
45
+ out << name
46
+ end
47
+ return out
48
+ end
49
+
50
+ #loads a default policy template in policies instance
51
+ def load_default_policy(user, uri, group="member")
52
+ template = case user
53
+ when "guest", "anonymous" then "default_guest_policy"
54
+ else "default_policy"
55
+ end
56
+ xml = File.read(File.join(File.dirname(__FILE__), "templates/#{template}.xml"))
57
+ self.load_xml(xml)
58
+ datestring = Time.now.strftime("%Y-%m-%d-%H-%M-%S-x") + rand(1000).to_s
59
+
60
+ @policies["policy_user"].name = "policy_user_#{user}_#{datestring}"
61
+ @policies["policy_user"].rules["rule_user"].uri = uri
62
+ @policies["policy_user"].rules["rule_user"].name = "rule_user_#{user}_#{datestring}"
63
+ @policies["policy_user"].subjects["subject_user"].name = "subject_user_#{user}_#{datestring}"
64
+ @policies["policy_user"].subjects["subject_user"].value = "uid=#{user},ou=people,dc=opentox,dc=org"
65
+ @policies["policy_user"].subject_group = "subjects_user_#{user}_#{datestring}"
66
+
67
+ @policies["policy_group"].name = "policy_group_#{group}_#{datestring}"
68
+ @policies["policy_group"].rules["rule_group"].uri = uri
69
+ @policies["policy_group"].rules["rule_group"].name = "rule_group_#{group}_#{datestring}"
70
+ @policies["policy_group"].subjects["subject_group"].name = "subject_group_#{group}_#{datestring}"
71
+ @policies["policy_group"].subjects["subject_group"].value = "cn=#{group},ou=groups,dc=opentox,dc=org"
72
+ @policies["policy_group"].subject_group = "subjects_#{group}_#{datestring}"
73
+ return true
74
+ end
75
+
76
+ #loads a xml template
77
+ def load_xml(xml)
78
+ rexml = REXML::Document.new(xml)
79
+ rexml.elements.each("Policies/Policy") do |pol| #Policies
80
+ policy_name = pol.attributes["name"]
81
+ new_policy(policy_name)
82
+ #@policies[policy_name] = Policy.new(policy_name)
83
+ rexml.elements.each("Policies/Policy[@name='#{policy_name}']/Rule") do |r| #Rules
84
+ rule_name = r.attributes["name"]
85
+ uri = rexml.elements["Policies/Policy[@name='#{policy_name}']/Rule[@name='#{rule_name}']/ResourceName"].attributes["name"]
86
+ @policies[policy_name].rules[rule_name] = @policies[policy_name].new_rule(rule_name, uri)
87
+ rexml.elements.each("Policies/Policy[@name='#{policy_name}']/Rule[@name='#{rule_name}']/AttributeValuePair") do |attribute_pairs|
88
+ action=nil; value=nil;
89
+ attribute_pairs.each_element do |elem|
90
+ action = elem.attributes["name"] if elem.attributes["name"]
91
+ value = elem.text if elem.text
92
+ end
93
+ if action and value
94
+ case action
95
+ when "GET"
96
+ @policies[policy_name].rules[rule_name].get = value
97
+ when "POST"
98
+ @policies[policy_name].rules[rule_name].post = value
99
+ when "PUT"
100
+ @policies[policy_name].rules[rule_name].put = value
101
+ when "DELETE"
102
+ @policies[policy_name].rules[rule_name].delete = value
103
+ end
104
+ end
105
+ end
106
+ end
107
+ rexml.elements.each("Policies/Policy[@name='#{policy_name}']/Subjects") do |subjects| #Subjects
108
+ @policies[policy_name].subject_group = subjects.attributes["name"]
109
+ rexml.elements.each("Policies/Policy[@name='#{policy_name}']/Subjects[@name='#{@policies[policy_name].subject_group}']/Subject") do |s| #Subject
110
+ subject_name = s.attributes["name"]
111
+ subject_type = s.attributes["type"]
112
+ subject_value = rexml.elements["Policies/Policy[@name='#{policy_name}']/Subjects[@name='#{@policies[policy_name].subject_group}']/Subject[@name='#{subject_name}']/AttributeValuePair/Value"].text
113
+ @policies[policy_name].new_subject(subject_name, subject_type, subject_value) if subject_name and subject_type and subject_value
114
+ end
115
+ end
116
+ end
117
+ end
118
+
119
+ #generates xml from policies instance
120
+ def to_xml
121
+ doc = REXML::Document.new()
122
+ 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\"")
123
+ doc.add_element(REXML::Element.new("Policies"))
124
+
125
+ @policies.each do |name, pol|
126
+ policy = REXML::Element.new("Policy")
127
+ policy.attributes["name"] = pol.name
128
+ policy.attributes["referralPolicy"] = false
129
+ policy.attributes["active"] = true
130
+ @policies[name].rules.each do |r,rl|
131
+ rule = @policies[name].rules[r]
132
+ out_rule = REXML::Element.new("Rule")
133
+ out_rule.attributes["name"] = rule.name
134
+ servicename = REXML::Element.new("ServiceName")
135
+ servicename.attributes["name"]="iPlanetAMWebAgentService"
136
+ out_rule.add_element(servicename)
137
+ rescourcename = REXML::Element.new("ResourceName")
138
+ rescourcename.attributes["name"] = rule.uri
139
+ out_rule.add_element(rescourcename)
140
+
141
+ ["get","post","delete","put"].each do |act|
142
+ if rule.method(act).call
143
+ attribute = REXML::Element.new("Attribute")
144
+ attribute.attributes["name"] = act.upcase
145
+ attributevaluepair = REXML::Element.new("AttributeValuePair")
146
+ attributevaluepair.add_element(attribute)
147
+ attributevalue = REXML::Element.new("Value")
148
+ attributevaluepair.add_element(attributevalue)
149
+ attributevalue.add_text REXML::Text.new(rule.method(act).call)
150
+ out_rule.add_element(attributevaluepair)
151
+
152
+ end
153
+ end
154
+ policy.add_element(out_rule)
155
+ end
156
+
157
+ subjects = REXML::Element.new("Subjects")
158
+ subjects.attributes["name"] = pol.subject_group
159
+ subjects.attributes["description"] = ""
160
+ @policies[name].subjects.each do |subj, subjs|
161
+ subject = REXML::Element.new("Subject")
162
+ subject.attributes["name"] = pol.subjects[subj].name
163
+ subject.attributes["type"] = pol.subjects[subj].type
164
+ subject.attributes["includeType"] = "inclusive"
165
+ attributevaluepair = REXML::Element.new("AttributeValuePair")
166
+ attribute = REXML::Element.new("Attribute")
167
+ attribute.attributes["name"] = "Values"
168
+ attributevaluepair.add_element(attribute)
169
+ attributevalue = REXML::Element.new("Value")
170
+ attributevalue.add_text REXML::Text.new(pol.subjects[subj].value)
171
+ attributevaluepair.add_element(attributevalue)
172
+ subject.add_element(attributevaluepair)
173
+ subjects.add_element(subject)
174
+ end
175
+ policy.add_element(subjects)
176
+ doc.root.add_element(policy)
177
+ end
178
+ out = ""
179
+ doc.write(out, 2)
180
+ return out
181
+ end
182
+
183
+ end
184
+
185
+ #single policy in a policies instance
186
+ class Policy
187
+
188
+ attr_accessor :name, :rules, :subject_group, :subjects
189
+
190
+ def initialize(name)
191
+ @name = name
192
+ @rules = {}
193
+ @subject_group = ""
194
+ @subjects = {}
195
+ end
196
+
197
+ #create a new rule instance for the policy
198
+ def new_rule(name, uri)
199
+ @rules[name] = Rule.new(name, uri)
200
+ end
201
+
202
+ #create a new subject instance for the policy
203
+ def new_subject(name, type, value)
204
+ @subjects[name] = Subject.new(name, type, value)
205
+ end
206
+
207
+ # @return [Array] set of uris affected by policy
208
+ def uris
209
+ @rules.collect{ |k,v| v.uri }.uniq
210
+ end
211
+
212
+ #rule inside a policy
213
+ class Rule
214
+
215
+ attr_accessor :name, :uri, :get, :post, :put, :delete
216
+
217
+ def initialize(name, uri)
218
+ @name = name
219
+ @uri = uri
220
+ end
221
+
222
+ def rename(new, old)
223
+ self[new] = self.delete(old)
224
+ self[new].name = new
225
+ end
226
+
227
+ def get=(value)
228
+ @get = check_value(value, @get)
229
+ end
230
+
231
+ def post=(value)
232
+ @post = check_value(value, @post)
233
+ end
234
+
235
+ def delete=(value)
236
+ @delete = check_value(value, @delete)
237
+ end
238
+
239
+ def put=(value)
240
+ @put = check_value(value, @put)
241
+ end
242
+
243
+ private
244
+ #checks if value is allow or deny. returns old value if not valid.
245
+ def check_value(new_value, old_value)
246
+ return (new_value=="allow" || new_value=="deny" || new_value==nil) ? new_value : old_value
247
+ end
248
+ end
249
+
250
+ class Subject
251
+
252
+ attr_accessor :name, :type, :value
253
+
254
+ def initialize(name, type, value)
255
+ @name = name
256
+ @type = type
257
+ @value = value
258
+ end
259
+ end
260
+ end
261
+ end