source: TI05-delivery/ows_framework/trunk/ows_server/ows_server/models/eXistInterface.py @ 2626

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI05-delivery/ows_framework/trunk/ows_server/ows_server/models/eXistInterface.py@2760
Revision 2626, 6.7 KB checked in by lawrence, 13 years ago (diff)

Interim checkin supports "dummy" logging in and out,
provided pages inherit from ndgPage.kid

Line 
1# Code inspired by example on eXist website.
2import urllib2, base64, urllib, urlparse, httplib, xmlrpclib, types, os
3
4class   InstanceObject(object):
5    def __init__(self, **kw):
6        self.dict={}
7        self.dict.update(kw)
8    def __getattr__(self,arg):
9        return self.dict[arg]
10
11class  eXist_Connector(object):
12    """Access class for eXist"""
13    def __init__(self,constants=None):
14        ''' Instantiates the eXist connector using supplied constants '''
15        if constants is None: raise 'NoExistConstants'
16        authinfo = urllib2.HTTPPasswordMgrWithDefaultRealm()
17        authinfo.add_password(None,
18                                  constants.host,
19                                  constants.userid,
20                                  constants.password)
21        authHandler = urllib2.HTTPBasicAuthHandler(authinfo)
22        opener = urllib2.build_opener(authHandler)
23        s = constants.userid+':'+constants.password
24        z = base64.encodestring(s)[:-1] # strip trailing 12
25        opener.addheaders.append(('Authorization', 'Basic %s' % z))
26        self.http_headers = {'Authorization':'Basic %s' % z}
27        self.opener = opener
28        # also create an xmlrpc Server object
29       
30        xmlrpc_uri = '%s%s:%s@%s:%d%s' % ( 
31                                            'http://',
32                                            constants.userid,
33                                            constants.password,
34                                            constants.host,
35                                            constants.port,
36                                            constants.xmlrpc_base_path
37                                        )
38        self.xmlrpc = xmlrpclib.Server(xmlrpc_uri)
39
40    def executeQuery(self, xquery, params={}):
41        '''Execute an xquery string, return session and summary information'''
42        xquery=xmlrpclib.Binary(xquery)
43        id = self.xmlrpc.executeQuery(xquery, params)
44        summary = self.xmlrpc.querySummary(id)
45        return id,summary
46
47    def release(self,id):
48        ''' Release an executeQuery session '''
49        self.xmlrpc.releaseQueryResult(id)
50       
51    def retrieve(self,id,pos,params={}):
52        ''' Retrieve a specific document from an executeQuery result set '''
53        return self.xmlrpc.retrieve(id,pos,params).data
54 
55    def executeChunkedQuery(self,xquery,start,number,params={}):
56        ''' Execute a query, return a specific part of the result set, and
57        dump the session automagically '''
58        xquery=xmlrpclib.Binary(xquery)
59        r=self.xmlrpc.query(xquery,number,start,params)
60        return r
61   
62    def querySummary(self,id):
63        ''' Returns a summary of query results for the result-set referenced by id (which was returned by a previous query '''
64        return self.xmlrpc.querySummary(id)
65   
66    def getHits(self,id):
67        ''' Return the number of hits associated with the query that created session id '''
68        return self.xmlrpc.getHits(id)
69   
70    def getDoc(self,collectionName,documentName):
71        ''' Lightweight interface to the getDocument method '''
72        name='%s/%s'%(collectionName,documentName)
73        r=self.xmlrpc.getDocumentAsString(name,{})
74        return r
75   
76# unfortunately it looks like the exist server doesn't support introspection
77#    def showMethods(self):
78#        print self.xmlrpc.system.listMethods()
79       
80class ndg_eXist(eXist_Connector):
81    ''' Adds ndg methods to a "standard" exist Connector '''
82    def __init__(self,db='glue.badc.rl.ac.uk',passwordFile='passwords.txt'):
83        try:
84            f=file(passwordFile,'r')
85        except IOError,e:
86            raise IOError('%s [looking for %s in %s]'%(e,passwordFile,os.getcwd()))
87           
88        pw={}
89        for line in f.readlines():
90            host,userid,password=line.strip().split(' ')
91            pw[host]=(userid,password)
92        if db not in pw:
93            raise ValueError('Unable to find eXist password for repository [%s]'%db)
94        eXistConstants = InstanceObject(host=db,
95                                userid=pw[db][0],
96                                password=pw[db][1],
97                                base_path="/exist/servlet",
98                                xmlrpc_base_path="/exist/xmlrpc",
99                                port=8080)
100       
101        eXist_Connector.__init__(self,eXistConstants)
102        self.ids={}
103       
104    def __buildquery(self,query,target=None):
105        '''Create an NDG full text query '''
106        if target is not None:
107            s="//%s[. &='%s']"%(target,query)
108        else: s="/*[. &='%s']"%query
109        return s#xmlrpclib.Binary(s)
110
111    def __buildParamSearch(self,param,value,target):
112        s="for $x in document()//%s where $x[.%s &= '%s'] return $x"%(target,param,value)
113        return s
114
115    def full_text(self,query,target=None):
116        ''' Carry out a full text search within the "target" collection '''
117        id,summary=self.executeQuery(self.__buildquery(query,target))
118        self.ids[id]=0
119        return id,summary
120
121    def retrieveNext(self,id,pos=None):
122        ''' Takes a sessionID from an existing query and gets the next document '''
123        if pos is not None: self.ids[id]=pos
124        try:
125            r=self.retrieve(id, self.ids[id])
126            self.ids[id]+=1
127            return r
128        except xmlrpclib.Fault:
129            return None
130        except KeyError:
131            return None
132   
133    def sessionRelease(self,id):
134        ''' Releases a session and removes the position counter '''
135        try:
136            self.release(id)
137            del self.ids[id]
138            return 1
139        except:
140            return 0
141   
142    def chunkedFullText(self,query,start=1,number=10,target='DIF'):
143        ''' Execute a chunked full text query and return the result
144        set '''
145        return self.executeChunkedQuery(self.__buildquery(query,target),start,number,params={})
146   
147   
148    def getDIF(self,entryID):
149        ''' Get a specific DIF document from a repository by using the entryID '''
150        xq='''for $DE in collection()/DIF[Entry_ID='%s'] return $DE'''%entryID
151        xquery='''for $DE in collection('/db/testdif1')/DIF[Entry_ID='%s'] return $DE'''%entryID
152        id,summary=self.executeQuery(xq)#xquery)
153        if summary['hits']==1:
154            r=self.retrieve(id,0,{})
155            self.sessionRelease(id)
156        else:
157            r=summary['hits']
158        return r
159       
160   
161import unittest
162
163class TestCase(unittest.TestCase):
164   
165    def testFullText(self):
166           
167        ''' Exercises some of the methods based on something we hope might exist in the database '''
168       
169        existDB=ndg_eXist(db='glue.badc.rl.ac.uk')
170        id,summary=existDB.full_text('neodc')
171       
172        r=existDB.retrieveNext(id)
173        d=summary['documents'][0][0]
174        print d
175        doc=existDB.getDoc('/db/discovery/moles',d)
176       
177        ok=existDB.sessionRelease(id)
178        self.assertEqual(1,ok)
179
180if __name__=="__main__":
181    unittest.main()
182 
Note: See TracBrowser for help on using the repository browser.