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

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

svn commit -m fixed WCS CRS handling so correct CRSs are advertised

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