Package occi :: Module workflow
[hide private]
[frames] | no frames]

Source Code for Module occi.workflow

  1  # coding=utf-8 
  2  # 
  3  # Copyright (C) 2010-2012 Platform Computing 
  4  # 
  5  # This library is free software; you can redistribute it and/or 
  6  # modify it under the terms of the GNU Lesser General Public 
  7  # License as published by the Free Software Foundation; either 
  8  # version 2.1 of the License, or (at your option) any later version. 
  9  # 
 10  # This library is distributed in the hope that it will be useful, 
 11  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
 13  # Lesser General Public License for more details. 
 14  # 
 15  # You should have received a copy of the GNU Lesser General Public 
 16  # License along with this library; if not, write to the Free Software 
 17  # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA 
 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  # Handling of Resources & Links 
 34  #============================================================================== 
 35   
 36   
37 -def create_entity(key, entity, registry, extras):
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 # if it is an resource we create make sure we create the links properly 53 if isinstance(entity, Resource): 54 # if it's a resource - set/create links properly. 55 for link in entity.links: 56 # FUTURE_IMPROVEMENT: string links 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 # call all the backends who are associated with this entity.kind... 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
77 -def delete_entity(entity, registry, extras):
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 # it's an resource - so delete all it's links 89 # FUTURE_IMPROVEMENT: string links 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 # call all the backends who are associated with this entity.kind... 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
106 -def replace_entity(old, new, registry, extras):
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 # call all the backends who are associated with this entity.kind... 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
137 -def update_entity(old, new, registry, extras):
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 # call all the backends who are associated with this entity.kind... 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 # for added mixins called create! 159 backend.create(old, extras) 160 161 del new
162 163
164 -def retrieve_entity(entity, registry, extras):
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 # if it's a resource - retrieve all links... 176 for link in entity.links: 177 # FUTURE_IMPROVEMENT: string links 178 for back in registry.get_all_backends(link, extras): 179 back.retrieve(link, extras) 180 181 # call all the backends who are associated with this entity.kind... 182 backends = registry.get_all_backends(entity, extras) 183 for backend in backends: 184 backend.retrieve(entity, extras)
185 186
187 -def action_entity(entity, action, registry, attributes, extras):
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 # Collections 202 #============================================================================== 203 204
205 -def update_collection(mixin, old_entities, new_entities, registry, extras):
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
226 -def replace_collection(mixin, old_entities, new_entities, registry, extras):
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
253 -def delete_from_collection(mixin, entities, registry, extras):
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
272 -def get_entities_under_path(path, registry, extras):
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
299 -def filter_entities(entities, categories, attributes):
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 # Query Interface 333 #============================================================================== 334 335
336 -def filter_categories(categories, registry, extras):
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
355 -def append_mixins(mixins, registry, extras):
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
380 -def remove_mixins(mixins, registry, extras):
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 # Convenient stuff 408 #============================================================================== 409 410
411 -def create_id(kind):
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
421 -def intersect(list_a, list_b):
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
434 -def unique(list_a, list_b):
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