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

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

Interim commit to support common cache. At this point
it's implemented in retrieve (although not obviously
working in all cases).

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