source: exist/trunk/python/ndgUtils/eXistInterface.py @ 4529

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/exist/trunk/python/ndgUtils/eXistInterface.py@4529
Revision 4529, 8.0 KB checked in by cbyrom, 12 years ago (diff)

Improve reading in of password file data.

Line 
1from eXistConnector import *
2from ndgXqueries import ndgXqueries
3import xmlHandler2, logging
4
5class ndg_eXist(eXistConnector):
6    ''' Adds ndg methods to a "standard" exist Connector '''
7   
8    ATOM_TARGET = 'Atom'
9    DEFAULT_ALL_VAL = 'All' # value used when specifying '*' in searches
10
11    def __init__(self,db='glue.badc.rl.ac.uk',passwordFile='passwords.txt'):
12        logging.debug("Initialising connection to eXist DB ('%s')" %db)
13        try:
14            f=file(passwordFile,'r')
15        except IOError,e:
16            raise IOError('%s [looking for %s in %s]'%(e,passwordFile,os.getcwd()))
17           
18        pw={}
19        for line in f.readlines():
20            line = line.strip()
21            if not line:
22                continue
23            host,userid,password=line.split(' ')
24            pw[host]=(userid,password)
25        f.close()
26        if db not in pw:
27            raise ValueError('Unable to find eXist password for repository [%s]'%db)
28        eXistConstants = InstanceObject(host=db,
29                                userid=pw[db][0],
30                                password=pw[db][1],
31                                base_path="/exist/servlet",
32                                xmlrpc_base_path="/exist/xmlrpc",
33                                port=8080)
34       
35        eXistConnector.__init__(self,eXistConstants)
36        self.ids={}
37        logging.debug("Connection initialised")
38       
39       
40    def __buildquery(self,query,target=None):
41        '''Create an NDG full text query '''
42        if target is not None:
43            s='''let $hits := collection('/db/%s')//root()[. &= '%s'] ;
44                 for $i in $hits
45                    return <document>{document-uri($i)}</document>'''%(target,query)
46        else: s="/*[. &='%s']"%query
47
48        return s#xmlrpclib.Binary(s)
49
50    def __buildParamSearch(self,param,value,target):
51        s="for $x in document()//%s where $x[.%s &= '%s'] return $x"%(target,param,value)
52        return s
53
54    def full_text(self,query,target=None):
55        ''' Carry out a full text search within the "target" collection '''
56        id,summary=self.executeQuery(self.__buildquery(query,target))
57        self.ids[id]=0
58        return id,summary
59
60    def retrieveNext(self,id,pos=None):
61        ''' Takes a sessionID from an existing query and gets the next document '''
62        if pos is not None: self.ids[id]=pos
63        try:
64            r=self.retrieve(id, self.ids[id])
65            self.ids[id]+=1
66            return r
67        except xmlrpclib.Fault:
68            return None
69        except KeyError:
70            return None
71   
72    def sessionRelease(self,id):
73        ''' Releases a session and removes the position counter '''
74        try:
75            self.release(id)
76            del self.ids[id]
77            return 1
78        except:
79            return 0
80   
81    def chunkedFullText(self,query,start=1,number=10,target='DIF'):
82        ''' Execute a chunked full text query and return the result
83        set '''
84        return self.executeChunkedQuery(self.__buildquery(query,target),start,number,params={})
85   
86   
87    def getDIF(self,entryID):
88        ''' Get a specific DIF document from a repository by using the entryID '''
89        xq='''declare default element namespace 'http://gcmd.gsfc.nasa.gov/Aboutus/xml/dif/'; \
90            for $DE in collection()/DIF[Entry_ID='%s'] return $DE'''%entryID
91        xquery='''for $DE in collection('/db/testdif1')/DIF[Entry_ID='%s'] return $DE'''%entryID
92        id,summary=self.executeQuery(xq)#xquery)
93        if summary['hits']==1:
94            r=self.retrieve(id,0,{})
95            self.sessionRelease(id)
96        else:
97            r=summary['hits']
98        return r
99       
100    def search(self,term,start=1,howmany=20, \
101               target=None,scope=None,bbox=None, \
102               dateRange=None,geoSearchType=None, \
103               providerID=None, atomTypeID=None):
104        ''' Provides a search interface that mimics the WSDL search interface, except that
105        the target used is the exist collection name, and scope, bbox and dateRange are ignored,
106        and a python summary object is returned '''
107        #select the right query according to the docType
108       
109        if target == self.ATOM_TARGET:
110            xquery = self.__createAtomSearch(providerID, atomTypeID, term)
111        else:
112            xqName={'ndg_B_metadata':'molesSummary',\
113                'NumSim':'numsimSummary'}[target]
114            xquery=ndgXqueries()[xqName]
115            xquery=xquery.replace('SEARCHSTRING',term)
116       
117        logging.info("Executing xquery search")
118        logging.debug(" - query: '%s'" %xquery)
119        r=self.executeChunkedQuery(str(xquery),start,howmany)
120        logging.info("Search complete - processing results")
121        x=xmlHandler2.xmlHandler(str(r),string=1)
122        h=x.tree.get('hits')
123        self.results=[]
124        self.serverSessionID=''
125        if h is None:
126            self.hits=0
127            self.start=0
128            self.howmany=0
129            self.error=['No results for [%s]'%term,]
130        else:
131            self.hits=int(h)
132            self.error=None
133            self.start=int(x.tree.get('start'))
134            self.howmany=int(x.tree.get('count'))
135            slist=x.tree.findall('summary')
136            for s in slist:
137                t=edict(id=s.find('id').text,name=s.find('name').text,\
138                        type=s.find('type').text)
139                # add extra stuff for atom search (NB, this could be added to all
140                # but am unsure of implications elsewhere atm
141                if target == self.ATOM_TARGET:
142                    for key in ['providerID', 'created', 'href', 'subtype']:
143                        t[key] = s.find(key).text
144
145                        # adjust href to point to atom editor instead of atom view
146                        if key == 'href' and t[key]:
147                            t[key] = t[key].replace('view', 'editAtom')
148                           
149                        if key == 'subtype':
150                            t[key] = t[key]
151                   
152                self.results.append(t)
153        return self.results
154   
155
156    def __createAtomSearch(self, providerID, atomTypeID, term):
157        '''
158        Create a valid xquery search for searching atoms
159        '''
160        logging.debug("Creating xquery for searching atoms")
161        logging.debug("providerID: '%s', atomTypeID: '%s', term: '%s'" 
162                      %(providerID, atomTypeID, term))
163        xquery = "declare namespace moles='http://ndg.nerc.ac.uk/schema/moles2beta';\n" + \
164            "declare namespace atom='http://www.w3.org/2005/Atom';\n" + \
165            "for $DE in collection('/db/atoms')//root()["
166
167        # only add the required search clauses - NB, these increase the search time
168        # significantly, so avoid unless really required
169        whereClause = []
170        if term:
171            whereClause.append(". &= '" + term + "'")
172       
173        if providerID and providerID != self.DEFAULT_ALL_VAL:
174            whereClause.append("atom:entry/moles:entity/moles:molesISO/moles:providerID = '" + providerID + "'")
175       
176        if atomTypeID and atomTypeID != self.DEFAULT_ALL_VAL:
177            whereClause.append("atom:entry/atom:category/@label = '" + atomTypeID + "'")
178           
179        if not whereClause:
180            whereClause.append(".")
181       
182        for i, clause in enumerate(whereClause):
183            if i > 0:
184                xquery += " and "
185            xquery += clause
186           
187        xquery += "] return <summary> \
188<id>{$DE/atom:entry/atom:id/text()}</id> \
189<name>{$DE/atom:entry/atom:title/text()}</name> \
190<type>{string($DE/atom:entry/atom:category[@term='ATOM_TYPE']/@scheme)}</type> \
191<subtype>{string($DE/atom:entry/atom:category[@term='ATOM_SUBTYPE']/@scheme)}</subtype> \
192<href>{string($DE/atom:entry/atom:link[@rel='self']/@href)}</href> \
193<providerID>{$DE/atom:entry/moles:entity/moles:molesISO/moles:providerID/text()}</providerID> \
194<created>{$DE/atom:entry/moles:entity/moles:molesISO/moles:created/text()}</created> \
195</summary>"
196
197        logging.debug("Created xquery: '%s'" %xquery)
198        return xquery
Note: See TracBrowser for help on using the repository browser.