source: TI01-discovery/trunk/OAIInfoEditor/oai_info_editor/dal/editorfileclient.py @ 5240

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI01-discovery/trunk/OAIInfoEditor/oai_info_editor/dal/editorfileclient.py@5240
Revision 5240, 12.1 KB checked in by cbyrom, 11 years ago (diff)

Add data access methods to retrieve all provider information and add
tests to exercise these new methods.

  • Property svn:executable set to *
Line 
1'''
2 Class representing the data access object for provider info data - with
3 methods to create, update, retrieve and delete data - uses a simple client
4 to do ops direct to a flat file.
5 
6 @author: C Byrom, Tessella Apr 2009
7'''
8from xml.etree import cElementTree as ET
9import logging, datetime, os, uuid, urllib, shutil
10
11import oai_info_editor.lib.constants as c
12from oai_info_editor.model.providerinfocollection import ProviderInfoCollection
13from oai_info_editor.dal.interfaceeditordbclient import InterfaceEditorDataClient
14from ndg.common.src.lib.fileutilities import *
15
16
17class EditorFileClient(InterfaceEditorDataClient):
18
19    FILE_SUFFIX_1 = "_provider_info_data"
20    FILE_SUFFIX_2 = ".xml"
21   
22    def __init__(self, configFile = None):
23        '''
24        Constructor - initialise the client
25        @keyword configFile: myConfig object to use to set up client
26        '''
27        logging.info("Initialising EditorFileClient object")
28        self.cf = configFile
29        if configFile:
30            self.__setUpFileClient()
31        else:
32            self.dataDir = None
33            self.backupDir = None
34           
35        # field to allow easy access to collection info from outside of the client
36        # - primarily for testing purposes
37        self.pic = None
38        logging.info("EditorFileClient initialised")
39       
40
41    def __setUpFileClient(self):
42        '''
43        Do basic setting up of client - get config details and
44        ensure the required directory structure exists
45        '''
46        logging.debug("Setting up file client")
47        self.__getConfigInfo()
48       
49        createDir(self.dataDir)
50        createDir(self.backupDir)
51
52        logging.debug("- file client set up")
53
54
55    def __getConfigInfo(self):
56        '''
57        Retrieve file system info from the config file - in order to
58        establish where to create/backup data to
59        @raises SystemError: if no config file specified
60        @raises ValueError: if inappropriate config info specified
61        '''
62        logging.debug("Getting config info for data store")
63        if not self.cf:
64            raise SystemError("Cannot retrieve app data since a config file has not been specified")
65       
66        self.dataFileName = self.cf.get('DATA_STORE', 'appDataFileName')
67        self.dataDir = self.cf.get('DATA_STORE', 'appDataFileDir')
68        self.backupDir = self.cf.get('DATA_STORE', 'backupFileDir')
69       
70        if not self.dataDir or not self.backupDir or not self.dataFileName:
71            raise ValueError("Config file missing info - need keys, 'appDataFileName', 'appDataFileDir' and 'backupFileDir' specified")
72
73        logging.debug("Config info retrieved")
74
75
76    def __loadProviderInfoFile(self, fileName):
77        '''
78        Load the specified filename containing provider info - and
79        return this in a ProviderInfoCollection data model object
80        @param fileName: Name of file to open
81        @return: ProviderInfoCollection object with the file data in
82        '''
83        logging.debug("Reading provider info data from file, '%s'" %fileName)
84        f = open(fileName, 'r')
85        xml = f.read()
86        f.close()
87        pic = ProviderInfoCollection(fileName, xmlString = xml)
88        logging.debug("Returning info from file")
89        return pic
90
91
92    def _deleteProviderInfoFile(self, fileName):
93        '''
94        Delete the specified filename containing provider info - NB, this
95        is primarily for use in test cases to tidy up things
96        @param fileName: Name of file to delete
97        @return: True, if successful, False otherwise
98        '''
99        logging.debug("Deleting file, '%s'" %fileName)
100        if not os.path.isfile(fileName):
101            raise IOError("File to delete, '%s', does not exist" %fileName)
102       
103        os.remove(fileName)
104        logging.debug("File deleted successfully")
105        return True
106   
107
108    def __getProviderInfoData(self):
109        '''
110        Get the provider info
111        - if data already exists, load this in and return as a populated
112        ProviderInfoCollection object, otherwise create and return a new
113        ProviderInfoCollection
114        @return: ProviderInfoCollection object with the current provider info data and filename
115        '''
116        logging.debug("Getting provider info data")
117       
118        fileName = self.__generateFileName()
119       
120        pic = None
121        if os.path.isfile(fileName):
122            logging.debug("- config data already exists for this vocab list - load this now")
123            pic = self.__loadProviderInfoFile(fileName)
124           
125        else:
126            logging.debug(" - no data found for this list - setting up a new data collection")
127            pic = ProviderInfoCollection(fileName) 
128
129        return pic, fileName
130
131
132    def __createOrUpdatePICollection(self, pic):
133        '''
134        Create a new file containing the data from the input provider info
135        collection.  NB, firstly check if the collection file
136        already exists and, if it does, backup the old collection.
137        @param pic: ProviderInfoCollection object with data to output
138        @return ProviderInfoCollection created
139        '''
140        logging.info("Creating or updating provider info collection file")
141       
142        fileName = self.__generateFileName()
143        if os.path.isfile(fileName):
144            logging.info("- found existing file - creating backup")
145            logging.debug("- this will be a backup file")
146           
147            backupFileName = self.__generateFileName(isBackup = True)
148            logging.info("- backup change request collection file, '%s'" %backupFileName)
149           
150            shutil.copy(fileName, backupFileName)
151            pic.backupFile = backupFileName
152            if not os.path.isfile(backupFileName):
153                raise IOError("Problem occurred whilst creating backup file, '%s'" %backupFileName)
154           
155            # update the version number of the collection
156            pic.version = str(int(pic.version) + 1)
157
158        logging.info("- create provider info collection file, '%s'" %fileName)
159        createFile(fileName, pic.toXMLString())
160        return pic
161       
162       
163    def createProviderInfo(self, providerInfo):
164        '''
165        Create a new provider info record
166        @param providerInfo: ProviderInfo object with which to create the new
167        change request record
168        @raise ValueError if provider with same name already exists
169        @return ProviderInfo, fileName: object with any new data from the creation in + filename
170        '''
171        self.pic, fileName = self.__getProviderInfoData()
172        logging.info("Creating new provider info in file, '%s'" %fileName)
173       
174        # check provider with the same name doesn't already exist
175        pi = self.getProviderInfo(providerInfo.name)
176        if pi:
177            raise ValueError("Cannot create new provider info - a provider with the name, '%s' already exists" \
178                             %providerInfo.name)
179           
180        self.pic.addProviderInfo(providerInfo)
181       
182        # now, just dump the data out to the file
183        self.pic = self.__createOrUpdatePICollection(self.pic)
184       
185        logging.info("New provider info created in XML file")
186        return providerInfo, fileName
187   
188   
189    def updateProviderInfo(self, providerInfo):
190        '''
191        Update the input providerInfo
192        @param providerInfo: ProviderInfo object to update
193        @raise ValueError: if ProviderInfo doesn't have a name specified
194        @return ProviderInfo, fileName: object with any new data from the creation in
195        '''
196        logging.info("Updating provider info in XML file")
197
198        if not providerInfo.name:
199            raise ValueError("Provider info name is not specified: cannot update entry")
200       
201        self.pic, fileName = self.__getProviderInfoData()
202       
203        self.pic.addProviderInfo(providerInfo, raiseErrorIfNotFound = True)
204        self.pic = self.__createOrUpdatePICollection(self.pic)
205
206        logging.info("Change request updated in file")
207        return providerInfo
208
209       
210    def deleteProviderInfo(self, providerName):
211        '''
212        Delete the input providerInfo from the backend data file
213        @param providerName: Name of provider to delete
214        @return True if successful, False otherwise
215        '''
216        logging.info("Deleting provider info in provider info collection")
217        self.pic, fileName = self.__getProviderInfoData()
218       
219        self.pic.removeProviderInfo(providerName)
220        self.pic = self.__createOrUpdatePICollection(self.pic)
221        logging.info("Delete complete successfully")
222        return True
223
224
225    def getProviderInfo(self, providerInfoName):
226        '''
227        Get the provider info details for the specified name
228        @param providerInfoName: name of the provider info to retrieve
229        @return ProviderInfo: object with requested data - or None if no data found
230        ''' 
231        logging.info("Retrieving provider info with name, '%s'" %(providerInfoName))
232        pi = None
233        self.pic, fileName = self.__getProviderInfoData()
234       
235        try:
236            pi = self.pic.getProviderInfoByName(providerInfoName)
237            logging.info("- returning provider info details")
238        except ValueError:
239            logging.info("- no data found with specified name - returning None")
240           
241        return pi
242
243
244    def getAllProviderInfo(self):
245        '''
246        Get all provider info
247        @return ProviderInfo list: list of ProviderInfo objects representing all provider info data
248        ''' 
249        logging.info("Retrieving all provider info data")
250        self.pic, fileName = self.__getProviderInfoData()
251           
252        return self.pic.providerInfos
253       
254       
255    def getRepositoryInfo(self, providerInfoName, repositoryInfoName):
256        '''
257        Get the repository info object for the specified provider and repository name
258        @param providerInfoName: name of the provider info to retrieve
259        @param repositoryInfoName: name of the repository info to retrieve
260        @return RepositoryInfo object with the requested data - or None if no data found
261        '''
262        logging.debug("Retrieving repository info, '%s' for provider, '%s'" \
263                      %(repositoryInfoName, providerInfoName))
264        ri = None
265        self.pic, fileName = self.__getProviderInfoData()
266       
267        try:
268            pi = self.pic.getProviderInfoByName(providerInfoName)
269            ri = pi.getRepositoryInfoByName(repositoryInfoName)
270            logging.info("- returning repository info details")
271        except ValueError:
272            logging.info("- no data found with specified name - returning None")
273        return ri
274
275
276    def getProviderInfoForUser(self, user):
277        '''
278        Return provider info records valid to the input user
279        @param user: a User object with user details
280        @return list of ProviderInfo objects which the user can update
281        '''
282        self.pic, fileName = self.__getProviderInfoData()
283       
284        pis = self.pic.getProviderInfoForUser(user)
285           
286        return pis
287       
288
289    def __generateFileName(self, isBackup = False):
290        '''
291        Generate the filename for the provider info data.  If keyword, 'isBackup'
292        is set to True, generate an appropriate backup filename
293        @keyword isBackup: If True, generate a name for a backup file - with datestamp
294        and in the backup directory.  Default = False.
295        @return fileName: full path to file
296        '''
297        logging.debug("Generating filename to store provider info")
298
299        # check we have the necessary config info
300        if not self.dataDir:
301            self.__setUpFileClient()
302           
303        if isBackup:
304            logging.debug("- this will be a backup file")
305            dateStamp = datetime.datetime.now().strftime(c.DATE_FORMAT)
306            fileName = self.backupDir + os.sep + self.dataFileName + self.FILE_SUFFIX_1 + dateStamp 
307        else:
308            fileName = self.dataDir + os.sep + self.dataFileName + self.FILE_SUFFIX_1
309       
310        fileName = fileName + self.FILE_SUFFIX_2
311        # remove colons - for the benefit of Windows
312        fileName = fileName.replace(':', '.')
313
314        logging.debug("- returning filename, '%s'" %fileName)
315        return fileName
Note: See TracBrowser for help on using the repository browser.