source: cows/branches/wcsmerge/cows/pylons/wcs_controller.py @ 4634

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

more merging

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
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    def __before__(self, **kwargs):
50        """
51        This default implementation of __before__() will pass all routes
52        arguments to the layer mapper to retrieve a list of coverages for
53        this WCS.
54
55        It will be called automatically by pylons before each action method.
56
57        @todo: The layer mapper needs to come from somewhere.
58
59        """
60        log.debug("loading layers")
61        self.layers = self.layerMapper.map(**kwargs)
62
63    #-------------------------------------------------------------------------
64    # Methods implementing stubs in OWSController
65
66    def _renderCapabilities(self, version, format):
67        if version == '1.0.0':
68            t = ows_controller.templateLoader.load('wcs_capabilities_1_0_0.xml')
69        else:
70            # We should never get here!  The framework should raise an exception before now.
71            raise RuntimeError("Version %s not supported" % version)
72       
73        return t.generate(c=c).render()
74
75    def _loadCapabilities(self):
76        """
77        @note: Assumes self.layers has already been created by __before__().
78
79        """
80
81        ows_controller.addOperation('GetCoverage') 
82        featureInfoFormats = Set()
83
84        log.debug('Loading capabilities contents')
85        c.capabilities.contents = Contents()
86       
87        #TODO, the bounding box may include a Z dimension in WCS.
88        for cvgName, coverage in self.layers.items():
89            log.debug('Loading coverage %s' % cvgName)
90
91            wgs84BBox = WGS84BoundingBox(coverage.wgs84BBox[:2],
92                                         coverage.wgs84BBox[2:])
93            # Get CRS/BBOX pairs
94            bboxObjs = []
95            for crs in coverage.crss:
96                bbox = coverage.getBBox(crs)
97                bboxObjs.append(BoundingBox(bbox[:2], bbox[2:], crs=crs))
98               
99            # Create the cows object
100            #From the ows_servers stack - allthese values should come from  the Coverage object.
101            #TODO, the bounding box may include a Z dimension in WCS.
102            ds = WcsDatasetSummary(identifier=coverage.id,
103                                 titles=coverage.title,
104                                 boundingBoxes=[BoundingBox([bbox[0],bbox[1]], [bbox[2],bbox[3]],
105                                 crs='CRS:84')], 
106                                 description=coverage.description,
107                                 abstracts=coverage.abstract,
108                                 formats=['application/cf-netcdf'],
109                                 supportedCRSs=coverage.crss, 
110                                 timelimits=coverage.timeLimits
111                                 )
112
113
114
115            c.capabilities.contents.datasetSummaries.append(ds)
116
117   
118    def _getLayerParam(self, paramName='coverage'):
119        """
120        Retrieve the layers parameter enforcing the rule of only
121        selecting one coverage for now.
122
123        @param paramName: Overrides the query string parameter name to
124            look for.  This is usefull for implementing GetFeatureInfo.
125
126        """
127        layerName = self.getOwsParam(paramName)
128
129        # Select the first layer if several are requested.
130        # This plays nicer with mapClient.
131        if ',' in layerName:
132            #layerName = layerName.split(',')[0]
133            raise InvalidParameterValue(
134                'Multi-layer GetLegend requests are not supported', 'layers')
135        try:
136            layerObj = self.layers[layerName]
137        except KeyError:
138            raise InvalidParameterValue('Layer %s not found' % layerName,
139                                        paramName)
140
141        return layerName, layerObj
142   
143   
144    #-------------------------------------------------------------------------
145    # OWS Operation methods: DescribeCoverage and GetCoverage
146   
147    def GetCoverage(self):
148        # Housekeeping
149        version = self.getOwsParam('version', default=self.validVersions[0])
150        if version not in self.validVersions:
151            raise InvalidParameterValue('Version %s not supported' % version,
152                                        'version')
153        # Layer handling
154        layerName, layerObj = self._getLayerParam()
155       
156        # Coordinate parameters
157        bbox = tuple(float(x) for x in self.getOwsParam('bbox').split(','))
158
159        srs = self.getOwsParam('crs')
160
161        #if srs not in layerObj.crss:
162         #   raise InvalidParameterValue('Layer %s does not support SRS %s' % (layerName, srs))
163
164        # Get format
165        format = self.getOwsParam('format')
166       
167        if srs not in layerObj.crss:
168            raise InvalidParameterValue('Layer %s does not support SRS %s' % (layerName, srs))
169        times= self.getOwsParam('times')
170#               
171        #-------------------------------------------------------
172        #!TODO: Minimum and maximum values
173#        filepath = self._retrieveSubset(layerObj, srs, bbox, restoredDimValues)
174        filepath = layerObj.getCvg(bbox, time=times)
175        fileToReturn=open(filepath, 'r')
176        mType='application/cf-netcdf'
177        response.headers['Content-Type']=mType
178        response.headers['Content-Disposition'] = paste.httpheaders.CONTENT_DISPOSITION(attachment=True, filename='filename.nc')
179        return response.write(fileToReturn.read())
180           
181
182    def GetFeatureInfo(self): #TODO: This should be DescribeCoverage
183        # Housekeeping
184        version = self.getOwsParam('version', default=self.validVersions[0])
185        if version not in self.validVersions:
186            raise InvalidParameterValue('Version %s not supported' % version,
187                                        'version')
188
189        # Coordinate parameters
190        bbox = tuple(float(x) for x in self.getOwsParam('bbox').split(','))
191        width = int(self.getOwsParam('width'))
192        height = int(self.getOwsParam('height'))
193         
194        # Get pixel location
195        i = int(self.getOwsParam('i'))
196        j = int(self.getOwsParam('j'))
197
198        # Translate to geo-coordinates
199        x, y = bbox_util.pixelToGeo(i, j, bbox, width, height)
200        #start preparing GetFeatureInfo response. Assumes "HTML" output format
201
202        htmlResponse = "<html><body><p> <b>Feature Information about pixel position: "+self.getOwsParam('i')+","+self.getOwsParam('j')+"/geo position: "+str(x)+","+str(y) +"<b/></p>"
203       
204       
205        layers = self._getLayerParam('query_layers')
206        #Adjusts response for multiple layers
207        if len(layers) > 1:
208            htmlResponse = htmlResponse+" Multiple possible features found as follows:"
209 
210        htmlResponse = htmlResponse+"<ul>"
211       
212        format = self.getOwsParam('info_format', default='text/html')
213        for layerName, layerObj in layers.iteritems():
214            log.debug('Format: %s' % format)
215            log.debug('Title: %s' % layerObj.title)
216            log.debug('FeatureInfoFormats: %s' % layerObj.featureInfoFormats)
217        if format not in layerObj.featureInfoFormats:
218            raise InvalidParameterValue('Layer %s does not support GetFeatureInfo in format %s' %(layerName, format), 'info_format')
219
220        if version == '1.1.1':
221                srs = self.getOwsParam('srs')
222        else:
223            srs = self.getOwsParam('crs')
224
225        if srs not in layerObj.crss:
226            raise InvalidParameterValue('Layer %s does not support SRS %s' %
227                                        (layerName, srs))
228
229        # Dimension handling
230        dimValues = {}
231        for dimName, dim in layerObj.dimensions.items():
232            defaultValue = dim.extent[0]
233            dimValues[dimName] = self.getOwsParam(dimName, default=defaultValue)
234       
235        response.headers['Content-Type'] = format
236        response.write(layerObj.getFeatureInfo(format, srs, (x, y), dimValues))
237
238
239           
Note: See TracBrowser for help on using the repository browser.