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

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

A temporary fix (I think) for ticket:841.
Some more improvements with security (still turned off though)

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