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

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

Fixes for ticket:858

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