1 | # Code inspired by example on eXist website. |
---|
2 | import urllib2, base64, urllib, urlparse, httplib, xmlrpclib, types, os, logging |
---|
3 | |
---|
4 | class 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 | def __str__(self): |
---|
11 | return 'InstanceObject: %s '%self.dict |
---|
12 | |
---|
13 | class edict(dict): |
---|
14 | '''An extended dictionary which allows one to set and get values |
---|
15 | as attributes (kudos Joe Gregorio's 1812) |
---|
16 | The extended part allows you to get and set values as attributes. |
---|
17 | That is, |
---|
18 | d.fred |
---|
19 | is the same as |
---|
20 | d['fred'] |
---|
21 | ''' |
---|
22 | def __init__(self,**kw): |
---|
23 | for a in kw: |
---|
24 | self[a]=kw[a] |
---|
25 | def __getattr__(self, key): |
---|
26 | try: |
---|
27 | return self.__dict__[key] |
---|
28 | except KeyError: |
---|
29 | pass |
---|
30 | try: |
---|
31 | assert not key.startswith('_') |
---|
32 | return self.__getitem__(key) |
---|
33 | except: |
---|
34 | raise AttributeError, "object has no attribute '%s'" % key |
---|
35 | def __setattr__(self, key, value): |
---|
36 | if key.startswith('_'): |
---|
37 | self.__dict__[key] = value |
---|
38 | else: |
---|
39 | return self.__setitem__(key, value) |
---|
40 | |
---|
41 | |
---|
42 | class eXistConnector(object): |
---|
43 | |
---|
44 | # default collections for the various file types in eXist |
---|
45 | BASE_COLLECTION_PATH = "/db/atoms/" |
---|
46 | OLD_COLLECTION_PATH = "old/" |
---|
47 | PUBLISHED_COLLECTION_PATH = "Published/" |
---|
48 | SMALL_P_PUBLISHED_COLLECTION_PATH = "published/" |
---|
49 | WORKING_COLLECTION_PATH = "working/" |
---|
50 | BACKUP_COLLECTION_PATH = "/db/atoms_backup/" |
---|
51 | GRANULE_COLLECTION_PATH = "data_granules/" |
---|
52 | DEPLOYMENT_COLLECTION_PATH = "deployment_data/" |
---|
53 | DEPLOYMENTS_COLLECTION_PATH = "deployments/" |
---|
54 | DE_COLLECTION_PATH = "data_entities/" |
---|
55 | NDG_A_COLLECTION_PATH = "/db/ndg_A_metadata/" |
---|
56 | NDG_A_COLLECTION_PATH_BACKUP = "/db/ndg_A_metadata_backup/" |
---|
57 | |
---|
58 | """Access class for eXist""" |
---|
59 | def __init__(self,constants=None): |
---|
60 | ''' Instantiates the eXist connector using supplied constants ''' |
---|
61 | logging.debug("Setting up xmlrpc connection to eXist") |
---|
62 | if constants is None: raise 'NoExistConstants' |
---|
63 | logging.debug("Host: '%s', User: '%s'" %(constants.host, constants.userid)) |
---|
64 | authinfo = urllib2.HTTPPasswordMgrWithDefaultRealm() |
---|
65 | authinfo.add_password(None, |
---|
66 | constants.host, |
---|
67 | constants.userid, |
---|
68 | constants.password) |
---|
69 | authHandler = urllib2.HTTPBasicAuthHandler(authinfo) |
---|
70 | opener = urllib2.build_opener(authHandler) |
---|
71 | s = constants.userid+':'+constants.password |
---|
72 | z = base64.encodestring(s)[:-1] # strip trailing 12 |
---|
73 | opener.addheaders.append(('Authorization', 'Basic %s' % z)) |
---|
74 | self.http_headers = {'Authorization':'Basic %s' % z} |
---|
75 | self.opener = opener |
---|
76 | # also create an xmlrpc Server object |
---|
77 | |
---|
78 | xmlrpc_uri = '%s%s:%s@%s:%d%s' % ( |
---|
79 | 'http://', |
---|
80 | constants.userid, |
---|
81 | constants.password, |
---|
82 | constants.host, |
---|
83 | constants.port, |
---|
84 | constants.xmlrpc_base_path |
---|
85 | ) |
---|
86 | self.xmlrpc = xmlrpclib.Server(xmlrpc_uri) |
---|
87 | logging.debug("xmlrpc connection set up") |
---|
88 | |
---|
89 | |
---|
90 | def executeQuery(self, xquery, params={}): |
---|
91 | '''Execute an xquery string, return session and summary information''' |
---|
92 | logging.debug("Executing xquery on eXist:\n%s" %xquery) |
---|
93 | xquery=xmlrpclib.Binary(str(xquery)) |
---|
94 | id = self.xmlrpc.executeQuery(xquery, params) |
---|
95 | summary = self.xmlrpc.querySummary(id) |
---|
96 | logging.debug("XQuery executed") |
---|
97 | return id,summary |
---|
98 | |
---|
99 | def release(self,id): |
---|
100 | ''' Release an executeQuery session ''' |
---|
101 | self.xmlrpc.releaseQueryResult(id) |
---|
102 | |
---|
103 | def retrieve(self,id,pos,params={}): |
---|
104 | ''' Retrieve a specific document from an executeQuery result set ''' |
---|
105 | logging.debug("Retrieving document from eXist...") |
---|
106 | xml = self.xmlrpc.retrieve(id,pos,params).data |
---|
107 | logging.debug("Document retrieved.") |
---|
108 | return xml |
---|
109 | |
---|
110 | def executeChunkedQuery(self,xquery,start,number,params={}): |
---|
111 | ''' Execute a query, return a specific part of the result set, and |
---|
112 | dump the session automagically ''' |
---|
113 | xquery=xmlrpclib.Binary(xquery) |
---|
114 | r=self.xmlrpc.query(xquery,number,start,params) |
---|
115 | return r |
---|
116 | |
---|
117 | def querySummary(self,id): |
---|
118 | ''' Returns a summary of query results for the result-set referenced by id (which was returned by a previous query ''' |
---|
119 | return self.xmlrpc.querySummary(id) |
---|
120 | |
---|
121 | def getHits(self,id): |
---|
122 | ''' Return the number of hits associated with the query that created session id ''' |
---|
123 | return self.xmlrpc.getHits(id) |
---|
124 | |
---|
125 | def getDoc(self,collectionName,documentName): |
---|
126 | ''' |
---|
127 | Lightweight interface to the getDocument method |
---|
128 | ''' |
---|
129 | # atoms have a more structured collection directory - as a result |
---|
130 | # AtomList.xq returns the full path to the listed docs - so avoid |
---|
131 | # concat'ing the collectionName for these |
---|
132 | if documentName.startswith(collectionName): |
---|
133 | name = documentName |
---|
134 | else: |
---|
135 | name='%s/%s'%(collectionName,documentName) |
---|
136 | r=self.xmlrpc.getDocumentAsString(name,{}) |
---|
137 | return r |
---|
138 | |
---|
139 | def removeCollection(self,collectionPath): |
---|
140 | ''' Remove a collection in the eXist database ''' |
---|
141 | r=self.xmlrpc.removeCollection(collectionPath) |
---|
142 | return r |
---|
143 | |
---|
144 | def removeDoc(self, docPath): |
---|
145 | ''' Remove a document from the eXist database ''' |
---|
146 | r=self.xmlrpc.remove(docPath) |
---|
147 | return r |
---|
148 | |
---|
149 | def createCollection(self,collectionPath): |
---|
150 | ''' Create a collection in the eXist database at collectionPath ''' |
---|
151 | logging.info("Creating collection: '%s'" %collectionPath) |
---|
152 | r=self.xmlrpc.createCollection(collectionPath) |
---|
153 | logging.info("Collection created") |
---|
154 | return r |
---|
155 | |
---|
156 | def storeXML(self,xml,path,overwrite=0): |
---|
157 | ''' Store some XML into the databse at path ''' |
---|
158 | return self.xmlrpc.parse(xml,path,overwrite) |
---|
159 | |
---|
160 | |
---|