1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 '''
20 The web handling part of the OCCI service.
21
22 Created on Jun 27, 2011
23
24 @author: tmetsch
25 '''
26
27 from occi import workflow
28 from occi.exceptions import HTTPError
29
30
31
32
33
34 CONTENT_TYPE = 'Content-Type'
35 ACCEPT = 'Accept'
36 LINK = 'Link'
37 LOCATION = 'X-OCCI-Location'
38 ATTRIBUTE = 'X-OCCI-Attribute'
39 CATEGORY = 'Category'
40 QUERY_STRING = 'Query_String'
41
42
44 '''
45 General request handler.
46 '''
47
48
49
50
51 - def __init__(self, registry, headers, body, query, extras=None):
52 self.registry = registry
53 self.headers = headers
54 self.body = body
55 self.query = query
56
57 self.extras = extras
58
59 - def handle(self, method, key):
60 '''
61 Call a HTTP method function on this handler. E.g. when method is HTTP
62 GET the function get(key) will be called. If the function is not
63 defined a 405 is returned.
64
65 method -- The HTTP method name.
66 key -- The key of the resource.
67 '''
68 try:
69 return getattr(self, str.lower(method))(key)
70 except AttributeError:
71 return 405, {'Content-type': 'text/plain'}, 'Method not supported.'
72
84
85 - def response(self, status, headers=None, body='OK'):
86 '''
87 Will try to figure out what rendering the client wants and return back
88 the given status, header and boy.
89
90 status -- The status code.
91 headers -- The HTTP headers (default: empty).
92 body -- The text for the body (default: 'ok').
93 '''
94 rendering = self.get_renderer(ACCEPT)
95
96 if headers is None:
97 headers = {}
98
99 headers['Content-Type'] = rendering.mime_type
100
101 return status, headers, body
102
113
115 '''
116 Retrieve any attributes or categories which where provided in the
117 request for filtering.
118 '''
119 attr = ATTRIBUTE
120 cat = CATEGORY
121 if attr not in self.headers:
122
123 if cat not in self.headers and self.body == '':
124 return [], {}
125
126 rendering = self.get_renderer(CONTENT_TYPE)
127
128 categories, attributes = rendering.get_filters(self.headers, self.body,
129 self.extras)
130
131 return categories, attributes
132
134 '''
135 Retrieves the entity which was rendered within the request.
136
137 def_kind -- Indicates if the request can be incomplete (False).
138 '''
139 rendering = self.get_renderer(CONTENT_TYPE)
140
141 entity = rendering.to_entity(self.headers, self.body, def_kind,
142 self.extras)
143 return entity
144
154
164
166 '''
167 Renders a single entity to the client.
168
169 entity -- The entity which should be rendered.
170 '''
171 rendering = self.get_renderer(ACCEPT)
172
173 headers, body = rendering.from_entity(entity)
174
175 return 200, headers, body
176
178 '''
179 Renders a list of entities to the client.
180
181 entities -- The entities which should be rendered.
182 '''
183 rendering = self.get_renderer(ACCEPT)
184
185 headers, body = rendering.from_entities(entities, key)
186
187 return 200, headers, body
188
190 '''
191 Renders a list of categories to the client.
192
193 categories -- The categories which should be rendered.
194 '''
195 rendering = self.get_renderer(ACCEPT)
196
197 headers, body = rendering.from_categories(categories)
198
199 return 200, headers, body
200
201
203 '''
204 Handles the request on single resource instances.
205 '''
206
207 - def get(self, key):
221
222 - def post(self, key):
223 '''
224 Do a HTTP POST on a resource.
225
226 key -- The resource id.
227 '''
228 if self.query is not ():
229
230 try:
231 entity = self.registry.get_resource(key, self.extras)
232 action, attr = self.parse_action()
233
234 workflow.action_entity(entity, action, self.registry, attr,
235 self.extras)
236
237 return self.render_entity(entity)
238 except AttributeError as attr:
239 raise HTTPError(400, str(attr))
240 except KeyError as key_error:
241 raise HTTPError(404, str(key_error))
242 else:
243
244 try:
245 old = self.registry.get_resource(key, self.extras)
246 new = self.parse_entity(def_kind=old.kind)
247
248 workflow.update_entity(old, new, self.registry, self.extras)
249
250 return self.render_entity(old)
251 except AttributeError as attr:
252 raise HTTPError(400, str(attr))
253 except KeyError as key_error:
254 raise HTTPError(404, str(key_error))
255
256 - def put(self, key):
257 '''
258 Do a HTTP PUT on a resource.
259
260 key -- The resource id.
261 '''
262 if key in self.registry.get_resource_keys(self.extras):
263
264 try:
265 old = self.registry.get_resource(key, self.extras)
266 new = self.parse_entity()
267
268 workflow.replace_entity(old, new, self.registry, self.extras)
269
270 return self.render_entity(old)
271 except AttributeError as attr:
272 raise HTTPError(400, str(attr))
273 else:
274
275 try:
276 entity = self.parse_entity()
277
278 workflow.create_entity(key, entity, self.registry, self.extras)
279
280 heads = {'Location': self.registry.get_hostname()
281 + entity.identifier}
282 return self.response(201, heads)
283 except AttributeError as attr:
284 raise HTTPError(400, str(attr))
285
287 '''
288 Do a HTTP DELETE on a resource.
289
290 key -- The resource id.
291 '''
292
293 try:
294 entity = self.registry.get_resource(key, self.extras)
295
296 workflow.delete_entity(entity, self.registry, self.extras)
297
298 return self.response(200)
299 except AttributeError as attr:
300 raise HTTPError(400, str(attr))
301 except KeyError as key_error:
302 raise HTTPError(404, str(key_error))
303
304
306 '''
307 Handles all operations on collections.
308 '''
309
310 - def get(self, key):
326
327 - def post(self, key):
328 '''
329 Do a HTTP POST on a collection.
330
331 key -- The resource id.
332 '''
333 if self.query is not ():
334
335 try:
336 action, attr = self.parse_action()
337 entities = workflow.get_entities_under_path(key, self.registry,
338 self.extras)
339 for entity in entities:
340 workflow.action_entity(entity, action, self.registry, attr,
341 self.extras)
342
343 return self.response(200)
344 except AttributeError as attr:
345 raise HTTPError(400, str(attr))
346 elif not len(self.parse_entities()):
347
348 try:
349 entity = self.parse_entity()
350 workflow.create_entity(workflow.create_id(entity.kind),
351 entity, self.registry, self.extras)
352
353 heads = {'Location': self.registry.get_hostname()
354 + entity.identifier}
355 return self.response(201, heads)
356 except AttributeError as attr:
357 raise HTTPError(400, str(attr))
358 elif len(self.parse_entities()) > 0:
359
360 try:
361 mixin = self.registry.get_category(key, self.extras)
362 new_entities = self.parse_entities()
363 old_entities = workflow.get_entities_under_path(key,
364 self.registry,
365 self.extras)
366 workflow.update_collection(mixin, old_entities,
367 new_entities, self.registry,
368 self.extras)
369
370 return self.response(200)
371 except AttributeError as attr:
372 raise HTTPError(400, str(attr))
373
374 - def put(self, key):
392
418
419
421 '''
422 Handles the Query interface.
423 '''
424
425
426
427
428
429 - def get(self, key=None):
430 '''
431 Do a HTTP GET on the query interface.
432
433 key -- The resource id.
434 '''
435
436 try:
437 categories, attributes = self.parse_filter()
438
439 result = workflow.filter_categories(categories, self.registry,
440 self.extras)
441
442 return self.render_categories(result)
443 except AttributeError as attr:
444 raise HTTPError(400, str(attr))
445
446 - def post(self, key=None):
447 '''
448 Do a HTTP POST on the query interface.
449
450 key -- The resource id.
451 '''
452
453 try:
454 mixins = self.parse_mixins()
455
456 workflow.append_mixins(mixins, self.registry, self.extras)
457
458 return self.render_categories(mixins)
459 except AttributeError as attr:
460 raise HTTPError(400, str(attr))
461
463 '''
464 Do a HTTP DELETE on the query interface.
465
466 key -- The resource id.
467 '''
468
469 try:
470 categories, attributes = self.parse_filter()
471
472 workflow.remove_mixins(categories, self.registry, self.extras)
473
474 return self.response(200)
475 except AttributeError as attr:
476 raise HTTPError(400, str(attr))
477