|
1 # |
|
2 # Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 # All rights reserved. |
|
4 # This component and the accompanying materials are made available |
|
5 # under the terms of "Eclipse Public License v1.0" |
|
6 # which accompanies this distribution, and is available |
|
7 # at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 # |
|
9 # Initial Contributors: |
|
10 # Nokia Corporation - initial contribution. |
|
11 # |
|
12 # Contributors: |
|
13 # |
|
14 # Description: |
|
15 # |
|
16 |
|
17 """ |
|
18 Container classes. |
|
19 Mainly internal classed that the public data model uses internally. |
|
20 """ |
|
21 |
|
22 import re |
|
23 import pickle |
|
24 import logging |
|
25 import utils, exceptions |
|
26 |
|
27 def object_container_filter(obj,**kwargs): |
|
28 """ Create a list of filter functions for each argument """ |
|
29 filters=[] |
|
30 if kwargs.has_key('name'): |
|
31 filters.append(lambda x: re.match(kwargs.get('name'), x._name)) |
|
32 if kwargs.has_key('path'): |
|
33 filters.append(lambda x: re.match(kwargs.get('path'), x._path())) |
|
34 if kwargs.has_key('type'): |
|
35 filters.append(lambda x: isinstance(x, kwargs.get('type'))) |
|
36 if kwargs.has_key('filters'): |
|
37 filters += kwargs.get('filters') |
|
38 ret = [] |
|
39 for sobj in utils.get_list(obj): |
|
40 if utils.filter(obj,filters): |
|
41 ret.append(sobj) |
|
42 |
|
43 return ret |
|
44 |
|
45 def _apply_filter(obj,filters): |
|
46 """ Create a list of filter functions for each argument """ |
|
47 if utils.filter(obj,filters): |
|
48 return [obj] |
|
49 else: |
|
50 return [] |
|
51 |
|
52 """ object container adding policies """ |
|
53 REPLACE = 0 |
|
54 APPEND = 1 |
|
55 PREPEND = 2 |
|
56 ERROR = 3 |
|
57 |
|
58 class DataContainer(object): |
|
59 """ |
|
60 Class for data containers. |
|
61 Container is a data storage that can hold several keys, where each key is unique. Each key however |
|
62 can hold several values, where the active value is the last one added. |
|
63 |
|
64 Example: |
|
65 data = {'key1' :[1,2,3,4], |
|
66 'key2' :['foo','bar], |
|
67 'key3' :['testing'], |
|
68 'path/to/key' :['some','value','in','here','too']} |
|
69 |
|
70 The active values for keys are the last ones in the array. E.g. key1 = 4. |
|
71 """ |
|
72 def __init__(self): |
|
73 self.data = {} |
|
74 |
|
75 def list_keys(self): |
|
76 """ |
|
77 List all keys of the DataStorage. |
|
78 """ |
|
79 return self.data.keys() |
|
80 |
|
81 def add_value(self,key,value): |
|
82 """ |
|
83 Add the value as a topmost item for the given key. |
|
84 @param key: name for the key to store the data. |
|
85 @param value: the value to store. |
|
86 """ |
|
87 if self.data.has_key(key): |
|
88 self.data[key].append(value) |
|
89 else: |
|
90 self.data[key] = [value] |
|
91 return |
|
92 |
|
93 def remove_value(self,key,value): |
|
94 """ |
|
95 remove individual value of the key value array |
|
96 """ |
|
97 self.data[key].remove(value) |
|
98 return |
|
99 |
|
100 def remove_key(self,key): |
|
101 del self.data[key] |
|
102 return |
|
103 |
|
104 def get_value(self,key): |
|
105 """ |
|
106 self.data = {'key1' :[1,2,3,4], |
|
107 'key2' :['foo','bar], |
|
108 'key3' :['testing'], |
|
109 'path/to/key' :['some','value','in','here','too']} |
|
110 self.get_value('key1') |
|
111 4 |
|
112 """ |
|
113 return self.data[key][-1] |
|
114 |
|
115 def get_values(self,key): |
|
116 """ |
|
117 return a copy of data values inside the container |
|
118 """ |
|
119 values = [] |
|
120 values.extend(self.data[key]) |
|
121 return values |
|
122 |
|
123 def flatten(self): |
|
124 """ |
|
125 return a new dictionary of the DataContainer data with only single values for each key, |
|
126 instead of the array of values. |
|
127 """ |
|
128 rest = {} |
|
129 for key in self.data.keys(): |
|
130 rest[key] = self.get_value(key) |
|
131 return rest |
|
132 |
|
133 def clear(self): |
|
134 """ |
|
135 Remove all data from the container. |
|
136 """ |
|
137 return self.data.clear() |
|
138 |
|
139 class ContainerBase(object): |
|
140 |
|
141 def _set_parent(self, newparent): |
|
142 """ |
|
143 @param newparent: The new parent object |
|
144 @return: None |
|
145 """ |
|
146 self._parent = newparent |
|
147 |
|
148 def _get_parent(self): |
|
149 """ |
|
150 @return: existing parent object |
|
151 """ |
|
152 return self._parent |
|
153 |
|
154 def _del_parent(self): |
|
155 """ |
|
156 Set the current parent to None |
|
157 """ |
|
158 self._parent = None |
|
159 |
|
160 parent = property(_get_parent, _set_parent,_del_parent) |
|
161 |
|
162 |
|
163 class ObjectProxy(ContainerBase): |
|
164 """ |
|
165 An object proxy class. The ObjectProxy overrides the python builtin methdo __getattr__ |
|
166 to redirect any function/member access to the subobject. |
|
167 """ |
|
168 def __init__(self,obj=None): |
|
169 """ |
|
170 """ |
|
171 self._obj = obj |
|
172 self._parent = None |
|
173 |
|
174 def __getattr__(self,name): |
|
175 """ |
|
176 direct all not found attribute calls to the sub object getattr |
|
177 """ |
|
178 return getattr(self._obj,name) |
|
179 |
|
180 |
|
181 # def _set_parent(self, newparent): |
|
182 # """ |
|
183 # @param newparent: The new parent object |
|
184 # @return: None |
|
185 # """ |
|
186 # self._parent = newparent |
|
187 # if isinstance(self._obj, ContainerBase): |
|
188 # self._obj._set_parent(newparent) |
|
189 |
|
190 class LoadInterface(ContainerBase): |
|
191 def load(self,ref): |
|
192 file = open(ref,"r") |
|
193 self._parent = None |
|
194 return pickle.load(file) |
|
195 |
|
196 def unload(self,ref, obj): |
|
197 """ |
|
198 unload or release |
|
199 """ |
|
200 file = open(ref,"w") |
|
201 pickle.dump(obj,file) |
|
202 file.close() |
|
203 |
|
204 def get_path(self): |
|
205 """ |
|
206 Return the path of the configuration resource |
|
207 """ |
|
208 return "" |
|
209 |
|
210 class LoadProxy(ContainerBase): |
|
211 """ |
|
212 This class is meant for loading & unloading an object, when it need. |
|
213 """ |
|
214 def __init__(self, path, store_interface=None): |
|
215 """ |
|
216 @param path: the path which is used in loadin |
|
217 @param store_interface: the loading interface object, which is used. |
|
218 Expects load(path) and dump(obj) functions |
|
219 """ |
|
220 self.set('_obj', None) |
|
221 self.set('_parent', None) |
|
222 self.set('path', path) |
|
223 self.set('_storeint', store_interface) |
|
224 |
|
225 def __getattr__(self,name): |
|
226 """ |
|
227 direct all not found attribute calls to the sub object getattr |
|
228 """ |
|
229 if not self._obj: |
|
230 self._load() |
|
231 return getattr(self._obj,name) |
|
232 |
|
233 def __setattr__(self, name, value): |
|
234 """ |
|
235 direct attribute setting calls to the sub object setattr |
|
236 """ |
|
237 if not self._obj: |
|
238 self._load() |
|
239 setattr(self._obj,name,value) |
|
240 |
|
241 def __delattr__(self, name): |
|
242 """ |
|
243 direct attribute setting calls to the sub object setattr |
|
244 """ |
|
245 if not self._obj: |
|
246 self._load() |
|
247 delattr(self._obj,name) |
|
248 |
|
249 def _set_parent(self, newparent): |
|
250 """ |
|
251 @param newparent: The new parent object |
|
252 @return: None |
|
253 """ |
|
254 self.set('_parent',newparent) |
|
255 if self._obj: |
|
256 self._obj._parent = self._parent |
|
257 |
|
258 def _set_obj(self, obj): |
|
259 self.set('_obj',obj) |
|
260 # set the same _parent for the actual object as is stored for the proxy |
|
261 self._obj._parent = self._parent |
|
262 self._obj.set_path(self.path) |
|
263 |
|
264 def _get_obj(self): |
|
265 if not self._obj: |
|
266 self._load() |
|
267 return self._obj |
|
268 |
|
269 def _load(self): |
|
270 # Should the loading of layer external resources be supported? |
|
271 # E.g. resources with absolute path relative to the storage (starts with slash) |
|
272 """ If the loading of the object fails => Raise an InvalidObject exception """ |
|
273 try: |
|
274 obj = self._store_interface().load(self.fullpath) |
|
275 self._set_obj(obj) |
|
276 obj.set_ref(utils.resourceref.to_objref(self.path)) |
|
277 except exceptions.NotResource,e: |
|
278 logging.getLogger('cone').warning("Loading %s from parent %s failed! %s" % (self.path,self.get_parent_path(), e)) |
|
279 raise exceptions.InvalidObject("Invalid configuration object %s" % self.path) |
|
280 |
|
281 def _unload(self): |
|
282 if self._obj: |
|
283 self._store_interface().unload(self.fullpath, self._obj) |
|
284 self.set('_obj',None) |
|
285 |
|
286 def _store_interface(self): |
|
287 if not self._storeint: |
|
288 self.set('_storeint',self._parent.get_project()) |
|
289 return self._storeint |
|
290 |
|
291 def set(self,name,value): |
|
292 """ |
|
293 Proxy has a specific attribute setting function, because by default all attributes are |
|
294 stored to the actual proxy object |
|
295 """ |
|
296 self.__dict__[name] = value |
|
297 |
|
298 def get(self,name): |
|
299 """ |
|
300 Proxy has also a specific attribute getting function, because by default all attributes are |
|
301 stored to the actual proxy object |
|
302 """ |
|
303 return self.__dict__[name] |
|
304 |
|
305 def save(self): |
|
306 if hasattr(self._obj,'save'): |
|
307 self._obj.save() |
|
308 self._unload() |
|
309 |
|
310 def close(self): |
|
311 if hasattr(self._obj,'close'): |
|
312 self._obj.close() |
|
313 |
|
314 def get_parent_path(self): |
|
315 """ |
|
316 Return the path of the configuration resource |
|
317 """ |
|
318 if self._parent: |
|
319 return utils.resourceref.get_path(self._parent.get_path()) |
|
320 else: |
|
321 return "" |
|
322 |
|
323 def get_path(self): |
|
324 """ |
|
325 Return the path of the configuration resource |
|
326 """ |
|
327 if self._obj: |
|
328 return self._obj.get_path() |
|
329 else: |
|
330 return self.path |
|
331 |
|
332 @property |
|
333 def fullpath(self): |
|
334 """ |
|
335 Return the path of the configuration resource |
|
336 """ |
|
337 try: |
|
338 return self._obj.get_full_path() |
|
339 except AttributeError: |
|
340 parent_path = self.get_parent_path() |
|
341 return utils.resourceref.join_refs([parent_path,self.path]) |
|
342 |
|
343 class ObjectContainer(ContainerBase): |
|
344 """ |
|
345 An object container class. The ObjectContainer is actually a Tree data structure. Any ObjectContainer |
|
346 instance can include any number of children, that must be instances of ObjectContainer. |
|
347 """ |
|
348 def __init__(self,name="",**kwargs): |
|
349 """ |
|
350 """ |
|
351 if len(name.split(".")) > 1 or len(name.split("/")) > 1: |
|
352 raise exceptions.InvalidRef("Illegal name for ObjectContainer %s" % name) |
|
353 self._name = name |
|
354 self._parent = None |
|
355 self._order = [] |
|
356 self._children = {} |
|
357 for arg in kwargs.keys(): |
|
358 setattr(self, arg, kwargs.get(arg)) |
|
359 |
|
360 def __getattr__(self,name): |
|
361 """ |
|
362 direct all not found attribute calls to the sub object getattr |
|
363 """ |
|
364 try: |
|
365 return self.__dict__['_children'][name] |
|
366 except KeyError: |
|
367 return getattr(super(ObjectContainer),name) |
|
368 |
|
369 def _path(self, toparent=None): |
|
370 """ |
|
371 Get the path to this ObjectContainer. |
|
372 @param toparent: the _parent object up to which the path is relative. Default value is None., |
|
373 which gives the fully qualified path |
|
374 @return: The path to the ObjectContainer from toparent |
|
375 """ |
|
376 if self == toparent: |
|
377 return "" |
|
378 elif self._parent and self._parent != toparent: |
|
379 # return the path with list index if the given element is in a list |
|
380 if utils.is_list(self.parent._get(self._name)): |
|
381 return self._parent._path(toparent)+"."+"%s[%s]" % (self._name,self.get_index()) |
|
382 else: |
|
383 return self._parent._path(toparent)+"."+self._name |
|
384 else: |
|
385 return self._name |
|
386 |
|
387 def _add(self, child, policy=REPLACE): |
|
388 """ |
|
389 Add a child object. |
|
390 @param child: The child object to add. The child needs to be an instance of ObjectContainer. |
|
391 @param policy: The policy which is used when an object with same name exists already |
|
392 """ |
|
393 # check that the child is a supported type |
|
394 if not self._supported_type(child): |
|
395 raise exceptions.IncorrectClassError("Cannot add instance of %s to %s." % (child.__class__,self.__class__)) |
|
396 if policy == REPLACE: |
|
397 self._replace(child) |
|
398 elif policy == ERROR: |
|
399 self._error(child) |
|
400 elif policy == APPEND: |
|
401 self._append(child) |
|
402 elif policy == PREPEND: |
|
403 self._prepend(child) |
|
404 |
|
405 def _append(self, child): |
|
406 """ |
|
407 Add the given child to the proper key. Create a list entry if necessary |
|
408 """ |
|
409 child._set_parent(self) |
|
410 if not self._children.has_key(child._name): |
|
411 # skip all internal objects (that start with _) |
|
412 if not child._name.startswith('?'): |
|
413 self._order.append(child._name) |
|
414 self._children[child._name] = child |
|
415 else: |
|
416 """ Create a list under the child name """ |
|
417 self._children[child._name] = utils.add_list(self._children[child._name], child) |
|
418 return |
|
419 |
|
420 def _prepend(self, child): |
|
421 """ |
|
422 Add the given child to the proper key. Create a list entry if necessary |
|
423 """ |
|
424 child._set_parent(self) |
|
425 if not self._children.has_key(child._name): |
|
426 # skip all internal objects (that start with _) |
|
427 if not child._name.startswith('?'): |
|
428 self._order.insert(0,child._name) |
|
429 self._children[child._name] = child |
|
430 else: |
|
431 """ Create a list under the child name """ |
|
432 self._children[child._name] = utils.prepend_list(self._children[child._name], child) |
|
433 return |
|
434 |
|
435 def _replace(self, child): |
|
436 """ |
|
437 If the given child already exists => Replace the child, |
|
438 but maintain the current children of that child |
|
439 """ |
|
440 child._set_parent(self) |
|
441 # skip all internal objects (that start with _) |
|
442 if not self._children.has_key(child._name): |
|
443 if not child._name.startswith('?'): |
|
444 self._order.append(child._name) |
|
445 else: |
|
446 """ if the existing child is a instance of ObjectContainer, |
|
447 add all children of the existing contianer to this new object """ |
|
448 existingchild = self._children[child._name] |
|
449 if isinstance(existingchild, ObjectContainer): |
|
450 for subchild in existingchild._objects(): |
|
451 child._add(subchild) |
|
452 |
|
453 self._children[child._name] = child |
|
454 return |
|
455 |
|
456 def _error(self, child): |
|
457 """ |
|
458 If the given child already exists => raise an exception. |
|
459 @raise exceptions.AlreadyExists: |
|
460 """ |
|
461 child._set_parent(self) |
|
462 if not self._children.has_key(child._name): |
|
463 # skip all internal objects (that start with _) |
|
464 if not child._name.startswith('?'): |
|
465 self._order.insert(0,child._name) |
|
466 self._children[child._name] = child |
|
467 else: |
|
468 raise exceptions.AlreadyExists('Child %s already exists' % child._name) |
|
469 return |
|
470 |
|
471 def _add_to_path(self, path, child, policy=REPLACE): |
|
472 """ |
|
473 Add a child object. |
|
474 @param path: the path for the object |
|
475 @param child: The child object to add |
|
476 @param namespace: The namespace of the object, which defines where the object is created |
|
477 """ |
|
478 # check that the child is a supported type |
|
479 if not self._supported_type(child): |
|
480 raise exceptions.IncorrectClassError("Cannot add instance of %s to %s Container" % (child.__class__,self.__class__)) |
|
481 # ensure that the elements to the namespace exist |
|
482 curelem = self |
|
483 for ppath in utils.dottedref.split_ref(path): |
|
484 |
|
485 if not curelem._children.has_key(ppath): |
|
486 # Create missing elem |
|
487 curelem._add(self._default_object(ppath)) |
|
488 curelem = curelem._get(ppath) |
|
489 curelem._add(child,policy) |
|
490 |
|
491 def _get(self, path): |
|
492 """ |
|
493 Get a child object by it path. |
|
494 @return: The child object if it is found. |
|
495 @raise NotFound: when object is not found from the children. |
|
496 """ |
|
497 |
|
498 try: |
|
499 # traverse to the actual child element |
|
500 curelem = self |
|
501 for pathelem in utils.dottedref.split_ref(path): |
|
502 if utils.dottedref.get_index(pathelem) == None: |
|
503 curelem = curelem._children[pathelem] |
|
504 else: |
|
505 # If the given pathelem is referring to a list |
|
506 name = utils.dottedref.get_name(pathelem) |
|
507 index = utils.dottedref.get_index(pathelem) |
|
508 curelem = utils.get_list(curelem._children[name])[index] |
|
509 return curelem |
|
510 # Catch the KeyError exception from dict and IndexError from list |
|
511 except (KeyError,IndexError): |
|
512 raise exceptions.NotFound("Child %s not found!" % path) |
|
513 |
|
514 def _has(self, path): |
|
515 """ |
|
516 Returns True if an element under the path is found. |
|
517 @return: Boolean value. |
|
518 """ |
|
519 |
|
520 try: |
|
521 # traverse to the actual child element |
|
522 curelem = self |
|
523 for pathelem in utils.dottedref.split_ref(path): |
|
524 curelem = curelem._children[pathelem] |
|
525 return True |
|
526 except KeyError: |
|
527 return False |
|
528 |
|
529 def _remove(self, path): |
|
530 """ |
|
531 Remove a child object by it path. |
|
532 """ |
|
533 # if the patherence is a long patherence (dotted name) |
|
534 # first get the _parent object and call the remove to the _parent |
|
535 (parentref,name) = utils.dottedref.psplit_ref(path) |
|
536 if parentref != "": |
|
537 self._get(parentref)._remove(name) |
|
538 elif utils.dottedref.get_index(path) != None and \ |
|
539 self._get(utils.dottedref.get_name(path)): |
|
540 # Delete If the given pathelem is referring to a list |
|
541 name = utils.dottedref.get_name(path) |
|
542 index = utils.dottedref.get_index(path) |
|
543 del self._children[name][index] |
|
544 if len(self._children[name]) == 0: |
|
545 del self._order[self._order.index(name)] |
|
546 elif self._get(path) != None: # delete if the child is found |
|
547 del self._children[path] |
|
548 del self._order[self._order.index(path)] |
|
549 |
|
550 else: |
|
551 raise exceptions.NotFound("Child %s not found!" % path) |
|
552 |
|
553 def _list_traverse(self,**kwargs): |
|
554 """ |
|
555 Return a list of all children paths. This function calls internally __traverse__, see it for |
|
556 more details. |
|
557 @return: an unordered list of children paths. The path is relative to this node. |
|
558 """ |
|
559 return [child._path(self) for child in self._traverse(**kwargs)] |
|
560 |
|
561 def _traverse(self, **kwargs): |
|
562 """ |
|
563 The traverse goes recursively through the tree of children of this node and returns a result set as list. |
|
564 Arguments can be passed to it to filter out elements of the result set. All arguments are |
|
565 given as dict, so they must be given with name. E.g. _traverse(name='test') |
|
566 @param name: The node name or part of name which is used as a filter. This is a regular expression (uses internally re.match()) |
|
567 @param path: The path name or part of name which is used as a filter. This is a regular expression (uses internally re.match()) |
|
568 @param filters: A list of predefined filters can be given as lambda functions. E.g. filters=[lambda x: isinstance(x._obj, FooClass)] |
|
569 @return: a list of ObjectContainer objects. |
|
570 """ |
|
571 filterlist=[] |
|
572 if kwargs.has_key('ref'): |
|
573 filterlist.append(lambda x: re.match(kwargs.get('ref'), x.ref)) |
|
574 if kwargs.has_key('name'): |
|
575 filterlist.append(lambda x: re.match(kwargs.get('name'), x._name)) |
|
576 if kwargs.has_key('path'): |
|
577 filterlist.append(lambda x: re.match(kwargs.get('path'), x._path())) |
|
578 if kwargs.has_key('type'): |
|
579 filterlist.append(lambda x: isinstance(x, kwargs.get('type'))) |
|
580 if kwargs.has_key('filters'): |
|
581 filterlist += kwargs.get('filters') |
|
582 |
|
583 ret = [] |
|
584 for child in self._objects(): |
|
585 subchildren = child._tail_recurse(_apply_filter,filters=filterlist) |
|
586 ret += subchildren |
|
587 return ret |
|
588 |
|
589 def _find_leaves(self, **kwargs): |
|
590 """ |
|
591 Find all leaf nodes in the tree that satisfy the given filtering criteria. |
|
592 |
|
593 For possible keyword arguments see _traverse(). |
|
594 |
|
595 @return: A list of ObjectContainer objects. |
|
596 """ |
|
597 # Find all children |
|
598 nodes = self._traverse(**kwargs) |
|
599 |
|
600 # Filter out non-leaves |
|
601 return filter(lambda node: len(node._objects()) == 0, nodes) |
|
602 |
|
603 def _tail_recurse(self, function, **kwargs): |
|
604 """ |
|
605 Run a tail recursion on all container children and execute the given function. |
|
606 1. function will receive self as argument to it. |
|
607 2. function will receive all kwargs as argument to it. |
|
608 3. tail recursion means that the function is executed first and then the |
|
609 recursion continues. |
|
610 @param function: the function which is executed |
|
611 @param kwargs: a list of arguments as dict |
|
612 @return: an list of objects, which can be anything that the funtion returns |
|
613 """ |
|
614 |
|
615 ret = [] |
|
616 ret += function(self,**kwargs) |
|
617 for child in self._objects(): |
|
618 try: |
|
619 # We wont add the object to the ret until we know that it is a valid object |
|
620 subchildren = child._tail_recurse(function,**kwargs) |
|
621 #ret += function(child,**kwargs) |
|
622 ret += subchildren |
|
623 except exceptions.InvalidObject,e: |
|
624 # remove the invalid object from this container |
|
625 logging.getLogger('cone').warning('Removing invalid child because of exception %s' % e) |
|
626 self._remove(child._name) |
|
627 continue |
|
628 return ret |
|
629 |
|
630 def _head_recurse(self, function,**kwargs): |
|
631 """ |
|
632 Run a tail recursion on all container children and execute the given function. |
|
633 1. function will receive self as argument to it. |
|
634 2. function will receive all kwargs as argument to it. |
|
635 3. head recursion means that the recursion continues to the leaf nodes and then the |
|
636 execution of the function begins. |
|
637 @param function: the function which is executed |
|
638 @param kwargs: a list of arguments as dict |
|
639 @return: an list of objects, which can be anything that the funtion returns |
|
640 """ |
|
641 ret = [] |
|
642 for child in self._objects(): |
|
643 try: |
|
644 ret += child._head_recurse(function,**kwargs) |
|
645 ret += function(child,**kwargs) |
|
646 except exceptions.InvalidObject,e: |
|
647 # remove the invalid object from this container |
|
648 logging.getLogger('cone').warning('Removing invalid child because of exception %s' % e) |
|
649 self._remove(child._name) |
|
650 continue |
|
651 return ret |
|
652 |
|
653 def _list(self): |
|
654 """ |
|
655 Return a array of immediate children names. |
|
656 @return: an unordered list of immediate children path-references |
|
657 """ |
|
658 # skip all internal objects (that start with _) |
|
659 return [name for name in self._order if not name.startswith('?')] |
|
660 |
|
661 def _objects(self, **kwargs): |
|
662 """ |
|
663 Return a array of immediate children. |
|
664 @return: an unordered list of immediate children |
|
665 """ |
|
666 ret = [] |
|
667 for cname in self._order: |
|
668 try: |
|
669 if object_container_filter(self._children[cname], **kwargs): |
|
670 ret += utils.get_list(self._children[cname]) |
|
671 except exceptions.InvalidObject,e: |
|
672 # remove the invalid object from this container |
|
673 logging.getLogger('cone').warning('Removing invalid child because of exception %s' % e) |
|
674 self._remove(cname) |
|
675 continue |
|
676 return ret |
|
677 |
|
678 def _get_index(self, name): |
|
679 """ |
|
680 Get the index of a child object by its name. The index matches the index |
|
681 of the child object in the _children array. |
|
682 @return: integer. |
|
683 @raise NotFound: when object is not found from the children. |
|
684 """ |
|
685 |
|
686 try: |
|
687 return self._order.index(name) |
|
688 except KeyError: |
|
689 raise exceptions.NotFound("Child %s not found!" % name) |
|
690 |
|
691 def _supported_type(self,obj): |
|
692 """ |
|
693 An internal function to check that the given object is a supported for this Tree. |
|
694 This is used in every __add__ operation to check whether the object can be added to the tree. |
|
695 This function should be overloaded by a subclass if the supported types need to be changed. |
|
696 @return: True if object is supported, otherwise false. |
|
697 """ |
|
698 return isinstance(obj, ObjectContainer) |
|
699 |
|
700 def _default_object(self,name): |
|
701 """ |
|
702 An internal function to create a default object for this container in case of __add_to_path__, which |
|
703 creates the intermediate objects automatically. |
|
704 This function should be overloaded by a subclass if the default object need to be changed. |
|
705 @return: A new object. |
|
706 """ |
|
707 return ObjectContainer(name) |
|
708 |
|
709 def _find_parent(self, **kwargs): |
|
710 """ |
|
711 find a _parent object by arguments. You can define any number of object attributes that |
|
712 have to match to the object. |
|
713 Example1: |
|
714 _find_parent(foobar=True) searches for a _parent |
|
715 object which has a member attribute foobar and its value is True. |
|
716 Example2: |
|
717 _find_parent(name="test") searches for a _parent |
|
718 object which has a member attribute name and its value is "test". |
|
719 Example3: type is a special case |
|
720 _find_parent(type=Configuration) searches for a _parent |
|
721 object which is an instance of Configuration (checked with isinstance). |
|
722 @param kwargs: |
|
723 @return: The object that matches the arguments |
|
724 @raise exceptions.NotFound: When no matching parent is found |
|
725 """ |
|
726 type = kwargs.get('type', None) |
|
727 if hasattr(self,'_parent') and self._parent != None: |
|
728 found = True |
|
729 for key in kwargs.keys(): |
|
730 try: |
|
731 # handle type as a special case |
|
732 if key == 'type': |
|
733 if not isinstance(self._parent, kwargs.get(key)): |
|
734 found = False |
|
735 break |
|
736 elif key == 'match': |
|
737 if not self._parent == kwargs.get(key): |
|
738 found = False |
|
739 break |
|
740 elif not getattr(self._parent, key) == kwargs.get(key): |
|
741 found = False |
|
742 break |
|
743 except AttributeError: |
|
744 found = False |
|
745 break |
|
746 if found: |
|
747 return self._parent |
|
748 else: |
|
749 return self._parent._find_parent(**kwargs) |
|
750 else: |
|
751 raise exceptions.NotFound("Parent not found!") |
|
752 |
|
753 def _find_parent_or_default(self, default=None,**kwargs): |
|
754 """ |
|
755 Calls internally the find parent function, which is encapsulated with try except |
|
756 returns the given default value if find parent raises NotFound exception. |
|
757 """ |
|
758 try: |
|
759 return self._find_parent(**kwargs) |
|
760 except exceptions.NotFound: |
|
761 return default |
|
762 |
|
763 def set_ref(self,ref): |
|
764 """ |
|
765 @param ref: The new reference of the object |
|
766 """ |
|
767 self._name = ref |
|
768 self.ref = ref |
|
769 |
|
770 def get_ref(self): |
|
771 """ |
|
772 @return: The reference of the object. |
|
773 """ |
|
774 return self.ref |
|
775 |
|
776 class ObjectProxyContainer(ObjectProxy,ObjectContainer): |
|
777 """ |
|
778 Combines the Container and Proxy classes to one. |
|
779 """ |
|
780 def __init__(self,obj=None,name=""): |
|
781 """ |
|
782 """ |
|
783 ObjectContainer.__init__(self,name) |
|
784 ObjectProxy.__init__(self,obj) |
|
785 |
|
786 def __getattr__(self,name): |
|
787 """ |
|
788 First check if the requested attr is a children then |
|
789 direct all not found attribute calls to the sub object getattr |
|
790 """ |
|
791 try: |
|
792 return self.__dict__['_children'][name] |
|
793 except KeyError: |
|
794 return getattr(self._obj,name) |