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., |
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. |
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]) |