source: cows/trunk/cows/pylons/wcs_controller.py @ 5962

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/cows/trunk/cows/pylons/wcs_controller.py@5962
Revision 5962, 9.6 KB checked in by domlowe, 11 years ago (diff)

wcs was not deleting temporary files.

Line 
1# BSD Licence
2# Copyright (c) 2009, Science & Technology Facilities Council (STFC)
3# All rights reserved.
4#
5# See the LICENSE file in the source distribution of this software for
6# the full license text.
7
8"""
9WMS controller for OGC Web Services (OWS).
10
11@author: Stephen Pascoe
12"""
13   
14import re, os
15import math
16from cStringIO import StringIO
17from sets import Set
18from matplotlib.cm import get_cmap
19from pylons import request, response, c
20import paste
21
22import logging
23log = logging.getLogger(__name__)
24
25
26from genshi.template import TextTemplate
27
28from cows.model.wms import Dimension
29from cows.model.wcs import WcsDatasetSummary, CoverageDescription
30from cows.model import PossibleValues, WGS84BoundingBox, BoundingBox, Contents
31from cows.pylons import ows_controller
32from cows.exceptions import *
33from cows import bbox_util
34
35class WCSController(ows_controller.OWSController):
36    """
37    Subclass this controller in a pylons application and set the layerMapper
38    class attribute to implement a WCS.
39
40    @cvar layerMapper: an cows.service.wcs_iface.ILayerMapper object.
41
42    """
43    layerMapper = None
44    _layerSlabCache = {}
45
46    #-------------------------------------------------------------------------
47    # Attributes required by OWSController
48
49    service = 'WCS'
50    owsOperations = (ows_controller.OWSController.owsOperations +
51        ['GetCoverage', 'DescribeCoverage'])
52    validVersions = ['1.0.0']
53   
54
55    #-------------------------------------------------------------------------
56
57    def __before__(self, **kwargs):
58        """
59        This default implementation of __before__() will pass all routes
60        arguments to the layer mapper to retrieve a list of coverages for
61        this WCS.
62
63        It will be called automatically by pylons before each action method.
64
65        @todo: The layer mapper needs to come from somewhere.
66
67        """
68        log.debug("loading layers")
69        self.layers = self.layerMapper.map(**kwargs)
70
71    #-------------------------------------------------------------------------
72    # Methods implementing stubs in OWSController
73
74    def _renderCapabilities(self, version, format):
75        if version == '1.0.0':
76            t = ows_controller.templateLoader.load('wcs_capabilities_1_0_0.xml')
77        else:
78            # We should never get here!  The framework should raise an exception before now.
79            raise RuntimeError("Version %s not supported" % version)
80       
81        return t.generate(c=c).render()
82
83    def _loadCapabilities(self):
84        """
85        @note: Assumes self.layers has already been created by __before__().
86
87        """
88        ows_controller.addOperation('GetCoverage')
89        ows_controller.addOperation('DescribeCoverage') 
90        featureInfoFormats = Set()
91
92        log.debug('Loading capabilities contents')
93        c.capabilities.contents = Contents()
94       
95        #TODO, the bounding box may include a Z dimension in WCS.
96        for cvgName, coverage in self.layers.items():
97            log.debug('Loading coverage %s' % cvgName)
98
99#            wgs84BBox = WGS84BoundingBox(coverage.wgs84BBox[:2],
100#                                         coverage.wgs84BBox[2:])
101#            wgs84BBox=coverage.wgs84BBox
102#            # Get CRS/BBOX pairs
103#            bboxObjs = []
104#            for crs in coverage.crss:
105#                bbox = coverage.getBBox(crs)
106#                bboxObjs.append(BoundingBox(bbox[:2], bbox[2:], crs=crs))
107               
108            # Create the cows object
109            #From the ows_servers stack - allthese values should come from  the Coverage object.
110            #TODO, the bounding box may include a Z dimension in WCS.
111            ds = WcsDatasetSummary(identifier=coverage.id,
112                                 titles=coverage.title,
113                                 wgs84BoundingBoxes=[coverage.wgs84BBox],
114                                 boundingBoxes=[coverage.bboxes], 
115                                 description=coverage.description,
116                                 abstracts=coverage.abstract,
117                                 formats=['application/cf-netcdf'],
118                                 supportedCRSs=coverage.crss, 
119                                 timelimits=coverage.timeLimits
120                                 )
121
122            c.capabilities.contents.datasetSummaries.append(ds)
123        #LayerMapper may optionally implement a datasetName attribute which
124        #will be tried if serviceIdentification/title is not supplied in capabilities config
125        if c.capabilities.serviceIdentification.titles[0] is None:
126            try:
127                c.capabilities.serviceIdentification.titles=[self.layerMapper.datasetName]
128            except AttributeError:
129                pass
130           
131    def _getLayerParam(self, paramName='coverage'):
132        """
133        Retrieve the layers parameter enforcing the rule of only
134        selecting one coverage for now.
135
136        @param paramName: Overrides the query string parameter name to
137            look for.  This is usefull for implementing GetFeatureInfo.
138
139        """
140        layerName = self.getOwsParam(paramName)
141
142        # Select the first layer if several are requested.
143        # This plays nicer with mapClient.
144        if ',' in layerName:
145            #layerName = layerName.split(',')[0]
146            raise InvalidParameterValue(
147                'Multi-coverage getCoverage requests are not supported', 'coverage')
148        try:
149            layerObj = self.layers[layerName]
150        except KeyError:
151            raise InvalidParameterValue('coverage %s not found' % layerName,
152                                        paramName)
153
154        return layerName, layerObj
155   
156   
157    #-------------------------------------------------------------------------
158    # OWS Operation methods: DescribeCoverage and GetCoverage
159   
160    def GetCoverage(self):
161        # Housekeeping
162        version = self.getOwsParam('version', default=self.validVersions[0])
163        if version not in self.validVersions:
164            raise InvalidParameterValue('Version %s not supported' % version,
165                                        'version')
166        # Layer handling
167        layerName, layerObj = self._getLayerParam()
168       
169        # Coordinate parameters
170        bbox = tuple(float(x) for x in self.getOwsParam('bbox').split(','))
171
172        srs = self.getOwsParam('crs')
173
174        #if srs not in layerObj.crss:
175         #   raise InvalidParameterValue('Layer %s does not support SRS %s' % (layerName, srs))
176
177        # Get format
178        format = self.getOwsParam('format')
179        if srs not in layerObj.crss:
180            raise InvalidParameterValue('Layer %s does not support SRS %s' % (layerName, srs))
181        times= self.getOwsParam('time', default=None)
182       
183        #process times parameter so it is either a single string (one time) or a tuple (range) (OR None)       
184        if times is not None:
185            if len(times.split(',')) >1:
186                times=tuple(times.split(','))
187       
188        kwargs={}
189        for axis in layerObj.axisDescriptions: #TODO - axisDescriptions attribute
190            log.debug('axis: %s'%axis.name)
191            axisvalues=self.getOwsParam(axis.name, default=None)
192            log.debug('values: %s'%axisvalues)
193            if axisvalues:
194                values=tuple(float(x) for x in axisvalues.split(','))
195                if len(values)==1:
196                    values=(values[0], values[0],) #set min and max to be equal if single value
197                kwargs[axis.name]=values   
198       
199#     
200        filepath = layerObj.getCvg(bbox, time=times, **kwargs) #TODO, refactor so is more flexible (e.g. not just netcdf)
201        fileToReturn=open(filepath, 'r')
202        mType='application/cf-netcdf'
203        response.headers['Content-Type']=mType
204        response.headers['Content-Disposition'] = paste.httpheaders.CONTENT_DISPOSITION(attachment=True, filename=filepath)
205        u=fileToReturn.read()
206        #close and delete file from file system
207        fileToReturn.close()
208        log.debug('deleting temporary file %s'%filepath)
209        os.system('rm %s'%filepath)
210        return response.write(u)
211       
212       
213           
214    def DescribeCoverage(self):
215        c.descriptions=[]
216        requestCvg=self.getOwsParam('coverage')
217#        super(WCSController, self).GetCapabilities()
218        #TODO, the bounding box may include a Z dimension in WCS.
219        log.debug('DescribeCoverage request for %s'%requestCvg)
220        for cvgName, coverage in self.layers.items():
221            log.debug(cvgName)
222            if cvgName == requestCvg:
223                log.debug('found coverage %s'%cvgName)
224                # Create the enhanced Dataset summary for thic coverage
225                #TODO, the bounding box may include a Z dimension in WCS.               
226                ds = CoverageDescription(identifier=coverage.id,
227                                     titles=coverage.title,
228                                     wgs84BoundingBoxes=[coverage.wgs84BBox],
229                                     boundingBoxes=coverage.bboxes, 
230                                     description=coverage.description,
231                                     abstracts=coverage.abstract,
232                                     formats=['application/cf-netcdf'],
233                                     supportedCRSs=coverage.crss, 
234                                     timepositions=coverage.timePositions,
235                                     timelimits=coverage.timeLimits, 
236                                     axisdescriptions=coverage.axisDescriptions)
237
238                c.descriptions.append(ds)
239        response.headers['content-type']='text/xml'
240        t = ows_controller.templateLoader.load('wcs_describecoverage_1_0_0.xml')
241        return t.generate(c=c).render()               
242
243
244
245
246           
Note: See TracBrowser for help on using the repository browser.