configurationengine/source/cone/public/container.py
changeset 3 e7e0ae78773e
parent 0 2e8eeb919028
child 4 0951727b8815
equal deleted inserted replaced
2:87cfa131b535 3:e7e0ae78773e
    20 """
    20 """
    21 
    21 
    22 import re
    22 import re
    23 import pickle
    23 import pickle
    24 import logging
    24 import logging
    25 import utils, exceptions
    25 import utils
       
    26 from cone.public import exceptions
    26 
    27 
    27 def object_container_filter(obj,**kwargs):
    28 def object_container_filter(obj,**kwargs):
    28     """ Create a list of filter functions for each argument """ 
    29     """ Create a list of filter functions for each argument """ 
    29     filters=[]
    30     filters=[]
    30     if kwargs.has_key('name'):
    31     if kwargs.has_key('name'):
   135         Remove all data from the container.
   136         Remove all data from the container.
   136         """
   137         """
   137         return self.data.clear()
   138         return self.data.clear()
   138 
   139 
   139 class ContainerBase(object):
   140 class ContainerBase(object):
   140     
   141     def __init__(self, name="",**kwargs):
       
   142         if len(name.split(".")) > 1 or len(name.split("/")) > 1:
       
   143             raise exceptions.InvalidRef("Illegal name for ObjectContainer %s" % name)
       
   144         self._name = name
       
   145         self._parent = None
       
   146         self._order = []
       
   147         self._children = {}
       
   148         self._respath = ""
       
   149         for arg in kwargs.keys():
       
   150             setattr(self, arg, kwargs.get(arg))
       
   151 
       
   152     def __getstate__(self):
       
   153         state = {}
       
   154         if self._parent: state['_parent'] = self._parent
       
   155         if self._order: state['_order'] = self._order
       
   156         if self._children: state['_children'] = self._children
       
   157         if self._respath: state['_respath'] = self._respath
       
   158         return state
       
   159     
       
   160     def __setstate__(self, state):
       
   161         self._name = state.get('ref','')
       
   162         self._parent = state.get('_parent',None)
       
   163         self._order = state.get('_order',[])
       
   164         self._children = state.get('_children',{})
       
   165         self._respath = state.get('_respath',"")
       
   166         # update the parent link for all the children of this object
       
   167         for child in self._objects():
       
   168             child._parent = self
       
   169 
   141     def _set_parent(self, newparent):
   170     def _set_parent(self, newparent):
   142         """
   171         """
   143         @param newparent:  The new parent object
   172         @param newparent:  The new parent object
   144         @return: None
   173         @return: None
   145         """
   174         """
   154     def _del_parent(self):
   183     def _del_parent(self):
   155         """
   184         """
   156         Set the current parent to None
   185         Set the current parent to None
   157         """
   186         """
   158         self._parent = None
   187         self._parent = None
       
   188 
       
   189     def get_store_interface(self):
       
   190         """
       
   191         Get a possible store interface for this ContainerBase object
       
   192         """
       
   193         return None
       
   194 
       
   195     def get_path(self):
       
   196         """
       
   197         Return the path of the object
       
   198         """
       
   199         return self._respath
   159 
   200 
   160     parent = property(_get_parent, _set_parent,_del_parent)
   201     parent = property(_get_parent, _set_parent,_del_parent)
   161 
   202 
   162 
   203 
   163 class ObjectProxy(ContainerBase):
   204 class ObjectProxy(ContainerBase):
   187 #        if isinstance(self._obj, ContainerBase):
   228 #        if isinstance(self._obj, ContainerBase):
   188 #            self._obj._set_parent(newparent)
   229 #            self._obj._set_parent(newparent)
   189 
   230 
   190 class LoadInterface(ContainerBase):
   231 class LoadInterface(ContainerBase):
   191     def load(self,ref):
   232     def load(self,ref):
   192         file = open(ref,"r")
   233         file = open(ref,"rb")
   193         self._parent = None
   234         self._parent = None
   194         return pickle.load(file)
   235         return pickle.load(file)
   195 
   236 
   196     def unload(self,ref, obj):
   237     def unload(self,ref, obj):
   197         """
   238         """
   198         unload or release
   239         unload or release
   199         """
   240         """
   200         file = open(ref,"w")
   241         file = open(ref,"wb")
   201         pickle.dump(obj,file)
   242         pickle.dump(obj,file)
   202         file.close()
   243         file.close()
   203 
   244 
   204     def get_path(self):
   245     def get_path(self):
   205         """
   246         """
   206         Return the path of the configuration resource
   247         Return the path of the configuration resource
   207         """
   248         """
   208         return ""
   249         return ""
   209 
   250 
   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 
   251 
   343 class ObjectContainer(ContainerBase):
   252 class ObjectContainer(ContainerBase):
   344     """
   253     """
   345     An object container class. The ObjectContainer is actually a Tree data structure. Any ObjectContainer 
   254     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.  
   255     instance can include any number of children, that must be instances of ObjectContainer.  
   347     """
   256     """
   348     def __init__(self,name="",**kwargs):
   257     def __init__(self,name="",**kwargs):
   349         """
   258         """
   350         """
   259         """
   351         if len(name.split(".")) > 1 or len(name.split("/")) > 1:
   260         super(ObjectContainer,self).__init__(name, **kwargs)
   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 
   261 
   360     def __getattr__(self,name):
   262     def __getattr__(self,name):
   361         """
   263         """
   362         direct all not found attribute calls to the sub object getattr
   264         direct all not found attribute calls to the sub object getattr
   363         """
   265         """
   364         try:
   266         try:
   365             return self.__dict__['_children'][name]
   267             return self.__dict__['_children'][name]
   366         except KeyError:
   268         except KeyError:
   367             return getattr(super(ObjectContainer),name)
   269             try:
       
   270                 return getattr(super(ObjectContainer),name)
       
   271             except AttributeError,e:
       
   272                 raise AttributeError("%s object has not attribute '%s'" % (self.__class__, name))
   368 
   273 
   369     def _path(self, toparent=None):
   274     def _path(self, toparent=None):
   370         """
   275         """
   371         Get the path to this ObjectContainer.
   276         Get the path to this ObjectContainer.
   372         @param toparent: the _parent object up to which the path is relative. Default value is None.,
   277         @param toparent: the _parent object up to which the path is relative. Default value is None.,
   382             else:
   287             else:
   383                 return self._parent._path(toparent)+"."+self._name
   288                 return self._parent._path(toparent)+"."+self._name
   384         else:
   289         else:
   385             return self._name
   290             return self._name
   386     
   291     
   387     def _add(self, child, policy=REPLACE):
   292     def _add(self, child_or_children, policy=REPLACE):
   388         """
   293         """
   389         Add a child object. 
   294         Add a child object or multiple child objects. 
   390         @param child: The child object to add. The child needs to be an instance of ObjectContainer. 
   295         @param child_or_children: The child object or list of child objects to add.
       
   296             The children need to be instances of ObjectContainer. 
   391         @param policy: The policy which is used when an object with same name exists already  
   297         @param policy: The policy which is used when an object with same name exists already  
   392         """
   298         """
       
   299         if isinstance(child_or_children, list):
       
   300             objs = child_or_children
       
   301             if policy == PREPEND:
       
   302                 objs = reversed(objs)
       
   303                 policy_first = PREPEND
       
   304                 policy_rest = PREPEND
       
   305             else:
       
   306                 policy_first = policy
       
   307                 policy_rest = APPEND
       
   308             
       
   309             for i, obj in enumerate(objs):
       
   310                 if i == 0:  p = policy_first
       
   311                 else:       p = policy_rest
       
   312                 self._add(obj, p)
       
   313             return
       
   314         
       
   315         
   393         # check that the child is a supported type
   316         # check that the child is a supported type
       
   317         child = child_or_children
   394         if not self._supported_type(child):
   318         if not self._supported_type(child):
   395             raise exceptions.IncorrectClassError("Cannot add instance of %s to %s." % (child.__class__,self.__class__))
   319             raise exceptions.IncorrectClassError("Cannot add instance of %s to %s." % (child.__class__,self.__class__))
   396         if policy == REPLACE:
   320         if policy == REPLACE:
   397             self._replace(child)
   321             self._replace(child)
   398         elif policy == ERROR:
   322         elif policy == ERROR:
   441         # skip all internal objects (that start with _)
   365         # skip all internal objects (that start with _)
   442         if not self._children.has_key(child._name):
   366         if not self._children.has_key(child._name):
   443             if not child._name.startswith('?'):
   367             if not child._name.startswith('?'):
   444                 self._order.append(child._name)
   368                 self._order.append(child._name)
   445         else:
   369         else:
   446             """ if the existing child is a instance of ObjectContainer, 
   370             """ 
   447                 add all children of the existing contianer to this new object """
   371             if the existing child is a instance of ObjectContainer, 
       
   372             add all children of the existing container to this new object, except if the 
       
   373             child already exists in the new child. 
       
   374             """
   448             existingchild = self._children[child._name]
   375             existingchild = self._children[child._name]
   449             if isinstance(existingchild, ObjectContainer):
   376             if isinstance(existingchild, ObjectContainer):
   450                 for subchild in existingchild._objects():
   377                 for subchild in existingchild._objects():
   451                      child._add(subchild)
   378                     if not child._children.has_key(subchild._name):
       
   379                         child._add(subchild)
       
   380                      
   452         
   381         
   453         self._children[child._name] = child
   382         self._children[child._name] = child
   454         return
   383         return
   455 
   384 
   456     def _error(self, child):
   385     def _error(self, child):
   506                     name = utils.dottedref.get_name(pathelem)
   435                     name = utils.dottedref.get_name(pathelem)
   507                     index = utils.dottedref.get_index(pathelem)
   436                     index = utils.dottedref.get_index(pathelem)
   508                     curelem = utils.get_list(curelem._children[name])[index]
   437                     curelem = utils.get_list(curelem._children[name])[index]
   509             return curelem
   438             return curelem
   510         # Catch the KeyError exception from dict and IndexError from list
   439         # Catch the KeyError exception from dict and IndexError from list
   511         except (KeyError,IndexError): 
   440         except (KeyError,IndexError), e: 
   512             raise exceptions.NotFound("Child %s not found!" % path)
   441             raise exceptions.NotFound("Child %s not found from %s! %s" % (path, self, e))
   513 
   442 
   514     def _has(self, path):
   443     def _has(self, path):
   515         """
   444         """
   516         Returns True if an element under the path is found.
   445         Returns True if an element under the path is found.
   517         @return: Boolean value. 
   446         @return: Boolean value. 
   543             del self._children[name][index]
   472             del self._children[name][index]
   544             if len(self._children[name]) == 0:
   473             if len(self._children[name]) == 0:
   545                 del self._order[self._order.index(name)]
   474                 del self._order[self._order.index(name)]
   546         elif self._get(path) != None: # delete if the child is found
   475         elif self._get(path) != None: # delete if the child is found
   547             del self._children[path]
   476             del self._children[path]
   548             del self._order[self._order.index(path)]
   477             # hidded children are not added to the order list 
       
   478             if not path.startswith('?'):
       
   479                 del self._order[self._order.index(path)]
   549             
   480             
   550         else:
   481         else:
   551             raise exceptions.NotFound("Child %s not found!" % path)
   482             raise exceptions.NotFound("Child %s not found!" % path)
   552 
   483 
   553     def _list_traverse(self,**kwargs):
   484     def _list_traverse(self,**kwargs):
   563         The traverse goes recursively through the tree of children of this node and returns a result set as list.
   494         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 
   495         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')
   496         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()) 
   497         @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())
   498         @param path: The path name or part of name which is used as a filter. This is a regular expression (uses internally re.match())
       
   499         @param type: The type (class) of the objects that should be returned (this can be a tuple of types)
       
   500         @param depth: The max recursion depth that traverse goes through. 
   568         @param filters: A list of predefined filters can be given as lambda functions. E.g. filters=[lambda x: isinstance(x._obj, FooClass)]  
   501         @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.
   502         @return: a list of ObjectContainer objects.
   570         """
   503         """
   571         filterlist=[]
   504         filterlist=[]
   572         if kwargs.has_key('ref'):
   505         if kwargs.has_key('ref'):
   580         if kwargs.has_key('filters'):
   513         if kwargs.has_key('filters'):
   581             filterlist += kwargs.get('filters')
   514             filterlist += kwargs.get('filters')
   582 
   515 
   583         ret = []
   516         ret = []
   584         for child in self._objects():
   517         for child in self._objects():
   585             subchildren = child._tail_recurse(_apply_filter,filters=filterlist)
   518             subchildren = child._tail_recurse(_apply_filter,filters=filterlist,depth=kwargs.get('depth',-1))
   586             ret += subchildren
   519             ret += subchildren
   587         return ret
   520         return ret
   588     
   521     
   589     def _find_leaves(self, **kwargs):
   522     def _find_leaves(self, **kwargs):
   590         """
   523         """
   609         recursion continues.
   542         recursion continues.
   610         @param function: the function which is executed
   543         @param function: the function which is executed
   611         @param kwargs: a list of arguments as dict
   544         @param kwargs: a list of arguments as dict
   612         @return: an list of objects, which can be anything that the funtion returns   
   545         @return: an list of objects, which can be anything that the funtion returns   
   613         """
   546         """
   614         
   547         depth = kwargs.get('depth',-1)
   615         ret = []
   548         ret = []
   616         ret += function(self,**kwargs)
   549         # check the if the recursion maximum depth has been reached
   617         for child in self._objects():
   550         # if not reached but set, decrease it by one and set that to subrecursion
   618             try:
   551         if depth != 0:
   619                 # We wont add the object to the ret until we know that it is a valid object
   552             ret += function(self,kwargs.get('filters',[]))
   620                 subchildren = child._tail_recurse(function,**kwargs)
   553             kwargs['depth'] = depth - 1
   621                 #ret += function(child,**kwargs)
   554             for child in self._objects():
   622                 ret += subchildren
   555                 try:
   623             except exceptions.InvalidObject,e:
   556                     # We wont add the object to the ret until we know that it is a valid object
   624                 # remove the invalid object from this container
   557                     subchildren = child._tail_recurse(function,**kwargs)
   625                 logging.getLogger('cone').warning('Removing invalid child because of exception %s' % e)
   558                     #ret += function(child,**kwargs)
   626                 self._remove(child._name)
   559                     ret += subchildren
   627                 continue
   560                 except exceptions.InvalidObject,e:
       
   561                     # remove the invalid object from this container
       
   562                     logging.getLogger('cone').warning('Removing invalid child because of exception %s' % e)
       
   563                     self._remove(child._name)
       
   564                     continue
       
   565         
   628         return ret
   566         return ret
   629 
   567 
   630     def _head_recurse(self, function,**kwargs):
   568     def _head_recurse(self, function,**kwargs):
   631         """
   569         """
   632         Run a tail recursion on all container children and execute the given function.
   570         Run a tail recursion on all container children and execute the given function.
   693         An internal function to check that the given object is a supported for this Tree. 
   631         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.
   632         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.
   633         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.  
   634         @return: True if object is supported, otherwise false.  
   697         """
   635         """
   698         return isinstance(obj, ObjectContainer)
   636         return isinstance(obj, (ObjectContainer,ContainerBase))
   699 
   637 
   700     def _default_object(self,name):
   638     def _default_object(self,name):
   701         """
   639         """
   702         An internal function to create a default object for this container in case of __add_to_path__, which
   640         An internal function to create a default object for this container in case of __add_to_path__, which
   703         creates the intermediate objects automatically. 
   641         creates the intermediate objects automatically. 
   771         """
   709         """
   772         @return: The reference of the object.
   710         @return: The reference of the object.
   773         """
   711         """
   774         return self.ref
   712         return self.ref
   775 
   713 
       
   714     def has_ref(self, ref):
       
   715         """
       
   716         Check if object container contains the given reference.
       
   717         @param ref: reference
       
   718         """
       
   719         return self._has(ref)
       
   720 
   776 class ObjectProxyContainer(ObjectProxy,ObjectContainer):
   721 class ObjectProxyContainer(ObjectProxy,ObjectContainer):
   777     """
   722     """
   778     Combines the Container and Proxy classes to one.
   723     Combines the Container and Proxy classes to one.
   779     """
   724     """
   780     def __init__(self,obj=None,name=""):
   725     def __init__(self,obj=None,name=""):
   790         """
   735         """
   791         try:
   736         try:
   792             return self.__dict__['_children'][name] 
   737             return self.__dict__['_children'][name] 
   793         except KeyError:
   738         except KeyError:
   794             return getattr(self._obj,name)
   739             return getattr(self._obj,name)
       
   740 
       
   741 class LoadContainer(ContainerBase):
       
   742     """
       
   743     This class is meant for loading & unloading an object(s), to a ObjectContainer. 
       
   744     The loading is done if the object container methods are accessed.
       
   745     """
       
   746     def __init__(self, path, store_interface=None):
       
   747         """
       
   748         @param path: the path which is used in loading
       
   749         @param store_interface: the loading interface object, which is used. 
       
   750         Expects load(path) and dump(obj) functions  
       
   751         """
       
   752         super(LoadContainer, self).__init__()
       
   753         self._parent = None
       
   754         self._container = None
       
   755         self._storeint = store_interface
       
   756         self._respath = path
       
   757     
       
   758     def __getattr__(self,name):
       
   759         """
       
   760         Load the container objects if they are not allready loaded
       
   761         """
       
   762         if not self._container:
       
   763             self._load()
       
   764         return getattr(self._container,name)
       
   765     
       
   766     def _load(self):
       
   767         """ If the loading of the object fails => Raise an InvalidObject exception """ 
       
   768         try:
       
   769             self._container = ObjectContainer()
       
   770             # this should be modified to support loading multiple elements 
       
   771             intf = self.get_store_interface()
       
   772             # Do not try to load the objects if interface cannot be found
       
   773             if intf:
       
   774                 obj = intf.load(self.get_full_path())
       
   775                 self._container._add(obj)
       
   776         except exceptions.NotResource,e:
       
   777             logging.getLogger('cone').warning("Loading %s from parent %s failed! %s" % (self.path,self.get_parent_path(), e))
       
   778             raise exceptions.InvalidObject("Invalid configuration object %s" % self.path)
       
   779 
       
   780     def _unload(self):
       
   781         # go through objects in the container
       
   782         intf = self.get_store_interface()
       
   783         for obj in self._container._objects():
       
   784             # remove the parent link 
       
   785             obj._parent = None
       
   786             if intf:
       
   787                 intf.unload(self.get_full_path(), obj)
       
   788             self._container._remove(obj._name)
       
   789         # set the container back to None
       
   790         self._container = None
       
   791         
       
   792     def get_store_interface(self):
       
   793         if not self._storeint and self._parent:
       
   794             try:
       
   795                 self._storeint = self._parent.get_store_interface()
       
   796             except exceptions.NotFound:
       
   797                 # If project is not found, let the store interface be None 
       
   798                 pass
       
   799         return self._storeint
       
   800 
       
   801     def get_parent_path(self):
       
   802         """
       
   803         Return the path of the configuration resource
       
   804         """
       
   805         if self._parent:
       
   806             return utils.resourceref.get_path(self._parent.get_path())
       
   807         else:
       
   808             return ""
       
   809 
       
   810     def get_full_path(self, obj=None):
       
   811         """
       
   812         Return the path of the configuration resource
       
   813         """
       
   814         if obj != None:
       
   815             try:
       
   816                 return obj.get_full_path()
       
   817             except AttributeError:
       
   818                 pass
       
   819         # default path processing returns the fullpath of this elem
       
   820         parent_path = self.get_parent_path() 
       
   821         return utils.resourceref.join_refs([parent_path,self.get_path()])
       
   822 
       
   823 
       
   824 class LoadLink(ContainerBase):
       
   825     """
       
   826     This class is meant for loading & unloading an object(s), to a ObjectContainer. 
       
   827     The loading is done if the object container methods are accessed.
       
   828     """
       
   829     def __init__(self, path, store_interface=None):
       
   830         """
       
   831         @param path: the path which is used in loading
       
   832         @param store_interface: the loading interface object, which is used. 
       
   833         Expects load(path) and dump(obj) functions  
       
   834         """
       
   835         super(LoadLink, self).__init__()
       
   836         self._parent = None
       
   837         self._loaded = False
       
   838         self._storeint = store_interface
       
   839         self._respath = path
       
   840     
       
   841     def populate(self):
       
   842         """
       
   843         Populate the object to the parent
       
   844         """
       
   845         if self._parent == None:
       
   846             raise exceptions.NoParent("Cannot populate a LoadLink object without existing parent object")
       
   847         if not self._loaded:
       
   848             for obj in self._load():
       
   849                 self._parent._add(obj)
       
   850     
       
   851     def _load(self):
       
   852         """ If the loading of the object fails => Raise an InvalidObject exception """ 
       
   853         objs = []
       
   854         try:
       
   855             # this should be modified to support loading multiple elements 
       
   856             intf = self.get_store_interface()
       
   857             # Do not try to load the objects if interface cannot be found
       
   858             if intf:
       
   859                 obj = intf.load(self.get_full_path())
       
   860                 objs.append(obj)
       
   861         except exceptions.NotResource,e:
       
   862             logging.getLogger('cone').warning("Loading %s from parent %s failed! %s" % (self.path,self.get_parent_path(), e))
       
   863             raise exceptions.InvalidObject("Invalid configuration object %s" % self.path)
       
   864         return objs
       
   865     
       
   866     def _unload(self):
       
   867         pass
       
   868     
       
   869     def get_store_interface(self):
       
   870         if not self._storeint and self._parent:
       
   871             try:
       
   872                 self._storeint = self._parent.get_store_interface()
       
   873             except exceptions.NotFound:
       
   874                 # If project is not found, let the store interface be None 
       
   875                 pass
       
   876         return self._storeint
       
   877 
       
   878     def get_parent_path(self):
       
   879         """
       
   880         Return the path of the configuration resource
       
   881         """
       
   882         if self._parent:
       
   883             return utils.resourceref.get_path(self._parent.get_path())
       
   884         else:
       
   885             return ""
       
   886 
       
   887     def get_full_path(self, obj=None):
       
   888         """
       
   889         Return the path of the configuration resource
       
   890         """
       
   891         if obj != None:
       
   892             try:
       
   893                 return obj.get_full_path()
       
   894             except AttributeError:
       
   895                 pass
       
   896         # default path processing returns the fullpath of this elem
       
   897         parent_path = self.get_parent_path() 
       
   898         return utils.resourceref.join_refs([parent_path,self.get_path()])
       
   899 
       
   900 
       
   901 class LoadProxy(ContainerBase):
       
   902     """
       
   903     This class is meant for representing any object loading & unloading an object, 
       
   904     when it is actually needed.  
       
   905     object 
       
   906     """
       
   907     def __init__(self, path, store_interface=None):
       
   908         """
       
   909         @param path: the path which is used in loadin
       
   910         @param store_interface: the loading interface object, which is used. 
       
   911         Expects load(path) and dump(obj) functions  
       
   912         """
       
   913         self.set('_obj', None)
       
   914         self.set('_parent', None)
       
   915         self.set('path', path)
       
   916         self.set('_storeint', store_interface)
       
   917 
       
   918     def __getattr__(self,name):
       
   919         """
       
   920         direct all not found attribute calls to the sub object getattr
       
   921         """
       
   922         if not self._obj: 
       
   923             self._load()
       
   924         return getattr(self._obj,name)
       
   925 
       
   926     def __getstate__(self):
       
   927         """
       
   928         Return a state which should have sufficient info to load the proxy object but 
       
   929         dont serialize the object itself.
       
   930         """
       
   931         state = {}
       
   932         state['path'] = self.path
       
   933         state['_obj'] = None
       
   934         # state['_parent'] = self._parent
       
   935         state['_storeint'] = self._storeint
       
   936         return state
       
   937     
       
   938     def __setstate__(self, state):
       
   939         self.set('_obj', state.get('_obj',None))
       
   940         self.set('_storeint', state.get('_storeint',None))
       
   941         self.set('_parent', state.get('_parent',self._storeint))
       
   942         self.set('path', state.get('path',''))
       
   943 
       
   944     def __setattr__(self, name, value):
       
   945         """
       
   946         direct attribute setting calls to the sub object setattr
       
   947         """
       
   948         if not self._obj: 
       
   949             self._load()
       
   950         setattr(self._obj,name,value)
       
   951 
       
   952     def __delattr__(self, name):
       
   953         """
       
   954         direct attribute setting calls to the sub object setattr
       
   955         """
       
   956         if not self._obj: 
       
   957             self._load()
       
   958         delattr(self._obj,name)
       
   959 
       
   960     def _set_parent(self, newparent):
       
   961         """
       
   962         @param newparent:  The new parent object
       
   963         @return: None
       
   964         """
       
   965         self.set('_parent',newparent)
       
   966         if self._obj:
       
   967             self._obj._parent = self._parent
       
   968 
       
   969     def _set_obj(self, obj):
       
   970         self.set('_obj',obj)
       
   971         # set the same _parent for the actual object as is stored for the proxy
       
   972         if self._obj:
       
   973             self._obj._parent = self._parent
       
   974             self._obj.set_path(self.path)
       
   975 
       
   976     def _get_obj(self):
       
   977         if not self._obj: 
       
   978             self._load()
       
   979         return self._obj
       
   980 
       
   981     def _load(self):
       
   982         # Should the loading of layer external resources be supported?
       
   983         # E.g. resources with absolute path relative to the storage (starts with slash)
       
   984         """ If the loading of the object fails => Raise an InvalidObject exception """ 
       
   985         try:
       
   986             obj = self.get_store_interface().load(self.fullpath)
       
   987             self._set_obj(obj)
       
   988             obj.set_ref(utils.resourceref.to_objref(self.path))
       
   989         except exceptions.NotResource,e:
       
   990             logging.getLogger('cone').warning("Loading %s from parent %s failed! %s" % (self.path,self.get_parent_path(), e))
       
   991             raise exceptions.InvalidObject("Invalid configuration object %s" % self.path)
       
   992 
       
   993     def _unload(self):
       
   994         if self._obj:
       
   995             self.get_store_interface().unload(self.fullpath, self._obj)
       
   996             self.set('_obj',None)
       
   997 
       
   998     def get_store_interface(self):
       
   999         if not self._storeint:
       
  1000             self.set('_storeint',self._parent.get_store_interface())
       
  1001         return self._storeint
       
  1002 
       
  1003     def set(self,name,value):
       
  1004         """
       
  1005         Proxy has a specific attribute setting function, because by default all attributes are 
       
  1006         stored to the actual proxy object  
       
  1007         """
       
  1008         self.__dict__[name] = value
       
  1009 
       
  1010     def get(self,name):
       
  1011         """
       
  1012         Proxy has also a specific attribute getting function, because by default all attributes are 
       
  1013         stored to the actual proxy object  
       
  1014         """
       
  1015         return self.__dict__[name]
       
  1016 
       
  1017     def save(self):
       
  1018         if hasattr(self._obj,'save'):
       
  1019             self._obj.save()
       
  1020         self._unload()
       
  1021 
       
  1022     def close(self):
       
  1023         if hasattr(self._obj,'close'):
       
  1024             self._obj.close()
       
  1025 
       
  1026     def get_parent_path(self):
       
  1027         """
       
  1028         Return the path of the configuration resource
       
  1029         """
       
  1030         if self._parent:
       
  1031             return utils.resourceref.get_path(self._parent.get_path())
       
  1032         else:
       
  1033             return ""
       
  1034 
       
  1035     def get_path(self):
       
  1036         """
       
  1037         Return the path of the configuration resource
       
  1038         """
       
  1039         if self._obj:
       
  1040             return self._obj.get_path()
       
  1041         else:
       
  1042             return self.path
       
  1043 
       
  1044     @property
       
  1045     def fullpath(self):
       
  1046         """
       
  1047         Return the path of the configuration resource
       
  1048         """
       
  1049         try:
       
  1050             return self._obj.get_full_path() 
       
  1051         except AttributeError:
       
  1052             parent_path = self.get_parent_path() 
       
  1053             return utils.resourceref.join_refs([parent_path,self.path])