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

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

fixing DescribeCoverage? response

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        try:
112            ndgO=ndgObject(uri)
113            localFile=0
114        except ValueError:
115            ''' It's a local file not an ndg identifier '''
116            ndg0=uri
117            localFile=1
118       
119        if 'ndgCleared' in session:
120            cleared=session['ndgCleared']
121        else:
122            cleared=None
123       
124        if outputSchema:
125            #bypass the cache ...
126            status,xmlh=ndgRetrieve(ndgO,request.environ['ndgConfig'],logger,outputSchema)
127        else:
128            try:
129                xmlh=self.XMLHCache[uri]
130                status=1
131                logging.info('XMLH Cache hit for [%s]'%uri)
132            except:
133                logging.info('XMLH Cache miss for [%s]'%uri)
134                if localFile:
135                    status,xmlH=self.__getLocal(uri)
136                else:   
137                    status,xmlh=ndgRetrieve(ndgO,request.environ['ndgConfig'],logger,outputSchema)
138                if status: self.XMLHCache[uri]=xmlh
139           
140        if not status: return status,xmlh
141       
142        # convert doc to an XML tree
143        xmlh=xmlHandler2.xmlHandler(xmlh,string=1)
144       
145        # valid values of the return objects SHOULD BE
146        #   ok:         status=1, xmlh=an xml handler instance.
147        #   exceptions, status=0, xmlh='Exception(e)'
148       
149        status,xmlh=self.__GateKeep(ndgO,xmlh)
150        if status:
151            if cleared is None:
152                session['ndgCleared']=[uri]
153            else:
154                session['ndgCleared'].append(uri)
155            session.save()
156       
157        return status,xmlh
158           
159    def GetParsedCSML(self,uri):
160       
161        ''' This method gets a parsed CSML object corresponding to the URI '''
162       
163        # do we need an xml handler instance to test the security?
164        if 'ndgCleared' not in session:
165            status,xmlh=self.GetXML(uri)
166        else: 
167            if uri not in session['ndgCleared']: 
168                status,xmlh=self.GetXML(uri)
169            else: status=1
170        if not status: return status,xmlh
171       
172        try:
173            d=self.CSMLDocCache[uri]
174            logging.info('CSML Cache hit for [%s]'%uri)
175        except:
176            logging.info('CSML Cache miss for [%s]'%uri)
177            status,xmlh=self.GetXML(uri)
178            if not status: return status,xmlh   
179            d=csml.parser.Dataset()
180            d.parseElemTree(xmlh.tree)
181            self.CSMLDocCache[uri]=d
182        status=1
183        return status,d
184       
185    def __GateKeep(self,uri,x):
186        ''' This is the NDG gatekeeper '''
187        if 'ndgSec' in session:
188            securityTokens=session['ndgSec']
189        else:
190            securityTokens=None
191       
192        if uri.schema=='DIF':
193            pass # no access control
194        elif uri.schema =='NDG-B0':
195            #cred=x.find('dgSecurityCondition/simpleCondition')
196            #if cred:
197            #    return 0,'<p> Access Control: <br/>[<![CDAT[%s]]> </p>'
198            pass
199        elif uri.schema =='NDG-B1':
200            pass # for the moment
201        elif uri.schema =='NDG-A0':
202            if True:  # use this for turning security on and off during testing
203                s=x.tree.find('{http://ndg.nerc.ac.uk/csml}AccessControlPolicy/{http://ndg.nerc.ac.uk/csml}dgSecurityCondition')
204                if s is not None:
205                    status,message=HandleSecurity(uri,s,securityTokens)
206                    if not status: return 0,'<p> Access Denied for %s </p><p>%s</p>'%(uri,message)
207        return 1,x
208               
209    def __getLocal(self,uri):
210        ''' Returns a local csml file (used for testing) '''
211        csml_dir = request.environ['paste.config']['app_conf']['csml_dir']
212        path = os.path.join(csml_dir, file)
213        if os.path.exists(path+'.csml'):
214            f = path+'.csml'
215        elif os.path.exists(path+'.xml'):
216            f = path +'.xml'
217        else:
218            return 0, '<p>Cannot find CSML file %s</p>' % file
219        r=f.read()
220        return 1,r     
221       
222
223
224interface=ndgInterface()
Note: See TracBrowser for help on using the repository browser.