configurationengine/source/cone/public/container.py
changeset 0 2e8eeb919028
child 3 e7e0ae78773e
equal deleted inserted replaced
-1:000000000000 0:2e8eeb919028
       
     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)