source: exist/trunk/python/ndgUtils/models/existdbclient.py @ 4220

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/exist/trunk/python/ndgUtils/models/existdbclient.py@4220
Revision 4220, 9.2 KB checked in by cbyrom, 11 years ago (diff)

Move the atom specific eXist db client code to ndgutils for re-use + move
associated tests.

Line 
1'''
2 Class supporting set up and communication with eXist DB
3 for the purposes of creating and updating atoms
4 
5 @author: C Byrom - Tessella 08
6'''
7import os, sys, logging, datetime
8from ndgUtils.eXistInterface import ndg_eXist
9from ndgUtils.eXistConnector import eXistConnector as ec
10
11class eXistDBClient:
12   
13   
14    def __init__(self, configFile):
15        '''
16        Initialise a connection to the eXistDB
17        '''
18        logging.info("Initialising connection to eXist DB")
19        # Firstly load in config data
20        self._loadDBDetails(configFile)
21       
22        # Now set up the connection
23        self.xmldb = ndg_eXist(db = self.eXistDBHostname, passwordFile = configFile)
24       
25        # set up any collections required - NB, if these already exist they won't cause any files to be lost
26        self._setUpEXistCollections()
27        logging.info("eXist DB connection initialised")
28
29
30    def createCollections(self, collections):
31        '''
32        Create the specified collections in eXist
33        @param collections: array of collections to create
34        @return True if successful
35        '''
36        logging.info("Setting up eXist collections")
37        for col in collections:
38            logging.debug("Creating collection, '%s'" %col)
39            self.xmldb.createCollection(col)
40        logging.info("All collections set up")
41
42
43    def _setUpEXistCollections(self):
44        '''
45        Set up the required eXist collections needed for running the granulator script
46        '''
47        logging.info("Ensuring required collections are available in eXist")
48        for col in [ec.BASE_COLLECTION_PATH, ec.BACKUP_COLLECTION_PATH]:
49            for type in [ec.OLD_COLLECTION_PATH, ec.PUBLISHED_COLLECTION_PATH, \
50                         ec.SMALL_P_PUBLISHED_COLLECTION_PATH, ec.WORKING_COLLECTION_PATH]:
51                self.xmldb.createCollection(col)
52                self.xmldb.createCollection(col + type)
53                self.xmldb.createCollection(col + type + ec.DE_COLLECTION_PATH)
54                self.xmldb.createCollection(col + type + ec.DEPLOYMENT_COLLECTION_PATH)
55                self.xmldb.createCollection(col + type + ec.GRANULE_COLLECTION_PATH)
56        logging.info("Required collections available")
57       
58
59    def _loadDBDetails(self, configFile):
60        '''
61        Retrieve info from the eXist db config file
62        '''
63        logging.info("Loading DB config data")
64        # Check this file exists
65        if not os.path.isfile(configFile):
66            errorMessage = "ERROR: Could not find the DB config file, %s; please make sure this " \
67                     "is available from the running directory" %configFile
68            logging.error(errorMessage)
69            raise ValueError(errorMessage)
70        dbinfo_file=open(configFile, "r")
71        dbinfo = dbinfo_file.read().split()
72        if len(dbinfo) < 3:
73            errorMessage = 'Incorrect data in DB config file'
74            logging.error(errorMessage)
75            raise ValueError(errorMessage)
76        self.eXistDBHostname = dbinfo[0]
77        self._username = dbinfo[1]
78        self._pw = dbinfo[2]
79        logging.info("DB config data loaded")
80
81
82    def _lookupEXistFile(self, docPath):
83        '''
84        Look up a file in eXist using XPath
85        @param docPath: path to doc to look up
86        @return: id returned from query, with which to retrieve doc; if doc doesn't exist, return None
87        '''
88        logging.info("Retrieving info for file, '%s'" %docPath)
89        doc = self.xmldb.executeQuery('doc("' + docPath + '")')
90       
91        if doc[1]['hits'] == 0:
92            logging.info("File does not exist in eXist DB")
93            return None
94        logging.info("Found file - returning result ID")
95        return doc[0]
96         
97
98    def getEXistFile(self, docPath):
99        '''
100        Use XQuery to retrieve the specified document from eXist
101        @param docPath: the path of the doc to retrieve
102        @return: contents of document if exists, None otherwise
103        '''
104        id = self._lookupEXistFile(docPath)
105       
106        if not id:
107            logging.info("No file found - nothing to retrieve")
108            return None
109       
110        logging.info("Found file - now retrieving content")
111        doc = self.xmldb.retrieve(id, 0)
112        return doc
113
114
115    def isNewEXistFile(self, docPath):
116        '''
117        Backup a file that exists in the eXist DB
118        @param docPath: path of file in eXist to backup
119        '''
120        logging.info("Checking if file, '%s', exists in eXist DB" %docPath)
121       
122        id = self._lookupEXistFile(docPath)
123
124        if id:
125            return False
126       
127        return True
128
129
130    def _addTimeStamp(self, fileName):
131        '''
132        Add timestamp to input filename
133        NB, this assumes there is a file type identifier at the end of the filename; if so, the datestamp
134        is included before this; if not it is just added at the end
135        '''
136        bits = fileName.rsplit(".", 1)
137        fileName = bits[0] + "_" + datetime.datetime.today().strftime("%Y-%m-%dT%H_%M_%S")
138       
139        if len(bits) > 1:
140            fileName += "." + bits[1]
141        return fileName
142
143
144    def backupEXistFile(self, collection, fileName):
145        '''
146        Backup a file that exists in the eXist DB
147        - NB, this really just creates a new file with the same contents in a
148        backup dir
149        @param collection: path of the collection to store the file in
150        @param fileName: name of file to add in eXist
151        @return: path to new backup file
152        '''
153        docPath = collection + fileName
154        logging.info("Backing up file, '%s', in eXist DB" %docPath)
155
156        logging.debug("Firstly, retrieve file contents from eXist")
157        doc = self.getEXistFile(docPath)
158        if not doc:
159            errorMessage = "Could not retrieve file contents (%s) to backup - exiting." %docPath
160            logging.error(errorMessage)
161            raise SystemError(errorMessage)
162       
163        # Now adjust the collection to map to the backup dir
164        collection = collection.replace(ec.BASE_COLLECTION_PATH, ec.BACKUP_COLLECTION_PATH)
165        collection = collection.replace(ec.NDG_A_COLLECTION_PATH, ec.NDG_A_COLLECTION_PATH_BACKUP)
166       
167        # add timestamp to filename
168        fileName = self._addTimeStamp(fileName)
169        docPath = collection + fileName
170
171        logging.debug("Now creating backup file, '%s'" %fileName)
172        self.createEXistFile(doc, collection, fileName)
173       
174        logging.info("File backed up in eXist")
175        return docPath
176
177
178    def createEXistFile(self, xml, collection, fileName):
179        '''
180        Add the input file to the eXist DB
181        @param xml: contents of xml file to create in eXist
182        @param collection: path of the collection to store the file in
183        @param fileName: name of file to add in eXist
184        @return: True, if file created successfully
185        '''
186        logging.info("Adding file, '%s' to eXist DB collection, '%s'" %(fileName, collection))
187        logging.debug("data: %s" %xml)
188
189        # create the collection, in case it doesn't already exist - NB, this won't overwrite anything
190        self.createCollections([collection])
191        status = self.xmldb.storeXML(xml, collection + "/" + fileName, overwrite=1)   
192        if not status:
193            errorMessage = "Command to create file in eXist did not complete successfully - exiting"
194            logging.error(errorMessage)
195            raise SystemError(errorMessage)
196       
197        logging.info("File added to eXist")
198        return True
199
200
201    def deleteEXistFile(self, docPath):
202        '''
203        Delete the input file from eXist DB
204        @param docPath: path of document to delete
205        @return: True, if file deleted successfully
206        '''
207        logging.info("Deleting file, '%s', from eXist DB" %docPath)
208
209        status = self.xmldb.removeDoc(docPath)   
210        if not status:
211            errorMessage = "Command to delete file in eXist did not complete successfully - exiting"
212            logging.error(errorMessage)
213            raise SystemError(errorMessage)
214       
215        logging.info("File deleted from eXist")
216        return True
217
218
219    def createOrUpdateEXistFile(self, xml, collection, fileName):
220        '''
221        Check if a file already exists in eXist; if it does, run an
222        update (which will backup the existing file), otherwise create
223        the file in eXist
224        @param xml: contents of xml file to create/update in eXist
225        @param collection: path of the collection to store the file in
226        @param fileName: name of file to add in eXist
227        '''
228        logging.info("Creating or updating file in eXist...")
229        if not self.isNewEXistFile(collection + fileName):
230            self.backupEXistFile(collection, fileName)
231           
232        self.createEXistFile(xml, collection, fileName)
233
234           
235    def createAtomInExist(self, atom):
236        logging.info("Creating atom in eXist")
237        eXistCollection = atom.getEXistCollectionPath()
238       
239        # ensure this collection exists - otherwise an exception will be thrown
240        self.createCollections([eXistCollection])
241        self.createOrUpdateEXistFile(atom.toPrettyXML(), \
242                                     eXistCollection, atom.atomName)
243        logging.info("Atom created in eXist")
Note: See TracBrowser for help on using the repository browser.