|
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 import StringIO |
|
18 import os |
|
19 import pickle |
|
20 import copy |
|
21 import logging |
|
22 |
|
23 from cone.public import * |
|
24 from cone.storage import persistentdictionary |
|
25 |
|
26 |
|
27 class _StringStorageObject(container.ObjectContainer): |
|
28 def __init__(self, name): |
|
29 container.ObjectContainer.__init__(self, utils.resourceref.to_dottedref(name)) |
|
30 self.path = name |
|
31 self.data = "" |
|
32 |
|
33 def get_path(self): |
|
34 """ |
|
35 Return the path of the configuration resource |
|
36 """ |
|
37 return self.path |
|
38 |
|
39 def set_path(self,path): |
|
40 """ |
|
41 Set the path of the configuration resource |
|
42 """ |
|
43 self.path = path |
|
44 |
|
45 def path_to_elem(self, toparent=None): |
|
46 parent_path = "" |
|
47 # check if the parent is found at all from this hierarchy |
|
48 if toparent and not self._find_parent_or_default(match=toparent): |
|
49 toparent = self._find_parent_or_default(container=True) |
|
50 if self._find_parent(): |
|
51 parent_path = self._find_parent()._path(toparent).replace(".","/") |
|
52 return utils.resourceref.join_refs([parent_path,self.get_path()]) |
|
53 |
|
54 def __getstate__(self): |
|
55 return self.__dict__.copy() |
|
56 |
|
57 def __setstate__(self,dict): |
|
58 self.__dict__ = dict.copy() |
|
59 |
|
60 class StringStorage(api.Storage, container.ObjectContainer): |
|
61 """ |
|
62 A general base class for all storage type classes |
|
63 @param path : the reference to the root of the storage. |
|
64 """ |
|
65 def __init__(self, path): |
|
66 container.ObjectContainer.__init__(self,"") |
|
67 api.Storage.__init__(self,path) |
|
68 |
|
69 def __getstate__(self): |
|
70 dict = self.__dict__.copy() |
|
71 del dict['__opened_res__'] |
|
72 return dict |
|
73 |
|
74 def __setstate__(self,dict): |
|
75 self.__dict__ = dict.copy() |
|
76 self.__dict__['__opened_res__'] = {} |
|
77 |
|
78 def __dump__(self): |
|
79 """ |
|
80 Dump the storage to the reference file |
|
81 """ |
|
82 file = open(self.get_path(),"w") |
|
83 pickle.dump(self,file) |
|
84 file.close() |
|
85 |
|
86 @classmethod |
|
87 def __open__(cls,path, mode="r"): |
|
88 if mode.find("a")!=-1 or mode.find("r")!=-1: |
|
89 if os.path.exists(path) and os.path.isfile(path): |
|
90 file = open(path,"r") |
|
91 obj = pickle.load(file) |
|
92 file.close() |
|
93 else: |
|
94 raise exceptions.StorageException("The given data file for storage does not exist! %s" % path) |
|
95 elif mode.find("w")!=-1: |
|
96 # check if the given storage path exists and delete it if it does |
|
97 if os.path.dirname(path) != '' and not os.path.exists(os.path.dirname(path)): |
|
98 os.makedirs(os.path.dirname(path)) |
|
99 obj = StringStorage(path) |
|
100 """ key value pairs of data. Key path = datastring """ |
|
101 else: |
|
102 raise exceptions.StorageException("Unsupported creation mode given! %s" % mode) |
|
103 return obj |
|
104 |
|
105 @classmethod |
|
106 def supported_storage(cls,path): |
|
107 """ |
|
108 Class method for determing if the given clas supports a storage by given path. |
|
109 E.g. foo.zip, foo.cpd, foo/bar, http://foo.com/ |
|
110 @param path: |
|
111 @return: Boolean value. True if the storage of the path is supported. False if not. |
|
112 """ |
|
113 if utils.resourceref.get_ext(path) == "pk": |
|
114 return True |
|
115 else: |
|
116 return False |
|
117 |
|
118 def close(self): |
|
119 """ |
|
120 Close the repository, which will save and close all open resources. |
|
121 """ |
|
122 super(StringStorage,self).close() |
|
123 self.__dump__() |
|
124 |
|
125 def save(self): |
|
126 """ |
|
127 Save changes from all resources to the repository. |
|
128 """ |
|
129 super(StringStorage,self).save() |
|
130 self.__dump__() |
|
131 |
|
132 def open_resource(self,path,mode="r"): |
|
133 """ |
|
134 Open the given resource and return a File object. |
|
135 @param path : reference to the resource |
|
136 @param mode : the mode in which to open. Can be one of r = read, w = write, a = append. |
|
137 raises a NotResource exception if the path item is not a resource. |
|
138 """ |
|
139 res = None |
|
140 # Add the current path in front of the given path |
|
141 path = utils.resourceref.join_refs([self.get_current_path(), path]) |
|
142 dottedref = utils.resourceref.to_dref(path) |
|
143 (pathto,name)= utils.resourceref.psplit_ref(path) |
|
144 (dpath, dref) = utils.dottedref.psplit_ref(dottedref) |
|
145 |
|
146 # check for existence |
|
147 if self.get_mode(mode) == self.MODE_READ: |
|
148 try: |
|
149 # Try to create a new StringResource in any case |
|
150 |
|
151 res = StringResource(self, path, self._get(dottedref).data,mode) |
|
152 except exceptions.NotFound,e: |
|
153 raise exceptions.NotResource("Not found %s" % path) |
|
154 elif self.get_mode(mode) == self.MODE_WRITE: |
|
155 # Create a new StringResource in any case |
|
156 self._add_to_path(dpath,_StringStorageObject(name)) |
|
157 res = StringResource(self, path, self._get(dottedref).data,mode) |
|
158 elif self.get_mode(mode) == self.MODE_APPEND: |
|
159 # Append case, create the data reference if it is not existing |
|
160 if not self._has(dottedref): |
|
161 self._add_to_path(dpath,_StringStorageObject(name)) |
|
162 # Create a new StringResource in any case |
|
163 res = StringResource(self, path, self._get(dottedref).data,mode) |
|
164 res.seek(0, os.SEEK_END) |
|
165 self.__opened__(res) |
|
166 return res |
|
167 |
|
168 def delete_resource(self,path): |
|
169 """ |
|
170 Delete the given resource from storage |
|
171 @param res : Resource objcet to the resource |
|
172 raises a NotSupportedException exception if delete operation is not supported by the storage |
|
173 """ |
|
174 # First close all open resources |
|
175 # Add the current path in front of the given path |
|
176 path = utils.resourceref.join_refs([self.curpath, path]) |
|
177 for res in self.__get_open__(path): |
|
178 self.__closed__(res) |
|
179 self._remove(utils.resourceref.to_dref(path)) |
|
180 |
|
181 def close_resource(self, res): |
|
182 """ |
|
183 Close the given resource instance. Normally this is called by the Resource object |
|
184 in its own close. |
|
185 @param res: the resource object to close. |
|
186 """ |
|
187 try: |
|
188 self.__closed__(res) |
|
189 if not res.get_mode() == api.Storage.MODE_READ: |
|
190 self._get(utils.resourceref.to_dref(res.path)).data = res.getvalue() |
|
191 except KeyError,e: |
|
192 raise StorageException("No such %s open resource! %s" % (res.path,e)) |
|
193 |
|
194 |
|
195 def save_resource(self, res): |
|
196 """ |
|
197 Flush the changes of a given resource instance. Normally this is called by the Resource object |
|
198 in its own save. |
|
199 @param res: the resource to the resource to save. |
|
200 """ |
|
201 if not self.__has_resource__(res): |
|
202 raise exceptions.NotResource("No such %s open resource!" % res.path) |
|
203 else: |
|
204 if not res.get_mode() == api.Storage.MODE_READ: |
|
205 self._get(utils.resourceref.to_dref(res.path)).data = res.getvalue() |
|
206 |
|
207 def is_resource(self,path): |
|
208 """ |
|
209 Return true if the path is a resource |
|
210 @param path : reference to path where resources are searched |
|
211 """ |
|
212 # Add the current path in front of the given path |
|
213 path = utils.resourceref.join_refs([self.get_current_path(), path]) |
|
214 return self._has(utils.resourceref.to_dref(path)) |
|
215 |
|
216 def list_resources(self,path,recurse=False,empty_folders=False): |
|
217 """ |
|
218 find the resources under certain path/path |
|
219 @param path : reference to path where resources are searched |
|
220 @param recurse : defines whether to return resources directly under the path or does the listing recurse to subfolders. |
|
221 Default value is False. Set to True to enable recursion. |
|
222 """ |
|
223 """ Get the given curpath element """ |
|
224 try: |
|
225 curelem = self._get(utils.resourceref.to_dref(self.get_current_path())) |
|
226 dref = utils.resourceref.to_dref(path) |
|
227 if recurse: |
|
228 return sorted([child.path_to_elem(curelem) for child in curelem._get(dref)._traverse(type=_StringStorageObject)]) |
|
229 else: |
|
230 return sorted([child.path_to_elem(curelem) for child in curelem._get(dref)._objects(type=_StringStorageObject)]) |
|
231 except exceptions.NotFound: |
|
232 return [] |
|
233 |
|
234 def import_resources(self,paths,storage,empty_folders=False): |
|
235 for path in paths: |
|
236 if not storage.is_resource(path): |
|
237 logging.getLogger('cone').warning("The given path is not a Resource in the storage %s! Ignoring from export!" % path) |
|
238 continue |
|
239 wres = self.open_resource(path,'wb') |
|
240 res = storage.open_resource(path,"rb") |
|
241 wres.write(res.read()) |
|
242 wres.close() |
|
243 res.close() |
|
244 |
|
245 |
|
246 def create_folder(self,path): |
|
247 """ |
|
248 Create a folder entry to a path |
|
249 @param path : path to the folder |
|
250 """ |
|
251 if not self._has(utils.resourceref.to_dref(path)): |
|
252 (dpath,name) = utils.dottedref.psplit_ref(utils.resourceref.to_dref(path)) |
|
253 self._add_to_path(dpath, self._default_object(name)) |
|
254 |
|
255 def delete_folder(self,path): |
|
256 """ |
|
257 Delete a folder entry from a path. The path must be empty. |
|
258 @param path : path to the folder |
|
259 """ |
|
260 self._remove(utils.resourceref.to_dref(path)) |
|
261 |
|
262 def is_folder(self,path): |
|
263 """ |
|
264 Check if the given path is an existing folder in the storage |
|
265 @param path : path to the folder |
|
266 """ |
|
267 return self._has(utils.resourceref.to_dref(path)) |
|
268 |
|
269 def export_resources(self,refs,storage,empty_folders=False): |
|
270 """ |
|
271 export resources from this storage based on a list of reference to this storage |
|
272 @param refs : a list of resource names in this storage (references). |
|
273 @param storage : the external storage where to export. |
|
274 """ |
|
275 storage.import_resources(refs, self, empty_folders=empty_folders) |
|
276 |
|
277 def unload(self, path, object): |
|
278 """ |
|
279 Dump a given object to the storage (reference is fetched from the object) |
|
280 @param object: The object to dump to the storage, which is expected to be an instance |
|
281 of Base class. |
|
282 """ |
|
283 # Add the current path in front of the given path |
|
284 path = utils.resourceref.join_refs([self.get_current_path(), path]) |
|
285 if not isinstance(object, api.Configuration): |
|
286 raise exceptions.StorageException("Cannot dump object type %s" % object.__class__) |
|
287 res = self.open_resource(path,"w") |
|
288 data = persistentdictionary.dumps(object) |
|
289 res.write(data) |
|
290 res.close() |
|
291 return |
|
292 |
|
293 def load(self, path): |
|
294 """ |
|
295 Load an from a reference. |
|
296 """ |
|
297 # Add the current path in front of the given path |
|
298 path = utils.resourceref.join_refs([self.get_current_path(), path]) |
|
299 if not utils.resourceref.get_ext(path) == "confml": |
|
300 raise exceptions.StorageException("Cannot load object from given path = %s!" % path) |
|
301 if self.is_resource(path): |
|
302 res = self.open_resource(path,"r") |
|
303 # read the dictionary from the resource with eval |
|
304 obj = persistentdictionary.loads(res.read()) |
|
305 res.close() |
|
306 return obj |
|
307 else: |
|
308 raise exceptions.NotResource("No such %s resource!" % path) |
|
309 |
|
310 class StringResource(api.Resource): |
|
311 """ |
|
312 A StringResource class that works on top of StringIO buffer. This class in |
|
313 intended mainly for testing purposes. |
|
314 """ |
|
315 def __init__(self,storage,path,stringdata, mode=api.Storage.MODE_READ): |
|
316 strio = StringIO.StringIO(stringdata) |
|
317 api.Resource.__init__(self,storage,path, mode) |
|
318 self.handle = strio |
|
319 self.read = self.handle.read |
|
320 self.tell = self.handle.tell |
|
321 self.seek = self.handle.seek |
|
322 self.readline = self.handle.readline |
|
323 self.getvalue = self.handle.getvalue |
|
324 |
|
325 def write(self, string): |
|
326 if self.get_mode() == api.Storage.MODE_READ: |
|
327 raise exceptions.StorageException("Writing attempted to %s in read-only mode." % self.path) |
|
328 else: |
|
329 self.handle.write(string) |
|
330 |
|
331 def read(self, bytes=0): |
|
332 if self.get_mode() == api.Storage.MODE_WRITE: |
|
333 raise exceptions.StorageException("Reading attempted to %s in write-only mode." % self.path) |
|
334 else: |
|
335 self.handle.read(string) |
|
336 |
|
337 def save(self): |
|
338 self.storage.save_resource(self) |
|
339 |
|
340 def close(self): |
|
341 self.storage.close_resource(self) |
|
342 self.handle.close() |
|
343 |
|
344 def get_size(self): |
|
345 if self.get_mode() == api.Storage.MODE_WRITE: |
|
346 raise exceptions.StorageException("Reading resource size attempted to %s in write-only mode." % self.path) |
|
347 return len(self.handle.getvalue()) |
|
348 |
|
349 def get_content_info(self): |
|
350 if self.content_info == None: |
|
351 self.content_info = utils.make_content_info(self, self.handle.getvalue()) |
|
352 |
|
353 return self.content_info |