source: cows/branches/migrate-py26-pylons10/cows/pylons/wcs_controller.py @ 7342

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/cows/branches/migrate-py26-pylons10/cows/pylons/wcs_controller.py@7342
Revision 7342, 9.6 KB checked in by spascoe, 9 years ago (diff)

New branch for migration to Python-2.6 and Pylons-1.0.

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