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

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

Modified the WCS code to work with the csml files in folders in the same way as the WMS code.

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 sorted(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.name,
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.