source: MILK/trunk/milk_server/milk_server/controllers/browse/retrieve.py @ 5750

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/MILK/trunk/milk_server/milk_server/controllers/browse/retrieve.py@5750
Revision 5750, 8.9 KB checked in by sdonegan, 11 years ago (diff)

updated to add xml header and convert to ascii from unicode so can work in mod_wsgi buildout

Line 
1'''
2 Class representing pylons controller for the retrieval of metadata records - and
3 records associated with these
4 
5 @author: B Lawrence?, C Byrom, Tessella Sep 2008
6'''
7import logging
8from paste.request import parse_querystring
9from xml.parsers.expat import ExpatError
10from milk_server.lib.base import *
11from milk_server.models.ndgdoc import NDGDoc
12from milk_server.controllers.trackback.trackback import TrackbackController
13from ndg.common.src.models.ndgObject import ndgObject
14from ndg.common.src.models.vocabtermdata import VocabTermData as VTD
15from ndg.common.src.clients.xmldb.eXist.searchclient import SearchClient
16
17class RetrieveController(BaseController):
18    '''
19    Provides the pylons controller for retrieving NDG documents. The simple model
20    is now that an attempt to retrieve/uri will parse the uri, read the config file,
21    and if the local server name is not the same as the uri server name, attempt
22    to retrieve the doc remotely.
23    '''
24    def __before__(self):
25        '''
26        Before anything is done, ensure the browse mode is enabled
27        - unless we're retrieving associated data then we can do this regardless
28        of the mode of operation
29        '''
30        if not g.browseEnabled and not g.atomEditorEnabled:# request.path_info.startswith('/viewAssociatedData'):
31            logging.info("Browse mode not enabled - redirect to default")
32            return h.redirect_to(h.url_for('default'))
33
34
35    def home(self):
36        '''
37        Display the browse home page
38        '''
39        logging.debug("Displaying browse home page")
40        c.title = "Browse"
41       
42        c.doc = "Use the search box above to find data centre metadata records" 
43        return render('genshi', 'browse/home')
44
45   
46    def __setup(self, uri):
47        ''' Common setup stuff for all the actions on this controller '''
48        logging.info("Setting up RetrieveController")
49        self.cf = request.environ['ndgConfig']
50        try:
51            self.uri=ndgObject(uri, config=self.cf)
52        except ValueError,e:
53            return e
54
55        self.inputs=dict(parse_querystring(request.environ))
56
57        # NB: we could have two types of query string argument:
58        #   format= (raw,html) and
59        #   outputSchema=(original, someSchema)
60        self.format=''
61        if 'format' in self.inputs: 
62            self.format = self.inputs['format']
63        self.outputSchema = ''
64        if 'outputSchema' in self.inputs: 
65            self.outputSchema = self.inputs['outputSchema']
66
67        self.ndgDoc = NDGDoc(ndgURI = uri, config = self.cf)
68                             
69        logging.info("RetrieveController set up")
70        return 0
71
72       
73    def index(self,uri):
74        '''
75        Returns the document unadorned in anyway, i.e. the raw xml
76        '''
77        status=self.__setup(uri)
78        if status:
79            c.xml='<p>%s</p>'%status
80            response.status_code = 400
81            return render('error')
82       
83        self.ndgDoc.setupDocumentModel(outputSchema = self.outputSchema,
84                                       format = 'xml')
85
86        if self.ndgDoc.status:
87            response.headers['Content-Type'] = 'application/xml'
88       
89            #When using this with mod_wsgi apps need to explicitly add the xml declaration lost during ingestion as well
90            #as encode as string as mod_wsgi does not like the unicode!!  SJD 22/0/09
91            xmlReturn = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + self.ndgDoc.xmlString
92            response.write(xmlReturn.encode('ascii','ignore'))
93           
94        else:
95            # the error templates should be set up already if there's an error
96            return self.__renderModel(self.ndgDoc)
97
98
99    def viewAssociatedData(self, type, uri):
100        '''
101        Get the specified data associated with the uri
102        @param type: type of associated data to lookup - currently VTD.DEPLOYMENT_TERM
103        or VTD.DE_TERM
104        @param uri: valid ndg uri
105        @return rendered genshi deployments template
106        '''
107        logging.info("Getting %s data for '%s'" %(type, uri))
108        status=self.__setup(uri)
109        if status:
110            c.xml='<p>%s</p>'%status
111            response.status_code = 400
112            return render('error')
113
114        try:
115            # NB, we should have stored the current atom data - so look this up now
116            atom = session.get('currentAtom')
117            if atom:
118                c.atom = atom
119                self.ndgDoc.templateType = "genshi"
120                self.ndgDoc.htmlCode = 200
121            else:
122               
123                self.ndgDoc.setupDocumentModel(outputSchema = self.outputSchema,
124                                               format = self.format)
125                c.atom = self.ndgDoc.docModel
126           
127            # NB, there are two routes through here - if we're viewing a data entity,
128            # the deployment links are available directly from the atom; if not we
129            # need to look them up
130            lookupIndirectReferences = True
131            if c.atom.isDE():
132                lookupIndirectReferences = False
133           
134            searchClient = SearchClient(dbHostName = self.cf.get('NDG_EXIST','local'),
135                                        configFileName = self.cf.get('NDG_EXIST','passwordFile'))
136           
137            c.atom.lookupAssociatedData(type, searchClient, 
138                                        lookupIndirectReferences = lookupIndirectReferences)
139
140            self.ndgDoc.renderTemplate = 'atom_editor/deployments_data'
141            if type == VTD.DE_TERM:
142                self.ndgDoc.renderTemplate = 'atom_editor/data_entities_data'
143
144            # store the atom to retain the looked up info
145            session['currentAtom'] = c.atom
146            session.save()
147               
148            logging.info("- %s data retrieved - now rendering" %type)
149
150            return self.__renderModel(self.ndgDoc)
151        except Exception, e:
152            c.xml = 'Unexpected error [%s] viewing [%s]'%(str(e), self.ndgDoc.ndgUri)
153            c.doc = ''
154            response.status_code = 400
155            logging.error(c.xml)
156            return render('error')
157           
158
159    def view(self, uri):
160        '''
161        Returns either an html marked up version of the xml, or a properly laid
162        out version of the document
163        '''
164        c.doc=None
165        # NB, this sets up self.uri as an ndgObject
166        status=self.__setup(uri)
167        if status:
168            c.xml='<p>%s</p>'%status
169            response.status_code = 400
170            return render('error')
171       
172        c.tab = 'Details'
173        c.title='Viewing [%s]'%self.uri
174       
175        self.ndgDoc.setupDocumentModel(outputSchema = self.outputSchema,
176                                       format = self.format)
177
178        c.xml = self.ndgDoc.xmlString
179
180        if self.format=='raw':
181            response.headers['Content-Type'] = 'application/xml'
182            return response.write(c.xml)
183
184        c.name = self.ndgDoc.name
185        c.xmlh = self.ndgDoc.xmlh    # xml in object form - NB, only used by NumSim docs
186        c.doc = self.ndgDoc.docModel
187
188        if self.ndgDoc.isAtom:
189            c.atom = self.ndgDoc.docModel
190           
191            # store the atom for easy re-use by asynch calls
192            # - primarily for the viewAssociatedData() method here
193            session['currentAtom'] = c.atom
194            session.save()
195               
196        # set up trackback rdf tag
197        c.tbinfo = TrackbackController().getTrackBackInfo(uri, self.ndgDoc.name)
198
199        needed=0
200        if 'lastViewed' not in session: 
201            needed=1
202           
203        session['lastViewed']=h.current_url()
204        session.save()
205
206        # only add the details tab data to the panel tab, if it is not already there
207        if needed: 
208            c.pageTabs.append(('Details',session['lastViewed']))
209
210        return self.__renderModel(self.ndgDoc)
211
212
213    def __renderModel(self, model):
214        '''
215        Render the requested document model - or handle errors appropriately
216        @param model: doc model - of type NDGDoc
217        '''
218        response.status_code = model.htmlCode
219        try:
220            logging.debug("Rendering output from data model")
221            out = render(model.templateType, model.renderTemplate)
222           
223            # if in atom editor mode, replace any browse links with to links to editor
224            if g.atomEditorEnabled:
225                out = out.replace(VTD.BROWSE_SERVER_URL, g.server)
226           
227            logging.debug("- returning rendered data model")
228            return out
229       
230        except ExpatError, e:
231            c.xml = 'XML content is not well formed'
232            c.doc = model.xmlString
233            response.status_code = 400
234            logging.error("Error retrieving [%s]: %s" % (model.ndgUri, e))
235            return render('error')
236
237        except Exception, e:
238            c.xml = 'Unexpected error [%s] viewing [%s]'%(str(e), model.ndgUri)
239            c.doc = ''
240            response.status_code = 400
241            logging.error(c.xml)
242            return render('error')
243       
244
Note: See TracBrowser for help on using the repository browser.