omf_sfa 0.1.1

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.
Files changed (152) hide show
  1. data/.gitignore +24 -0
  2. data/Gemfile +6 -0
  3. data/README.md +211 -0
  4. data/Rakefile +23 -0
  5. data/bin/parse_rspec.rb +167 -0
  6. data/etc/omf-sfa/omf-sfa-am.yaml +12 -0
  7. data/examples/exogeni5nodemanifest.rspec +105 -0
  8. data/examples/instageni5nodemanifest.rspec +150 -0
  9. data/lib/omf-sfa/am/am-rest/REST_API.md +301 -0
  10. data/lib/omf-sfa/am/am-rest/account_handler.rb +145 -0
  11. data/lib/omf-sfa/am/am-rest/am_rest_server.rb +255 -0
  12. data/lib/omf-sfa/am/am-rest/api_template.html +48 -0
  13. data/lib/omf-sfa/am/am-rest/config.ru +110 -0
  14. data/lib/omf-sfa/am/am-rest/resource_handler.rb +178 -0
  15. data/lib/omf-sfa/am/am-rest/rest_handler.rb +573 -0
  16. data/lib/omf-sfa/am/am-rest/session_authenticator.rb +130 -0
  17. data/lib/omf-sfa/am/am-rpc/abstract_rpc_service.rb +60 -0
  18. data/lib/omf-sfa/am/am-rpc/am_authorizer.rb +161 -0
  19. data/lib/omf-sfa/am/am-rpc/am_rpc_api.rb +450 -0
  20. data/lib/omf-sfa/am/am-rpc/am_rpc_service.rb +402 -0
  21. data/lib/omf-sfa/am/am_liaison.rb +93 -0
  22. data/lib/omf-sfa/am/am_manager.rb +859 -0
  23. data/lib/omf-sfa/am/am_runner.rb +108 -0
  24. data/lib/omf-sfa/am/am_scheduler.rb +146 -0
  25. data/lib/omf-sfa/am/am_server.rb +194 -0
  26. data/lib/omf-sfa/am/config.ru +122 -0
  27. data/lib/omf-sfa/am/credential.rb +145 -0
  28. data/lib/omf-sfa/am/default_authorizer.rb +44 -0
  29. data/lib/omf-sfa/am/privilege_credential.rb +76 -0
  30. data/lib/omf-sfa/am/signature.rb +37 -0
  31. data/lib/omf-sfa/am/user_credential.rb +56 -0
  32. data/lib/omf-sfa/am.rb +7 -0
  33. data/lib/omf-sfa/model/abstract_prop_description.rb +87 -0
  34. data/lib/omf-sfa/model/model_class_description.rb +145 -0
  35. data/lib/omf-sfa/model/model_data_prop_description.rb +28 -0
  36. data/lib/omf-sfa/model/model_obj_prop_description.rb +49 -0
  37. data/lib/omf-sfa/model/ontology.rb +169 -0
  38. data/lib/omf-sfa/resource/README.md +24 -0
  39. data/lib/omf-sfa/resource/channel.rb +49 -0
  40. data/lib/omf-sfa/resource/comp_group.rb +41 -0
  41. data/lib/omf-sfa/resource/component_lease.rb +10 -0
  42. data/lib/omf-sfa/resource/constants.rb +24 -0
  43. data/lib/omf-sfa/resource/group_component.rb +35 -0
  44. data/lib/omf-sfa/resource/group_membership.rb +17 -0
  45. data/lib/omf-sfa/resource/gurn.rb +187 -0
  46. data/lib/omf-sfa/resource/interface.rb +78 -0
  47. data/lib/omf-sfa/resource/ip.rb +48 -0
  48. data/lib/omf-sfa/resource/link.rb +29 -0
  49. data/lib/omf-sfa/resource/node.rb +75 -0
  50. data/lib/omf-sfa/resource/oaccount.rb +94 -0
  51. data/lib/omf-sfa/resource/ocomponent.rb +134 -0
  52. data/lib/omf-sfa/resource/ogroup.rb +106 -0
  53. data/lib/omf-sfa/resource/olease.rb +61 -0
  54. data/lib/omf-sfa/resource/oproperty.rb +178 -0
  55. data/lib/omf-sfa/resource/oreference.rb +15 -0
  56. data/lib/omf-sfa/resource/oresource.rb +491 -0
  57. data/lib/omf-sfa/resource/project.rb +28 -0
  58. data/lib/omf-sfa/resource/project_membership.rb +13 -0
  59. data/lib/omf-sfa/resource/sfa_base.rb +544 -0
  60. data/lib/omf-sfa/resource/user.rb +25 -0
  61. data/lib/omf-sfa/resource.rb +20 -0
  62. data/lib/omf-sfa/util/create_sample_testbed.rb +68 -0
  63. data/lib/omf-sfa/util/load_from_sfa_xml.rb +65 -0
  64. data/lib/omf-sfa/version.rb +4 -0
  65. data/lib/omf_sfa.rb +5 -0
  66. data/omf_sfa.gemspec +46 -0
  67. data/owl/README +3 -0
  68. data/owl/ben-6509.rdf +1377 -0
  69. data/owl/ben-dell.rdf +586 -0
  70. data/owl/ben-dtn.rdf +1698 -0
  71. data/owl/ben.rdf +1335 -0
  72. data/owl/collections.owl +309 -0
  73. data/owl/compute.owl +1486 -0
  74. data/owl/domain.owl +444 -0
  75. data/owl/dtn.owl +1165 -0
  76. data/owl/ec2.owl +385 -0
  77. data/owl/ethernet.owl +466 -0
  78. data/owl/eucalyptus.owl +431 -0
  79. data/owl/id-mp-Request1.rdf +247 -0
  80. data/owl/itu-grid.owl +147 -0
  81. data/owl/kansei.owl +511 -0
  82. data/owl/layer.owl +645 -0
  83. data/owl/location.owl +117 -0
  84. data/owl/mass.rdf +608 -0
  85. data/owl/nlr.rdf +901 -0
  86. data/owl/orca.owl +181 -0
  87. data/owl/planetlab.owl +124 -0
  88. data/owl/protogeni.owl +467 -0
  89. data/owl/request-6509-2.rdf +150 -0
  90. data/owl/request-6509-3.rdf +158 -0
  91. data/owl/request-6509.rdf +199 -0
  92. data/owl/request.owl +222 -0
  93. data/owl/storage.owl +511 -0
  94. data/owl/topology.owl +608 -0
  95. data/schema/rspec-v3/ad-common.xsd +269 -0
  96. data/schema/rspec-v3/ad-reservation.rnc +12 -0
  97. data/schema/rspec-v3/ad-reservation.rng +28 -0
  98. data/schema/rspec-v3/ad-reservation.xsd +13 -0
  99. data/schema/rspec-v3/ad.rnc +151 -0
  100. data/schema/rspec-v3/ad.xsd +77 -0
  101. data/schema/rspec-v3/any-extension-schema.xsd +38 -0
  102. data/schema/rspec-v3/any-extension.rnc +30 -0
  103. data/schema/rspec-v3/common.rnc +185 -0
  104. data/schema/rspec-v3/manifest-common.xsd +244 -0
  105. data/schema/rspec-v3/manifest-request.xsd +95 -0
  106. data/schema/rspec-v3/manifest.rnc +62 -0
  107. data/schema/rspec-v3/manifest.xsd +34 -0
  108. data/schema/rspec-v3/request-common.xsd +219 -0
  109. data/schema/rspec-v3/request-reservation.rnc +12 -0
  110. data/schema/rspec-v3/request-reservation.xsd +13 -0
  111. data/schema/rspec-v3/request.rnc +118 -0
  112. data/schema/rspec-v3/request.xsd +94 -0
  113. data/share/assets/css/default.css +147 -0
  114. data/share/assets/css/rest_api.css +0 -0
  115. data/share/assets/network.html +28 -0
  116. data/share/assets/network.js +82 -0
  117. data/spec/am/am-rest/common.rb +29 -0
  118. data/spec/am/am-rest/resource_group_handler_XspecX.rb +97 -0
  119. data/spec/am/am-rest/resource_handler_spec.rb +204 -0
  120. data/spec/am/am-rpc/sfa_methods_spec.rb +150 -0
  121. data/spec/am/am_manager_spec.rb +307 -0
  122. data/spec/am/am_scheduler_spec.rb +57 -0
  123. data/spec/am/common.rb +24 -0
  124. data/spec/resource/common.rb +31 -0
  125. data/spec/resource/node_spec.rb +171 -0
  126. data/spec/resource/oaccount_spec.rb +92 -0
  127. data/spec/resource/ocomponent_spec.rb +225 -0
  128. data/spec/resource/ogroup_spec.rb +93 -0
  129. data/spec/resource/oresource_spec.rb +208 -0
  130. data/spec/resource_and_leases_spec.rb +377 -0
  131. data/test/OLD_FILES/assertion1.xml +117 -0
  132. data/test/OLD_FILES/greeter_spec.rb +15 -0
  133. data/test/OLD_FILES/mongo_test.rb +45 -0
  134. data/test/OLD_FILES/req-sfa-2.xml +6 -0
  135. data/test/OLD_FILES/req-sfa-g.xml +8 -0
  136. data/test/OLD_FILES/req-sfa-g2.xml +10 -0
  137. data/test/OLD_FILES/req-sfa-g3.xml +14 -0
  138. data/test/OLD_FILES/req-sfa.xml +6 -0
  139. data/test/OLD_FILES/req1.xml +22 -0
  140. data/test/OLD_FILES/req1b.xml +15 -0
  141. data/test/OLD_FILES/rspec-test.xml +1867 -0
  142. data/test/OLD_FILES/test.rb +67 -0
  143. data/test/OLD_FILES/test2.rb +32 -0
  144. data/test/am/am_manager_rspec_tests.rb +378 -0
  145. data/test/am/am_manager_tests.rb +518 -0
  146. data/test/am/am_scheduler_tests.rb +173 -0
  147. data/test/resource/olease_test.rb +74 -0
  148. data/test/sfa_requests/request.xml +5 -0
  149. data/test/sfa_requests/request1.xml +5 -0
  150. data/test/sfa_requests/request2.xml +5 -0
  151. data/test/sfa_requests/request3.xml +5 -0
  152. metadata +601 -0
@@ -0,0 +1,491 @@
1
+ require 'rubygems'
2
+ require 'dm-core'
3
+ require 'dm-types'
4
+ require 'dm-validations'
5
+ require 'omf_base/lobject'
6
+ require 'set'
7
+ require 'active_support/inflector'
8
+
9
+ #require 'omf-sfa/resource/oproperty'
10
+ autoload :OProperty, 'omf-sfa/resource/oproperty'
11
+ #require 'omf-sfa/resource/group_membership'
12
+ autoload :GroupMembership, 'omf-sfa/resource/group_membership'
13
+ autoload :OAccount, 'omf-sfa/resource/oaccount'
14
+ autoload :OGroup, 'omf-sfa/resource/ogroup'
15
+ autoload :OLease, 'omf-sfa/resource/olease'
16
+
17
+ # module OMF::SFA::Resource
18
+ # class OResource; end
19
+ # end
20
+ #require 'omf-sfa/resource/oaccount'
21
+
22
+ module OMF::SFA::Resource
23
+
24
+ # This is the basic resource from which all other
25
+ # resources descend.
26
+ #
27
+ # Note: Can't call it 'Resource' to avoid any confusion
28
+ # with DataMapper::Resource
29
+ #
30
+ class OResource
31
+ include OMF::Base::Loggable
32
+ extend OMF::Base::Loggable
33
+
34
+ include DataMapper::Resource
35
+ include DataMapper::Validations
36
+
37
+ #@@default_href_prefix = 'http://somehost/resources/'
38
+ @@default_href_prefix = '/resources'
39
+ @@href_resolvers = {}
40
+
41
+ @@oprops = {}
42
+
43
+ # managing dm object
44
+ property :id, Serial
45
+ property :type, Discriminator
46
+
47
+ property :uuid, UUID
48
+ property :name, String
49
+ #property :href, String, :length => 255, :default => lambda {|r, m| r.def_href() }
50
+ property :urn, String, :length => 255
51
+ property :resource_type, String
52
+
53
+ has n, :o_properties, 'OProperty'
54
+ alias oproperties o_properties
55
+
56
+
57
+ #has n, :contained_in_groups, :model => :Group, :through => GroupMembership
58
+ #has n, :contained_in_groups, 'Group' #, :through => :group_membership #GroupMembership
59
+
60
+ #has n, :group_memberships
61
+ #has n, :groups, 'Group', :through => :group_membership #, :via => :groups
62
+
63
+ has n, :group_memberships, :child_key => [ :o_resource_id ]
64
+ has n, :included_in_groups, 'OGroup', :through => :group_memberships, :via => :o_group
65
+
66
+
67
+ #belongs_to :account, :model => 'OAccount', :child_key => [ :account_id ], :required => false
68
+
69
+ def self.href_resolver(&block)
70
+ @@href_resolvers[self] = block
71
+ end
72
+
73
+ def self.oproperty(name, type, opts = {})
74
+ name = name.to_s
75
+
76
+ # should check if +name+ is already used
77
+ op = @@oprops[self] ||= {}
78
+ opts[:__type__] = type
79
+
80
+ if opts[:functional] == false
81
+ # property is an array
82
+ pname = DataMapper::Inflector.pluralize(name)
83
+ op[pname] = opts
84
+
85
+ define_method pname do
86
+ res = oproperty_get(pname)
87
+ if res == nil
88
+ oproperty_set(pname, [])
89
+ # We make a oproperty_get in order to get the extended Array with
90
+ # the overidden '<<' method. Check module ArrayProxy in oproperty.rb
91
+ res = oproperty_get(pname)
92
+ end
93
+ #puts "PROPERTY_GET(#{pname}) #{res}"
94
+ if rev_m = opts[:inverse]
95
+ res.on_modified do |v, added|
96
+ if added
97
+ if v.respond_to?(m = "#{rev_m}_add".to_sym)
98
+ v.send(m, self)
99
+ elsif v.respond_to?(m = "#{rev_m}=".to_sym)
100
+ v.send(m, self)
101
+ else
102
+ raise "Can't find any setter '#{rev_m}' on '#{v}'"
103
+ end
104
+ else
105
+ # TODO: should remove this one form the reverse side
106
+ end
107
+ end
108
+ end
109
+ if sf = opts[:set_filter]
110
+ res.on_set do |v|
111
+ self.send(sf, v)
112
+ end
113
+ end
114
+ res
115
+ end
116
+
117
+ # Add method to add a single element to a non-functional property. This
118
+ # helps other entities to learn if this property is functional or not.
119
+ #
120
+ define_method "#{pname}_add" do |v|
121
+ self.send(pname.to_sym) << v
122
+ end
123
+
124
+ define_method "#{pname}=" do |v|
125
+ unless v.is_a? Array
126
+ raise "Property '#{pname}' in '#{self.class}' requires an Array in setter - #{v.inspect}"
127
+ end
128
+ res = self.send(pname.to_sym)
129
+ res.clear # clear any old values
130
+ v.each {|it| res << it }
131
+ res
132
+ end
133
+ else
134
+ op[name] = opts
135
+
136
+ define_method name do
137
+ res = oproperty_get(name)
138
+ if res.nil?
139
+ res = opts[:default]
140
+ if res.nil? && (self.respond_to?(m = "default_#{name}".to_sym))
141
+ res = send(m)
142
+ end
143
+ end
144
+ res
145
+ end
146
+
147
+ define_method "#{name}=" do |v|
148
+ if sf = opts[:set_filter]
149
+ v = self.send(sf, v)
150
+ end
151
+ return if (old = oproperty_get(name)) == v
152
+ oproperty_set(name, v)
153
+ if rev_m = opts[:inverse]
154
+ if v
155
+ if v.respond_to?(m = "#{rev_m}_add".to_sym)
156
+ v.send(m, self)
157
+ elsif v.respond_to?(m = "#{rev_m}=".to_sym)
158
+ v.send(m, self)
159
+ else
160
+ raise "Can't find any setter '#{rev_m}' on '#{v}'"
161
+ end
162
+ else
163
+ # TODO: should remove this one form the reverse side
164
+ end
165
+ end
166
+ end
167
+
168
+ end
169
+ end
170
+
171
+ # Clone this resource this resource. However, the clone will have a unique UUID
172
+ #
173
+ def clone()
174
+ clone = self.class.new
175
+ attributes.each do |k, v|
176
+ next if k == :id || k == :uuid
177
+ clone.attribute_set(k, DataMapper::Ext.try_dup(v))
178
+ end
179
+ oproperties.each do |p|
180
+ clone.oproperty_set(p.name, DataMapper::Ext.try_dup(p.value))
181
+ end
182
+
183
+ clone.uuid = UUIDTools::UUID.random_create
184
+ return clone
185
+ end
186
+
187
+ def uuid()
188
+ unless uuid = attribute_get(:uuid)
189
+ uuid = self.uuid = UUIDTools::UUID.random_create
190
+ end
191
+ uuid
192
+ end
193
+
194
+ def href(opts = {})
195
+ klass = self.class
196
+ while (resolver = @@href_resolvers[klass]).nil?
197
+ break if (klass = klass.superclass) == Object
198
+ end
199
+ if resolver
200
+ href = resolver.call(self, opts)
201
+ end
202
+ unless href
203
+ href = "/resources/#{self.uuid.to_s}"
204
+ end
205
+
206
+ # if prefix = opts[:name_prefix]
207
+ # href = "#{prefix}/#{self.name || self.uuid.to_s}"
208
+ # elsif opts[:href_use_class_prefix]
209
+ # #href = "/#{self.resource_type}/#{self.name || self.uuid.to_s}"
210
+ # href = "/#{self.resource_type.pluralize}/#{self.uuid.to_s}"
211
+ # elsif prefix = opts[:href_prefix] || @@default_href_prefix
212
+ # href = "#{prefix}/#{self.uuid.to_s}"
213
+ # end
214
+ href
215
+ end
216
+
217
+ def resource_type()
218
+ unless rt = attribute_get(:resource_type)
219
+ rt = self.class.to_s.split('::')[-1].downcase
220
+ end
221
+ rt
222
+ end
223
+
224
+
225
+ # Return the status of the resource. Should be
226
+ # one of: _configuring_, _ready_, _failed_, and _unknown_
227
+ #
228
+ def status
229
+ 'unknown'
230
+ end
231
+
232
+ def oproperty(pname)
233
+ self.oproperties.first(:name => pname.to_sym)
234
+ end
235
+
236
+
237
+ def oproperty_get(pname)
238
+ #puts "OPROPERTY_GET: pname:'#{pname}'"
239
+ pname = pname.to_sym
240
+ return self.name if pname == :name
241
+
242
+ prop = self.oproperties.first(:name => pname)
243
+ prop.nil? ? nil : prop.value
244
+ end
245
+ alias_method :[], :oproperty_get
246
+
247
+ def oproperty_set(pname, value, type = nil)
248
+ #puts "OPROPERTY_SET pname:'#{pname}', value:'#{value.class}'-#{type}, self:'#{self.inspect}'"
249
+ pname = pname.to_sym
250
+ if pname == :name
251
+ self.name = value
252
+ else
253
+ self.save
254
+ #puts ">>>>>" + @@oprops[self.class][pname.to_s].to_s
255
+ prop = self.oproperties.first_or_create(:name => pname)
256
+ prop.value = value
257
+ end
258
+ value
259
+ end
260
+ alias_method :[]=, :oproperty_set
261
+
262
+ def oproperties_as_hash
263
+ res = {}
264
+ oproperties.each do |p|
265
+ res[p.name] = p.value
266
+ end
267
+ res
268
+ end
269
+
270
+ def each_resource(&block)
271
+ # resources don't contain other resources, groups do'
272
+ end
273
+
274
+ # alias_method :_dirty_children?, :dirty_children?
275
+ # def dirty_children?
276
+ # puts "CHECKING CHILDREN DIRTY: #{_dirty_children?}"
277
+ # _dirty_children?
278
+ # end
279
+
280
+ alias_method :_dirty_self?, :dirty_self?
281
+ def dirty_self?
282
+ #puts "CHECKING DIRTY #{_dirty_self?}"
283
+ return true if _dirty_self?
284
+ o_properties.each do |p|
285
+ return true if p.dirty_self?
286
+ end
287
+ false
288
+ end
289
+
290
+ # alias_method :_dirty_attributes, :dirty_attributes
291
+ # def dirty_attributes
292
+ # dirty = _dirty_attributes
293
+ # puts "DIRTY ATTRIBUTE #{dirty.inspect}"
294
+ # dirty
295
+ # end
296
+
297
+ # Return true if this resource is a Group
298
+ def group?
299
+ false
300
+ end
301
+
302
+
303
+ # Remove this resource from all groups it currently belongs.
304
+ #
305
+ def remove_from_all_groups
306
+ self.group_memberships.each {|m| m.destroy}
307
+ end
308
+
309
+ # Add this resource and all contained to +set+.
310
+ def all_resources(set = Set.new)
311
+ set << self
312
+ set
313
+ end
314
+
315
+
316
+ before :save do
317
+ unless self.uuid
318
+ self.uuid = UUIDTools::UUID.random_create
319
+ end
320
+ unless self.name
321
+ self.name = self.urn ? GURN.create(self.urn).short_name : "r#{self.object_id}"
322
+ end
323
+ unless self.urn
324
+ # The purpose or function of a URN is to provide a globally unique,
325
+ # persistent identifier used for recognition, for access to
326
+ # characteristics of the resource or for access to the resource
327
+ # itself.
328
+ # source: http://tools.ietf.org/html/rfc1737
329
+ #
330
+ name = self.name
331
+ self.urn = GURN.create(name, :model => self.class).to_s
332
+ end
333
+ end
334
+
335
+ def destroy
336
+ #debug "ORESOURCE destroy #{self}"
337
+ self.remove_from_all_groups
338
+
339
+ #if p = self.provided_by
340
+ # pa = p.provides
341
+ # pa.delete self
342
+ # r = p.save
343
+ # i = 0
344
+ #end
345
+
346
+ # first destroy all properties
347
+ self.oproperties.all().each do |p|
348
+ #debug "ORESOURCE destroying property '#{p.inspect}'"
349
+ r = p.destroy
350
+ r
351
+ end
352
+ #p = self.oproperties.all()
353
+ super
354
+ end
355
+
356
+ def destroy!
357
+ #debug "ORESOURCE destroy! #{self}"
358
+ destroy
359
+ super
360
+ end
361
+
362
+ def to_json(*a)
363
+ unless self.id
364
+ # need an id, means I haven't been saved yet
365
+ save
366
+ end
367
+ {
368
+ 'json_class' => self.class.name,
369
+ 'id' => self.id
370
+ }.to_json(*a)
371
+ end
372
+
373
+ def as_json(options = { })
374
+ {
375
+ "json_class" => self.class.name,
376
+ "id" => self.id
377
+ }
378
+ end
379
+
380
+
381
+ #def self.from_json(o)
382
+ # puts "FROM_JSON"
383
+ # klass = o['json_class']
384
+ # id = o['id']
385
+ # eval(klass).first(:id => id)
386
+ #end
387
+
388
+ def self.json_create(o)
389
+ klass = o['json_class']
390
+ id = o['id']
391
+ r = eval(klass).first(:id => id)
392
+ r
393
+ end
394
+
395
+ def to_hash(objs = {}, opts = {})
396
+ max_level = opts[:max_level] ||= 0
397
+ level = opts[:level] ||= 0
398
+ if level > max_level
399
+ return self.href
400
+ end
401
+
402
+ #debug "to_hash(self):opts: #{opts.keys.inspect}::#{objs.keys.inspect}::"
403
+ h = to_hash_brief(opts)
404
+ return h if objs.key?(self)
405
+ objs[self] = true
406
+ return h if opts[:brief] || (level >= max_level)
407
+
408
+ opts = opts.merge(level: level + 1)
409
+ opts[:brief] = true if level > max_level
410
+ #puts ">>>> #{opts}"
411
+ to_hash_long(h, objs, opts)
412
+ h
413
+ end
414
+
415
+ def to_hash_brief(opts = {})
416
+ h = {}
417
+ uuid = h[:uuid] = self.uuid.to_s
418
+ h[:href] = self.href
419
+ name = self.name
420
+ if name && ! name.start_with?('_')
421
+ h[:name] = self.name
422
+ end
423
+ h[:type] = self.resource_type
424
+ h
425
+ end
426
+
427
+ def to_hash_long(h, objs = {}, opts = {})
428
+ _oprops_to_hash(h, objs, opts)
429
+ h
430
+ end
431
+
432
+ def default_href_prefix
433
+ @@default_href_prefix
434
+ end
435
+
436
+ def _oprops_to_hash(h, objs, opts)
437
+ klass = self.class
438
+ while klass
439
+ if op = @@oprops[klass]
440
+ op.each do |k, v|
441
+ k = k.to_sym
442
+ unless (value = send(k)).nil?
443
+ #puts "OPROPS_TO_HAHS(#{k}): #{value}::#{value.class}--#{oproperty_get(k)}"
444
+ #puts "OPROPS_TO_HAHS(#{k}): #{opts[:level]} >= #{opts[:max_level]}"
445
+ if value.is_a? OResource
446
+ href_only = opts[:level] >= opts[:max_level]
447
+ value = href_only ? value.href : value.to_hash(objs, opts)
448
+ #value = value.to_hash(objs, opts)
449
+ end
450
+ if value.is_a? Time
451
+ value = value.iso8601
452
+ end
453
+ if value.kind_of? Array
454
+ next if value.empty?
455
+ opts = opts.merge(level: opts[:level] + 1)
456
+ value = value.collect do |e|
457
+ #(e.kind_of? OResource) ? (href_only ? e.href : e.to_hash(objs, opts)) : e
458
+ (e.kind_of? OResource) ? e.to_hash(objs, opts) : e
459
+ end
460
+ end
461
+
462
+ h[k] = value
463
+ end
464
+ end
465
+ end
466
+ klass = klass.superclass
467
+ end
468
+ h
469
+ end
470
+ end
471
+
472
+ # Extend array to add functionality dealing with property values
473
+ #class PropValueArray < Array
474
+
475
+ # def to_json(*a)
476
+ # {
477
+ # 'json_class' => self.class.name,
478
+ # 'els' => self.to_a.to_json
479
+ # }.to_json(*a)
480
+ # end
481
+
482
+ # def self.json_create(o)
483
+ # # http://www.ruby-lang.org/en/news/2013/02/22/json-dos-cve-2013-0269/
484
+ # v = JSON.load(o['els'])
485
+ # v
486
+ # end
487
+
488
+ #end
489
+
490
+ end # OMF::SFA
491
+
@@ -0,0 +1,28 @@
1
+ require 'omf-sfa/resource/oresource'
2
+ require 'omf-sfa/resource/project_membership'
3
+ require 'omf-sfa/resource/user'
4
+
5
+ module OMF::SFA::Resource
6
+
7
+ # This class represents a Project which is strictly connected to the notion of the Slice/Account
8
+ #
9
+ class Project < OResource
10
+
11
+ #has 1, :account, :model => 'OAccount', :required => false
12
+ oproperty :account, :account, :inverse => :project
13
+
14
+ oproperty :users, :user, :functional => false, :inverse => :projects
15
+ # has n, :project_memberships
16
+ # has n, :users, :through => :project_memberships, :via => :user
17
+
18
+ def to_hash_long(h, objs, opts = {})
19
+ super
20
+ href_only = opts[:level] >= opts[:max_level]
21
+ h[:users] = self.users.map do |p|
22
+ href_only ? p.href : p.to_hash(objs, opts)
23
+ end
24
+ h
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,13 @@
1
+
2
+ module OMF::SFA::Resource
3
+
4
+ # Provides a many-to-many relationship
5
+ # between Users and Projects
6
+ #
7
+ class ProjectMembership
8
+ include DataMapper::Resource
9
+
10
+ belongs_to :project, :key => true
11
+ belongs_to :user, :key => true
12
+ end
13
+ end