0
|
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)
|