source: TI05-delivery/ows_framework/trunk/ows_server/ows_server/lib/ndgInterface.py @ 3833

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI05-delivery/ows_framework/trunk/ows_server/ows_server/lib/ndgInterface.py@3833
Revision 3833, 8.1 KB checked in by pjkersha, 12 years ago (diff)

Fix calls to ndgRetrieve so that the discovery flag is set explicitly from the 'standalone' config option rather than defaulting to 1. Prior to this fix browse queries were breaking.

Line 
1# Copyright (C) 2007 STFC & NERC (Science and Technology Facilities Council).
2# This software may be distributed under the terms of the
3# Q Public License, version 1.0 or later.
4# http://ndg.nerc.ac.uk/public_docs/QPublic_license.txt
5"""
6Manages interface to NDG documents and data, including caching
7"""
8
9from cache import Cache
10import os, tempfile
11import csml
12try:
13    import cdms2 as cdms
14except:
15    import cdms
16from ndgUtils import ndgRetrieve, ndgObject, xmlHandler2
17from pylons import request,session
18import logging
19logger = logging.getLogger('ndgInterface')
20from ows_server.models.ndgSecurity import HandleSecurity
21
22class CDMSEntry(object):
23    """
24    A reference to a CDMS file that will delete the file when it is
25    garbage collected.
26
27    Instances of this class are used as Cache entry values.  When entries are
28    automatically removed from the cache the CDMSEntry object will be
29    garbage collected unless it is being accessed by another thread.
30
31    """
32
33    __slots__ = ['_f', 'var']
34   
35    def __init__(self, filename, varname):
36        logger.info('Caching file variable %s in %s' % (varname, filename))
37        self._f = cdms.open(filename)
38        self.var = self._f[varname]
39    def __del__(self):
40        filename = self._f.id
41        logger.info('Removing file %s' % filename)
42        self._f.close()
43        os.remove(filename)
44 
45
46class CSMLExtractCache(Cache):
47   
48    def __init__(self, cache_dir, max_size=0):
49        super(CSMLExtractCache, self).__init__(max_size)
50        self._cache_dir = cache_dir
51
52    def _extract(self, feature, sel):
53        (fd, filename) = tempfile.mkstemp('.nc', 'csml_wxs_', self._cache_dir)
54        os.close(fd)
55        (outputdir, ncname) = os.path.split(filename)
56
57        # Workarround until ticket:778 (TestExtractAll) is fixed
58        sel.update(longitude=(-180, 180), latitude=(-90, 90))
59
60        feature.subsetToGridSeries(ncname=ncname, outputdir=outputdir, **sel)
61
62        return filename
63   
64    def key(self, name):
65        """
66        Cache provides this method to map externally visible entry names
67        to internal keys.  We use it here to turn selectors into hashable
68        values.
69
70        """
71        (feature, sel) = name
72       
73        return (feature.id, tuple(sorted(sel.items())))
74
75    def build(self, key, name, opened, entry):
76        (feature, sel) = name
77        filename = self._extract(feature, sel)
78
79        return CDMSEntry(filename, feature.name.CONTENT)
80
81    def __getitem__(self, name):
82        """
83        Returns the opened CDMS object.
84
85        """
86        return super(CSMLExtractCache, self).__getitem__(name).var
87
88class ndgInterface:
89   
90    def __init__(self):
91        ''' Instantiate with three level cache:
92                - a file cache
93                - a xmlhandler object cache, and
94                - a parsed CSML object cache.'''
95               
96        self.CSMLDataCache=CSMLExtractCache(
97                request.environ['paste.config']['app_conf']['tmp_dir'],max_size=10)
98        self.CSMLDocCache=Cache(max_size=10)
99        self.XMLHCache=Cache(max_size=10)
100       
101
102    def GetXML(self,uri,outputSchema=''):
103        ''' This method provides a secure interface to the server
104        document cache and a remote NDG exist. It is assumed that
105        the local filesystem is protected in that you can't get to
106        files except via the CSML api '''
107        #    Note that this method should not be used to obtain
108        #unsecured discovery documents, these are called directly
109        #in the retrieve controller!
110
111        # Fix call to ndgRetrieve so that it sets the discovery flag explicitly
112        # rather than defaulting to 1
113        #
114        # PJK 01/05/2008
115        standaloneDiscovery = \
116                request.environ['ndgConfig'].config.getboolean('DISCOVERY',
117                                                               'standalone')
118       
119        try:
120            ndgO=ndgObject(uri)
121            localFile=0
122        except ValueError:
123            ''' It's a local file not an ndg identifier '''
124            ndg0=uri
125            localFile=1
126       
127        if 'ndgCleared' in session:
128            cleared=session['ndgCleared']
129        else:
130            cleared=None
131       
132        if outputSchema:
133            #bypass the cache ...
134            status,xmlh=ndgRetrieve(ndgO,
135                                    request.environ['ndgConfig'],
136                                    logger,
137                                    outputSchema,
138                                    discovery=standaloneDiscovery)
139        else:
140            try:
141                xmlh=self.XMLHCache[uri]
142                status=1
143                logging.info('XMLH Cache hit for [%s]'%uri)
144            except:
145                logging.info('XMLH Cache miss for [%s]'%uri)
146                if localFile:
147                    status,xmlH=self.__getLocal(uri)
148                else:   
149                    status,xmlh=ndgRetrieve(ndgO,
150                                            request.environ['ndgConfig'],
151                                            logger,
152                                            outputSchema,
153                                            discovery=standaloneDiscovery)
154                if status: self.XMLHCache[uri]=xmlh
155           
156        if not status: return status,xmlh
157       
158        # convert doc to an XML tree
159        xmlh=xmlHandler2.xmlHandler(xmlh,string=1)
160       
161        # valid values of the return objects SHOULD BE
162        #   ok:         status=1, xmlh=an xml handler instance.
163        #   exceptions, status=0, xmlh='Exception(e)'
164       
165        status,xmlh=self.__GateKeep(ndgO,xmlh)
166        if status:
167            if cleared is None:
168                session['ndgCleared']=[uri]
169            else:
170                session['ndgCleared'].append(uri)
171            session.save()
172       
173        return status,xmlh
174           
175    def GetParsedCSML(self,uri):
176       
177        ''' This method gets a parsed CSML object corresponding to the URI '''
178       
179        # do we need an xml handler instance to test the security?
180        if 'ndgCleared' not in session:
181            status,xmlh=self.GetXML(uri)
182        else: 
183            if uri not in session['ndgCleared']: 
184                status,xmlh=self.GetXML(uri)
185            else: status=1
186        if not status: return status,xmlh
187       
188        try:
189            d=self.CSMLDocCache[uri]
190            logging.info('CSML Cache hit for [%s]'%uri)
191        except:
192            logging.info('CSML Cache miss for [%s]'%uri)
193            status,xmlh=self.GetXML(uri)
194            if not status: return status,xmlh   
195            d=csml.parser.Dataset()
196            d.parseElemTree(xmlh.tree)
197            self.CSMLDocCache[uri]=d
198        status=1
199        return status,d
200       
201    def __GateKeep(self,uri,x):
202        ''' This is the NDG gatekeeper '''
203        if 'ndgSec' in session:
204            securityTokens=session['ndgSec']
205        else:
206            securityTokens=None
207       
208        if uri.schema=='DIF':
209            pass # no access control
210        elif uri.schema =='NDG-B0':
211            #cred=x.find('dgSecurityCondition/simpleCondition')
212            #if cred:
213            #    return 0,'<p> Access Control: <br/>[<![CDAT[%s]]> </p>'
214            pass
215        elif uri.schema =='NDG-B1':
216            pass # for the moment
217        elif uri.schema =='NDG-A0':
218            if True:  # use this for turning security on and off during testing
219                s=x.tree.find('{http://ndg.nerc.ac.uk/csml}AccessControlPolicy/{http://ndg.nerc.ac.uk/csml}dgSecurityCondition')
220                if s is not None:
221                    status,message=HandleSecurity(uri,s,securityTokens)
222                    if not status: return 0,'<p> Access Denied for %s </p><p>%s</p>'%(uri,message)
223        return 1,x
224               
225    def __getLocal(self,uri):
226        ''' Returns a local csml file (used for testing) '''
227        csml_dir = request.environ['paste.config']['app_conf']['csml_dir']
228        path = os.path.join(csml_dir, file)
229        if os.path.exists(path+'.csml'):
230            f = path+'.csml'
231        elif os.path.exists(path+'.xml'):
232            f = path +'.xml'
233        else:
234            return 0, '<p>Cannot find CSML file %s</p>' % file
235        r=f.read()
236        return 1,r     
237       
238
239
240interface=ndgInterface()
Note: See TracBrowser for help on using the repository browser.