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

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

correction to WCS Capabilities doc in line with new bounding box handling

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
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
25import Image
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
124           
125    def _getLayerParam(self, paramName='coverage'):
126        """
127        Retrieve the layers parameter enforcing the rule of only
128        selecting one coverage for now.
129
130        @param paramName: Overrides the query string parameter name to
131            look for.  This is usefull for implementing GetFeatureInfo.
132
133        """
134        layerName = self.getOwsParam(paramName)
135
136        # Select the first layer if several are requested.
137        # This plays nicer with mapClient.
138        if ',' in layerName:
139            #layerName = layerName.split(',')[0]
140            raise InvalidParameterValue(
141                'Multi-coverage getCoverage requests are not supported', 'coverage')
142        try:
143            layerObj = self.layers[layerName]
144        except KeyError:
145            raise InvalidParameterValue('coverage %s not found' % layerName,
146                                        paramName)
147
148        return layerName, layerObj
149   
150   
151    #-------------------------------------------------------------------------
152    # OWS Operation methods: DescribeCoverage and GetCoverage
153   
154    def GetCoverage(self):
155        # Housekeeping
156        version = self.getOwsParam('version', default=self.validVersions[0])
157        if version not in self.validVersions:
158            raise InvalidParameterValue('Version %s not supported' % version,
159                                        'version')
160        # Layer handling
161        layerName, layerObj = self._getLayerParam()
162       
163        # Coordinate parameters
164        bbox = tuple(float(x) for x in self.getOwsParam('bbox').split(','))
165
166        srs = self.getOwsParam('crs')
167
168        #if srs not in layerObj.crss:
169         #   raise InvalidParameterValue('Layer %s does not support SRS %s' % (layerName, srs))
170
171        # Get format
172        format = self.getOwsParam('format')
173        if srs not in layerObj.crss:
174            raise InvalidParameterValue('Layer %s does not support SRS %s' % (layerName, srs))
175        times= self.getOwsParam('time')
176       
177        #process times parameter so it is either a single string (one time) or a tuple (range):       
178        if len(times.split(',')) >1:
179            times=tuple(times.split(','))
180       
181        kwargs={}
182        for axis in layerObj.axisDescriptions: #TODO - axisDescriptions attribute
183            log.debug('axis: %s'%axis.name)
184            axisvalues=self.getOwsParam(axis.name, default=None)
185            log.debug('values: %s'%axisvalues)
186            if axisvalues:
187                values=tuple(float(x) for x in axisvalues.split(','))
188                if len(values)==1:
189                    values=(values[0], values[0],) #set min and max to be equal if single value
190                kwargs[axis.name]=values   
191       
192#               
193        filepath = layerObj.getCvg(bbox, time=times, **kwargs) #TODO, refactor so is more flexible (e.g. not just netcdf)
194        fileToReturn=open(filepath, 'r')
195        mType='application/cf-netcdf'
196        response.headers['Content-Type']=mType
197        response.headers['Content-Disposition'] = paste.httpheaders.CONTENT_DISPOSITION(attachment=True, filename=filepath)
198        return response.write(fileToReturn.read())
199           
200    def DescribeCoverage(self):
201        c.descriptions=[]
202        requestCvg=self.getOwsParam('coverage')
203#        super(WCSController, self).GetCapabilities()
204        #TODO, the bounding box may include a Z dimension in WCS.
205        log.debug(requestCvg)
206        for cvgName, coverage in self.layers.items():
207            log.debug(cvgName)
208            if cvgName == requestCvg:                   
209                # Create the enhanced Dataset summary for thic coverage
210                #TODO, the bounding box may include a Z dimension in WCS.               
211                ds = CoverageDescription(identifier=coverage.id,
212                                     titles=coverage.title,
213                                     wgs84BoundingBoxes=[coverage.wgs84BBox],
214                                     boundingBoxes=coverage.bboxes, 
215                                     description=coverage.description,
216                                     abstracts=coverage.abstract,
217                                     formats=['application/cf-netcdf'],
218                                     supportedCRSs=coverage.crss, 
219                                     timepositions=coverage.timePositions,
220                                     timelimits=coverage.timeLimits, 
221                                     axisdescriptions=coverage.axisDescriptions)
222
223                c.descriptions.append(ds)
224        response.headers['content-type']='text/xml'
225        t = ows_controller.templateLoader.load('wcs_describecoverage_1_0_0.xml')
226        return t.generate(c=c).render()               
227
228
229
230
231           
Note: See TracBrowser for help on using the repository browser.