1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 '''
20 Python module holding routines for handling resources and collections.
21
22 Created on Jun 30, 2011
23
24 @author: tmetsch
25 '''
26
27 from occi.backend import UserDefinedMixinBackend
28 from occi.core_model import Resource, Link, Mixin
29 from occi.exceptions import HTTPError
30 import uuid
31
32
33
34
35
36
38 '''
39 Handles all the model magic during creation of an entity.
40
41 If it's an resource it will verify that all links are created.
42
43 If it's a link it will ensure that source and target are properly set.
44
45 key -- The key for the entity.
46 entity -- The entity itself - either Link or Resource instance.
47 registry -- The registry used for this process.
48 extras -- Any extra arguments which are defined by the user.
49 '''
50 entity.identifier = key
51
52
53 if isinstance(entity, Resource):
54
55 for link in entity.links:
56
57 if link.identifier is None:
58 link.identifier = create_id(link.kind)
59 elif link.identifier in registry.get_resource_keys(extras):
60 raise AttributeError('A link with that id is already present')
61
62 for back in registry.get_all_backends(link, extras):
63 back.create(link, extras)
64
65 registry.add_resource(link.identifier, link, extras)
66 elif isinstance(entity, Link):
67 entity.source.links.append(entity)
68
69
70 backends = registry.get_all_backends(entity, extras)
71 for backend in backends:
72 backend.create(entity, extras)
73
74 registry.add_resource(key, entity, extras)
75
76
78 '''
79 Handles all the model magic during deletion if an entity.
80
81 If it's a link it will remove the link from the entity source links list.
82
83 entity -- The entity itself - either Link or Resource instance.
84 registry -- The registry used for this process.
85 extras -- Any extra arguments which are defined by the user.
86 '''
87 if isinstance(entity, Resource):
88
89
90 for link in entity.links:
91 for back in registry.get_all_backends(link, extras):
92 back.delete(link, extras)
93 registry.delete_resource(link.identifier, extras)
94 elif isinstance(entity, Link):
95 entity.source.links.remove(entity)
96
97
98 backends = registry.get_all_backends(entity, extras)
99
100 for backend in backends:
101 backend.delete(entity, extras)
102
103 registry.delete_resource(entity.identifier, extras)
104
105
107 '''
108 Replace an entity - backends decide what is done.
109
110 If it's a link the entities must be replaced.
111
112 old -- The old entity.
113 new -- The new entity.
114 registry -- The registry used for this process.
115 extras -- Any extra arguments which are defined by the user.
116 '''
117 if isinstance(new, Resource) and len(new.links) is not 0:
118 raise HTTPError(400, 'It is not recommend to have links in a full' +
119 ' update request')
120
121 if new.kind is not old.kind:
122 raise AttributeError('It is not possible to change the kind of an' +
123 ' entity.')
124
125
126 backends = registry.get_all_backends(old, extras)
127 new_backends = registry.get_all_backends(new, extras)
128 for backend in backends:
129 backend.replace(old, new, extras)
130 for backend in unique(new_backends, backends):
131 backend.create(new, extras)
132 for backend in unique(backends, new_backends):
133 backend.delete(old, extras)
134 del new
135
136
138 '''
139 Update an entity - backends decide what is done.
140
141 If it's a link the entities must be updated.
142
143 old -- The old entity.
144 new -- The new entity.
145 registry -- The registry used for this process.
146 extras -- Any extra arguments which are defined by the user.
147 '''
148 if isinstance(new, Resource) and len(new.links) is not 0:
149 raise HTTPError(400, 'It is not recommend to have links in a full' +
150 ' update request')
151
152
153 backends = registry.get_all_backends(old, extras)
154 new_backends = registry.get_all_backends(new, extras)
155 for backend in backends:
156 backend.update(old, new, extras)
157 for backend in unique(new_backends, backends):
158
159 backend.create(old, extras)
160
161 del new
162
163
165 '''
166 Retrieves/refreshed an entity.
167
168 If it's a link the entities must be retrieved/refreshed.
169
170 entity -- The entity which is to be retrieved.
171 registry -- The registry used for this process.
172 extras -- Any extra arguments which are defined by the user.
173 '''
174 if isinstance(entity, Resource):
175
176 for link in entity.links:
177
178 for back in registry.get_all_backends(link, extras):
179 back.retrieve(link, extras)
180
181
182 backends = registry.get_all_backends(entity, extras)
183 for backend in backends:
184 backend.retrieve(entity, extras)
185
186
188 '''
189 Performs an action on the entity.
190
191 entity -- The entity on which to perform the operation.
192 action -- The action definition.
193 registry -- The registry used for this process.
194 attributes -- The attributes fro the operation.
195 extras -- Any extra arguments which are defined by the user.
196 '''
197 backend = registry.get_backend(action, extras)
198 backend.action(entity, action, attributes, extras)
199
200
201
202
203
204
206 '''
207 Updates a Collection of Mixin. If not present in the current collections
208 entities will be added to the collection (aka. assigned the Mixin).
209
210 mixin -- The mixin which defines the collection.
211 old_entities -- The entities which are in the collection to date.
212 new_entities -- The entities which should be added to the collection.
213 registry -- The registry used for this process.
214 extras -- Any extra arguments which are defined by the user.
215 '''
216 if not isinstance(mixin, Mixin):
217 raise AttributeError('This operation is only supported on Collections'
218 + ' of Mixins.')
219 for entity in unique(new_entities, old_entities):
220 entity.mixins.append(mixin)
221 backend = registry.get_backend(mixin, extras)
222 backend.create(entity, extras)
223 del new_entities
224
225
227 '''
228 Replaces a Collection of Mixin. If not present in the current collections
229 entities will be added to the collection (aka. assigned the Mixin). If old
230 entities are not present in the new collection the mixin will be removed
231 from them.
232
233 mixin -- The mixin which defines the collection.
234 old_entities -- The entities which are in the collection to date.
235 new_entities -- The new collection of entities.
236 registry -- The registry used for this process.
237 extras -- Any extra arguments which are defined by the user.
238 '''
239 if not isinstance(mixin, Mixin):
240 raise AttributeError('This operation is only supported on Collections'
241 + ' of Mixins.')
242 for entity in unique(new_entities, old_entities):
243 entity.mixins.append(mixin)
244 backend = registry.get_backend(mixin, extras)
245 backend.create(entity, extras)
246 for entity in unique(old_entities, new_entities):
247 backend = registry.get_backend(mixin, extras)
248 backend.delete(entity, extras)
249 entity.mixins.remove(mixin)
250 del new_entities
251
252
254 '''
255 Removes entities from a collection by removing the mixin from their list.
256
257 mixin -- The mixin which defines the collection.
258 entities -- The entities which are to be removed.
259 registry -- The registry used for this process.
260 extras -- Any extra arguments which are defined by the user.
261 '''
262 if not isinstance(mixin, Mixin):
263 raise AttributeError('This operation is only supported on Collections'
264 + ' of Mixins.')
265
266 for entity in intersect(entities, registry.get_resources(extras)):
267 backend = registry.get_backend(mixin, extras)
268 backend.delete(entity, extras)
269 entity.mixins.remove(mixin)
270
271
273 '''
274 Return all entities which fall under a path.
275
276 If the path is in locations return all entities of the kind which defines
277 the location.
278
279 If the path is just a path return all children.
280
281 path -- The path under which to look...
282 registry -- The registry used for this process.
283 extras -- Any extra arguments which are defined by the user.
284 '''
285 result = []
286 if registry.get_category(path, extras) is None:
287 for res in registry.get_resources(extras):
288 if not res.identifier.find(path):
289 result.append(res)
290 return result
291 else:
292 cat = registry.get_category(path, extras)
293 for res in registry.get_resources(extras):
294 if cat == res.kind or cat in res.mixins:
295 result.append(res)
296 return result
297
298
300 '''
301 Filters a set of entities and return those who match the given categories
302 and attributes.
303
304 entities -- The entities which are to be filtered.
305 categories -- Categories which must be present in the entity.
306 attributes -- Attributes which must match with the entity's attrs.
307 '''
308 result = []
309 if len(categories) == 0 and len(attributes.keys()) == 0:
310 return entities
311
312 for entity in entities:
313 indy = 0
314 if entity.kind in categories:
315 indy += 1
316 if len(intersect(categories, entity.mixins)):
317 indy += 1
318 for attr in intersect(attributes.keys(), entity.attributes.keys()):
319 if entity.attributes[attr] == attributes[attr]:
320 indy += 3
321
322 if len(categories) > 0 and len(attributes.keys()) == 0 and indy >= 1:
323 result.append(entity)
324 elif len(categories) == 0 and len(attributes.keys()) > 0 and indy == 3:
325 result.append(entity)
326 elif len(categories) > 0 and len(attributes.keys()) > 0 and indy >= 4:
327 result.append(entity)
328
329 return result
330
331
332
333
334
335
337 '''
338 Filter the categories. Only those requested should be added to the
339 resulting list.
340
341 categories -- The list of categories to filter against.
342 registry -- The registry used for this process.
343 extras -- Passed on extra object.
344 '''
345 if not len(categories):
346 return registry.get_categories(extras)
347
348 result = []
349 for cat in registry.get_categories(extras):
350 if cat in categories:
351 result.append(cat)
352 return result
353
354
356 '''
357 Add a mixin to the service.
358
359 mixins -- The mixins which are to be added.
360 registry -- The registry used for this process.
361 extras -- Passed on extra object.
362 '''
363 for mixin in mixins:
364 if not isinstance(mixin, Mixin):
365 raise AttributeError('Needs to be of type Mixin.')
366 if registry.get_category(mixin.location, extras):
367 raise AttributeError('Location overlaps with existing one.')
368
369 try:
370 registry.get_backend(mixin, extras)
371 except AttributeError:
372 pass
373 else:
374 raise AttributeError('Category with same term, scheme already' +
375 ' exists.')
376
377 registry.set_backend(mixin, UserDefinedMixinBackend(), extras)
378
379
381 '''
382 Remove a mixin from the service.
383
384 mixins -- The mixin which are to be removed.
385 registry -- The registry used for this process.
386 extras -- Any extra arguments which are defined by the user.
387 '''
388 for mixin in mixins:
389 if not isinstance(mixin, Mixin):
390 raise AttributeError('Needs to be of type Mixin.')
391
392 try:
393 backend = registry.get_backend(mixin, extras)
394 except AttributeError:
395 raise HTTPError(400, 'This Mixin is not registered!')
396
397 if not isinstance(backend, UserDefinedMixinBackend):
398 raise HTTPError(403, 'This Mixin cannot be deleted!')
399
400 entities = get_entities_under_path(mixin.location, registry, extras)
401 for entity in entities:
402 entity.mixins.remove(mixin)
403 registry.delete_mixin(mixin, extras)
404 del mixin
405
406
407
408
409
410
412 '''
413 Create a key with the hierarchy of the entity encapsulated.
414
415 kind -- The kind which this id should be created for.
416 '''
417 key = kind.location + str(uuid.uuid4())
418 return key
419
420
422 '''
423 Returns the intersection of two lists.
424
425 list_a -- The first list.
426 list_b -- Another list.
427 '''
428 if len(list_a) > 0 and len(list_b) > 0:
429 return list(set(list_a) & set(list_b))
430 else:
431 return list()
432
433
435 '''
436 Returns a list of elements which are only in list_a.
437
438 list_a -- The list to look into for unique elements.
439 list_b -- Ths list the verify against.
440 '''
441 return [item for item in list_a if item not in list_b]
442