configurationengine/source/cone/storage/filestorage.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 import os
       
    18 import re
       
    19 import logging
       
    20 import xml.parsers.expat
       
    21 try:
       
    22     from cElementTree import ElementTree
       
    23 except ImportError:
       
    24     try:    
       
    25         from elementtree import ElementTree
       
    26     except ImportError:
       
    27         try:
       
    28             from xml.etree import cElementTree as ElementTree
       
    29         except ImpotError:
       
    30             from xml.etree import ElementTree
       
    31             
       
    32 from cone.public import exceptions  
       
    33 from cone.public import api, utils
       
    34 #from cone.storage.configurationpersistence import ConfigurationReader, ConfigurationWriter
       
    35 from cone.storage import metadata, common
       
    36 from cone.confml import persistentconfml
       
    37 debug = 0
       
    38 
       
    39 class FileStorage(common.StorageBase):
       
    40     """
       
    41     A file system based implementation for Storage.
       
    42     @param path : path to the storage folder
       
    43     @param mode: the mode for the folder. Default is a=append that expects the folder to exist.
       
    44     """
       
    45     
       
    46     def __init__(self,path,mode="r", **kwargs):
       
    47         super(FileStorage, self).__init__(path)
       
    48         self.logger = logging.getLogger('cone')
       
    49         self.logger.debug("FileStorage path %s" % self.get_path())
       
    50         self.persistentmodule = persistentconfml
       
    51         self.mode = mode
       
    52         if mode.find("a")!=-1 or mode.find("r")!=-1:
       
    53             # check that the given folder exists and is a folder    
       
    54             if not os.path.isdir(self.get_path()):
       
    55                 raise exceptions.StorageException("The given data folder for storage does not exist! %s" % self.get_path())
       
    56         elif mode.find("w")!=-1:
       
    57             # check if the given folder exists and create it if it does not
       
    58             if not os.path.exists(os.path.abspath(self.get_path())):
       
    59                 os.makedirs(self.get_path())
       
    60         else:
       
    61             raise exceptions.StorageException("Unsupported creation mode given! %s" % mode)
       
    62         
       
    63         
       
    64 
       
    65     @classmethod
       
    66     def supported_storage(cls,path):
       
    67         """
       
    68         Class method for determing if the given clas supports a storage by given path. 
       
    69         E.g. foo.zip, foo.cpd, foo/bar, http://foo.com/
       
    70         @param path:
       
    71         @return: Boolean value. True if the storage of the path is supported. False if not.  
       
    72         """
       
    73         if path.startswith('http://'):
       
    74             return False
       
    75         path = os.path.abspath(path)
       
    76         (name,ext) = os.path.splitext(path)
       
    77         if path != "" and ext == "":
       
    78             return True
       
    79         elif os.path.isdir(path):
       
    80             return True
       
    81         else:
       
    82             return False
       
    83 
       
    84     def open_resource(self,path,mode="r"):
       
    85         # make sure that path exists if we are creating a file
       
    86         path = utils.resourceref.remove_end_slash(path)
       
    87         path = utils.resourceref.remove_begin_slash(path)
       
    88         path = utils.resourceref.join_refs([self.get_current_path(), path])
       
    89         fullpath = utils.resourceref.join_refs([self.get_path(),path])
       
    90         if mode.find("w") != -1:
       
    91             dirpath = os.path.dirname(fullpath)
       
    92             if not os.path.exists(dirpath):
       
    93                 os.makedirs(dirpath)
       
    94         try:
       
    95             res = FileResource(self,path,mode,open(fullpath,mode)) 
       
    96             self.__opened__(res)
       
    97             return res
       
    98         except IOError,e:
       
    99             raise exceptions.NotResource("%s, %s" % (path,e) )
       
   100 
       
   101     def delete_resource(self,path):
       
   102         if self.is_resource(path):
       
   103             try:
       
   104                 path = utils.resourceref.remove_begin_slash(path)
       
   105                 path = utils.resourceref.join_refs([self.get_path(),self.get_current_path(),path])
       
   106                 for res in self.__get_open__(path):
       
   107                     res.close()
       
   108                     self.__closed__(res)
       
   109                 os.unlink(path)
       
   110             except IOError:
       
   111                 raise exceptions.NotResource(path)
       
   112         else:
       
   113             raise exceptions.NotResource(path)
       
   114 
       
   115     def close_resource(self, res):
       
   116         """
       
   117         Close the given resource instance. Normally this is called by the Resource object 
       
   118         in its own close.
       
   119         @param res: the resource object to close. 
       
   120         """
       
   121         try:
       
   122             self.__closed__(res)
       
   123             #if not res.get_mode() == api.Storage.MODE_READ:
       
   124             #    self._get(utils.resourceref.to_dref(res.path)).data = res.getvalue()
       
   125         except KeyError,e:
       
   126             raise exceptions.StorageException("No such %s open resource! %s" % (res.path,e))
       
   127             
       
   128 
       
   129     def save_resource(self, res):
       
   130         """
       
   131         Flush the changes of a given resource instance. Normally this is called by the Resource object 
       
   132         in its own save.
       
   133         @param res: the resource to the resource to save. 
       
   134         """
       
   135         if not self.__has_resource__(res):
       
   136             raise exceptions.NotResource("No such %s open resource!" % res.path)
       
   137         else:
       
   138             res.save()
       
   139 
       
   140     def is_resource(self,path):
       
   141         path = utils.resourceref.remove_begin_slash(path)
       
   142         path = utils.resourceref.join_refs([self.get_current_path(), path])
       
   143         path = utils.resourceref.join_refs([self.get_path(),path])
       
   144         norm_path = os.path.normpath(path)
       
   145         return os.path.isfile(norm_path)
       
   146 
       
   147     def fix_entry(self,entry,current_root):
       
   148         entry = entry.replace(current_root,'')
       
   149         entry = entry.replace("\\","/")
       
   150         entry = utils.resourceref.remove_begin_slash(entry)
       
   151         return entry
       
   152 
       
   153 
       
   154     def list_resources(self,path,recurse=False,empty_folders=False):
       
   155         """
       
   156         Get an array of files in a folder
       
   157         """
       
   158         
       
   159         retarray = []
       
   160         path = utils.resourceref.remove_begin_slash(path)
       
   161         fullpath = utils.resourceref.join_refs([self.get_path(),self.get_current_path(),path])
       
   162         joined = os.path.join(self.get_path(), self.get_current_path())
       
   163         current_root = os.path.normpath(os.path.abspath(joined))
       
   164         # return always unix type file paths
       
   165         if recurse:    
       
   166             # Walk through all files in the layer
       
   167             for root, dirs, files in os.walk(fullpath):
       
   168                 for name in files:
       
   169                     entry = os.path.join(root, name)
       
   170                     entry = os.path.normpath(os.path.abspath(entry))
       
   171                     if os.path.isfile(entry):
       
   172                         retarray.append(self.fix_entry(entry,current_root))
       
   173                         
       
   174                 if empty_folders: 
       
   175                     for name in dirs:
       
   176                         entry = os.path.join(root, name)
       
   177                         entry = os.path.normpath(os.path.abspath(entry))
       
   178                         if  os.path.isdir(entry)  and  len(os.listdir(entry)) ==0:
       
   179                             retarray.append(self.fix_entry(entry,current_root))
       
   180                         
       
   181         else:
       
   182             filelist = os.listdir(fullpath)
       
   183             for name in filelist:
       
   184                 entry = os.path.join(path, name)
       
   185                 entry = os.path.normpath(entry)
       
   186                 entry = entry.replace("\\","/")               
       
   187                 entry = utils.resourceref.remove_begin_slash(entry)
       
   188                 # ignore non file entries
       
   189                 fileentry = os.path.join(current_root,entry)
       
   190                 if os.path.isfile(fileentry):
       
   191                     if debug: print "list_resources adding %s" % entry
       
   192                     retarray.append(entry)
       
   193                     
       
   194                 if os.path.isdir(fileentry) and empty_folders:
       
   195                     if debug: print "list_resources adding %s" % entry
       
   196                     retarray.append(entry)
       
   197         return retarray
       
   198 
       
   199     def import_resources(self,paths,storage):
       
   200         for path in paths:
       
   201             if not storage.is_resource(path):
       
   202                 logging.getLogger('cone').warning("The given path is not a Resource in the storage %s! Ignoring from export!" % path)
       
   203                 continue
       
   204             wres = self.open_resource(path,'wb')
       
   205             res  = storage.open_resource(path,"rb")
       
   206             wres.write(res.read())
       
   207             wres.close()
       
   208             res.close()
       
   209     
       
   210     def export_resources(self,paths,storage,empty_folders=False):
       
   211         """
       
   212         
       
   213         
       
   214         """
       
   215         for path in paths:
       
   216             if not self.is_resource(path) and empty_folders==False:
       
   217                 logging.getLogger('cone').warning("The given path is not a Resource in this storage %s! Ignoring from export!" % path)
       
   218                 continue
       
   219             if self.is_resource(path):
       
   220                 wres = storage.open_resource(path,'wb')
       
   221                 res  = self.open_resource(path,"rb")
       
   222                 wres.write(res.read())
       
   223                 wres.close()
       
   224                 res.close()
       
   225                 
       
   226                 
       
   227             if  self.is_folder(path) and  empty_folders:
       
   228                 storage.create_folder(path)
       
   229     
       
   230                 
       
   231                 
       
   232 
       
   233     def create_folder(self,path):
       
   234         """
       
   235         Create a folder entry to a path
       
   236         @param path : path to the folder
       
   237         """
       
   238         
       
   239         path = utils.resourceref.join_refs([self.get_path(), self.get_current_path(), path])
       
   240         if not os.path.exists(path):
       
   241             os.makedirs(path)
       
   242 
       
   243     def delete_folder(self,path):
       
   244         """
       
   245         Delete a folder entry from a path. The path must be empty.
       
   246         @param path : path to the folder
       
   247         """
       
   248         path = utils.resourceref.join_refs([self.get_path(), self.get_current_path(), path])
       
   249         if os.path.isdir(path):
       
   250             os.rmdir(path)
       
   251         else:
       
   252             raise exceptions.StorageException("Not a folder %s" % path)
       
   253 
       
   254     def is_folder(self,path):
       
   255         """
       
   256         Check if the given path is an existing folder in the storage
       
   257         @param path : path to the folder
       
   258         """
       
   259         path = utils.resourceref.join_refs([self.get_path(), self.get_current_path(), path])
       
   260         return os.path.isdir(path)
       
   261 
       
   262     def unload(self, path, object):
       
   263         """
       
   264         Dump a given object to the storage (reference is fetched from the object)
       
   265         @param object: The object to dump to the storage, which is expected to be an instance 
       
   266         of Base class.
       
   267         """
       
   268         # Add the current path in front of the given path
       
   269         path = utils.resourceref.join_refs([self.get_current_path(), path])
       
   270         if not isinstance(object, api.Configuration):
       
   271             raise exceptions.StorageException("Cannot dump object type %s" % object.__class__)
       
   272         # Skip the unload storing to storage if the storage is opened in read mode
       
   273         if self.get_mode(self.mode) != api.Storage.MODE_READ:
       
   274             res = self.open_resource(path,"wb")
       
   275             data = self.persistentmodule.dumps(object)
       
   276             res.write(data)
       
   277             res.close()
       
   278         return
       
   279 
       
   280 
       
   281     def load(self, path):
       
   282         """
       
   283         Load an from a reference.
       
   284         """
       
   285         # Add the current path in front of the given path
       
   286         path = utils.resourceref.join_refs([self.get_current_path(), path])
       
   287         if not utils.resourceref.get_ext(path) == "confml":
       
   288             raise exceptions.StorageException("Cannot load reference type %s" % utils.resourceref.get_ext(path))
       
   289         if self.is_resource(path):
       
   290             res = self.open_resource(path,"r")
       
   291             # read the resource with persistentmodule
       
   292             try:
       
   293                 obj = self.persistentmodule.loads(res.read())
       
   294                 #obj.set_path(path)
       
   295                 res.close()
       
   296                 return obj
       
   297             except exceptions.ParseError,e:
       
   298                 logging.getLogger('cone').error("Resource %s parsing failed with exception: %s" % (path,e))
       
   299                 # returning an empty config in case of xml parsing failure.
       
   300                 return api.Configuration(path)
       
   301         else:
       
   302             raise exceptions.NotResource("No such %s resource!" % path)
       
   303 
       
   304 
       
   305 class FileResource(api.Resource):
       
   306     def __init__(self,storage,path,mode,handle):
       
   307         api.Resource.__init__(self,storage,path,mode)
       
   308         self.handle = handle
       
   309         
       
   310     def read(self,bytes=0):
       
   311         if bytes == 0:
       
   312             return self.handle.read()
       
   313         else:
       
   314             return self.handle.read(bytes)
       
   315     
       
   316     def write(self,string):
       
   317         if self.get_mode() == api.Storage.MODE_READ:
       
   318             raise exceptions.StorageException("Writing attempted to %s in read-only mode." % self.path)
       
   319         else:
       
   320             self.handle.write(string)
       
   321 
       
   322     def truncate(self, size=0):
       
   323         self.handle.truncate(0)
       
   324         self.handle.seek(size, 0)
       
   325 
       
   326     def save(self):
       
   327         if not self.handle.closed:
       
   328             self.handle.save()
       
   329 
       
   330     def close(self):
       
   331         self.storage.close_resource(self)
       
   332         self.handle.close()
       
   333     
       
   334     def get_size(self):
       
   335         if self.get_mode() == api.Storage.MODE_WRITE:
       
   336             raise exceptions.StorageException("Reading size attempted to %s in write-only mode." % self.path)
       
   337         orig_pos = self.handle.tell()
       
   338         self.handle.seek(0, os.SEEK_END)
       
   339         try:        return self.handle.tell()
       
   340         finally:    self.handle.seek(orig_pos, os.SEEK_SET)
       
   341     
       
   342     def get_content_info(self):
       
   343         orig_pos = self.handle.tell()
       
   344         self.handle.seek(0, os.SEEK_SET)
       
   345         data = self.handle.read()
       
   346         self.handle.seek(orig_pos, os.SEEK_SET)
       
   347         if self.content_info == None:
       
   348             self.content_info = utils.make_content_info(self, data)
       
   349         
       
   350         return self.content_info