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

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

changing wcs response filename from default. Also tagging svn revisions when egging (may want to revise this following configuration disucssion).

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