opentox-client 0.0.1pre

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