source: qesdi/wms_ddc_vis/trunk/lib/wms_ddc_vis/controllers/coastwms.py @ 5479

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/qesdi/wms_ddc_vis/trunk/lib/wms_ddc_vis/controllers/coastwms.py@5479
Revision 5479, 9.7 KB checked in by pnorton, 11 years ago (diff)

Made some more modifications to the ddc WMS. I've tried to reduce the amount of code duplication between the code and the cows egg.

Line 
1import logging
2import Image
3import thread
4import re
5from StringIO import StringIO
6from sets import Set
7from matplotlib.cm import get_cmap
8from pylons import request, response, c
9from routes import url_for
10from routes.util import GenerationException
11from genshi.template import NewTextTemplate
12from cows.pylons.wms_controller import WMSController
13from cows.model.wms import WmsDatasetSummary, Dimension, DataURL
14from cows.model import PossibleValues, WGS84BoundingBox, BoundingBox, Contents
15from cows.pylons import ows_controller
16from cows.exceptions import *
17from cows import bbox_util
18
19from geoplot.layer_drawer_coastline import LayerDrawerCoastlines
20
21log = logging.getLogger(__name__)
22
23class CoastwmsController(ows_controller.OWSController):
24
25    #layers = {}   
26    _pilImageFormats = {
27        'image/png': 'PNG',
28        'image/jpg': 'JPEG',
29        'image/gif': 'GIF',
30        'image/tiff': 'TIFF'
31        }
32   
33    _layerSlabCache = {}
34
35    #-------------------------------------------------------------------------
36    # Attributes required by OWSController
37
38    service = 'WMS'
39    owsOperations = (ows_controller.OWSController.owsOperations +
40        ['GetMap', 'GetContext', 'GetLegend', 'GetFeatureInfo', 'GetInfo'])
41    validVersions = ['1.1.1', '1.3.0']
42
43
44
45    def _renderCapabilities(self, version, format):
46        if format == 'application/json':
47            t = ows_controller.templateLoader.load('wms_capabilities_json.txt',
48                                                   cls=NewTextTemplate)
49        elif version == '1.1.1':
50            t = ows_controller.templateLoader.load('wms_capabilities_1_1_1.xml')
51        elif version == '1.3.0':
52            t = ows_controller.templateLoader.load('wms_capabilities_1_3_0.xml')
53        else:
54            # We should never get here!  The framework should raise an exception before now.
55            raise RuntimeError("Version %s not supported" % version)
56       
57        return t.generate(c=c).render()
58
59    def _loadCapabilities(self):
60        """
61        @note: Assumes self.layers has already been created by __before__().
62
63        """
64        #!TODO: Add json format to GetCapabilities operation
65
66        ows_controller.addOperation('GetMap', formats=self._pilImageFormats.keys())
67        ows_controller.addOperation('GetContext', formats=['text/xml', 'application/json'])
68
69       
70        featureInfoFormats = Set()
71
72        log.debug('Loading capabilities contents')
73        c.capabilities.contents = Contents()
74        for layerName, layer in self.layers.items():
75            log.debug('LayerName: %s' % layerName)
76            log.debug('Loading layer %s' % layerName)
77
78            wgs84BBox = WGS84BoundingBox(layer.wgs84BBox[:2],
79                                         layer.wgs84BBox[2:])
80            # Get CRS/BBOX pairs
81            bboxObjs = []
82            for crs in layer.crss:
83                bbox = layer.getBBox(crs)
84                bboxObjs.append(BoundingBox(bbox[:2], bbox[2:], crs=crs))
85            # Get dimensions
86            dims = {}
87            for dimName, dim in layer.dimensions.items():
88                dimParam = self._mapDimToParam(dimName)
89                dims[dimParam] = Dimension(valuesUnit=dim.units,
90                                          unitSymbol=dim.units,
91                                          possibleValues=
92                                            PossibleValues.fromAllowedValues(dim.extent))
93            # Does the layer implement GetFeatureInfo?
94            if layer.featureInfoFormats:
95                queryable = True
96                featureInfoFormats.union_update(layer.featureInfoFormats)
97            else:
98                queryable = False
99               
100            #URL to WCS - uses named route 'wcsroute'
101            #TODO: Allow for a WCS blacklist to opt out of providing dataurls for certain datasets?
102            #TODO: How to make this more configurable - what if WCS is not coupled with WMS?
103            try:
104                version='1.0.0' #wcs version
105                wcsbaseurl=url_for('wcsroute', fileoruri=c.fileoruri,qualified=True)+'?'
106                dataURLs=[DataURL(format='WCS:CoverageDescription', onlineResource='%sService=WCS&Request=DescribeCoverage&Coverage=%s&Version=%s'%(wcsbaseurl, layerName, version))]
107            except GenerationException:
108                log.info("dataURLs not populated: could not generate WCS url with url_for('wcsroute', filedoruri=%s,qualified=True)"%c.fileoruri)
109                dataURLs=[]
110            # Create the cows object
111            ds = WmsDatasetSummary(identifier=layerName,
112                                   titles=[layer.title],
113                                   CRSs=layer.crss,
114                                   wgs84BoundingBoxes=[wgs84BBox],
115                                   boundingBoxes=bboxObjs,
116                                   abstracts=[layer.abstract],
117                                   dimensions=dims,
118                                   queryable=queryable,
119                                   dataURLs=dataURLs)
120
121            # Stuff that should go in the capabilities tree eventually
122            ds.legendSize = layer.legendSize
123            ds.legendFormats = ['image/png']
124
125            c.capabilities.contents.datasetSummaries.append(ds)
126
127        # Add this operation here after we have found all formats
128        ows_controller.addOperation('GetFeatureInfo',
129                                    formats = list(featureInfoFormats))
130
131
132    _escapedDimNames = ['width', 'height', 'version', 'request',
133                        'layers', 'styles', 'crs', 'srs', 'bbox',
134                        'format', 'transparent', 'bgcolor',
135                        'exceptions']
136
137
138    def _mapDimToParam(self, dimName):
139        """
140        Dimension names might clash with WMS parameter names, making
141        them inaccessible in WMS requests.  This method maps a
142        dimension name to a parameter name that appears in the
143        capabilities document and WMS requests.
144
145        """
146        if dimName.lower() in self._escapedDimNames:
147            return dimName+'_dim'
148        else:
149            return dimName
150       
151   
152    def GetMap(self):
153
154        # Housekeeping
155        version = self.getOwsParam('version', default=self.validVersions[0])
156        if version not in self.validVersions:
157            raise InvalidParameterValue('Version %s not supported' % version,
158                                        'version')
159        styles = self.getOwsParam('styles', default='')
160        transparent = self.getOwsParam('transparent', default='FALSE')
161        bgcolor = self.getOwsParam('bgcolor', default='0xFFFFFF')
162
163        # Layer handling
164        layerName = self.getOwsParam('layers')
165       
166        transparent = self.getOwsParam('transparent').lower() == 'true'
167       
168       
169        # Coordinate parameters
170        bbox = tuple(float(x) for x in self.getOwsParam('bbox').split(','))
171        width = int(self.getOwsParam('width'))
172        height = int(self.getOwsParam('height'))
173
174        if version == '1.1.1':
175            srs = self.getOwsParam('srs')
176        else:
177            srs = self.getOwsParam('crs')
178
179       # Get format
180        format = self.getOwsParam('format')
181        if format not in self._pilImageFormats:
182            raise InvalidParameterValue(
183                'Format %s not supported' % format, 'format')
184
185        ldg = LayerDrawerCoastlines(transparent=transparent,
186                                    resolution=layerName)
187
188        xLimits = (bbox[0], bbox[2])
189        yLimits = (bbox[1], bbox[3])       
190        finalImg = ldg.makeImage(xLimits, yLimits, width, height)     
191     
192       
193        # IE < 7 doesn't display the alpha layer right.  Here we sniff the
194        # user agent and remove the alpha layer if necessary.
195        try:
196            ua = request.headers['User-Agent']
197        except:
198            pass
199        else:
200            if 'MSIE' in ua and 'MSIE 7' not in ua:
201                finalImg = finalImg.convert('RGB')
202
203        buf = StringIO()
204        finalImg.save(buf, self._pilImageFormats[format])
205
206        response.headers['Content-Type'] = format
207        response.write(buf.getvalue())
208
209
210    def GetContext(self):
211        """
212        Return a WebMap Context document for a given set of layers.
213
214        """
215        # Parameters
216        layers = self.getOwsParam('layers', default=None)
217        format = self.getOwsParam('format', default='text/xml')
218
219        # Filter self.layers for selected layers
220        if layers is not None:
221            newLayerMap = {}
222            for layerName in layers.split(','):
223                try:
224                    newLayerMap[layerName] = self.layers[layerName]
225                except KeyError:
226                    raise InvalidParameterValue('Layer %s not found' % layerName,
227                                                'layers')
228                   
229            self.layers = newLayerMap
230
231        # Automatically select the first bbox/crs for the first layer
232        aLayer = self.layers.values()[0]
233        crs = aLayer.crss[0]
234        bb = aLayer.getBBox(crs)
235        c.bbox = BoundingBox(bb[:2], bb[2:], crs)
236
237        # Initialise as if doing GetCapabilities
238        ows_controller.initCapabilities()
239        self._loadCapabilities()
240
241        if format == 'text/xml':
242           
243            response.headers['Content-Type'] = format
244            t = ows_controller.templateLoader.load('wms_context_1_1_1.xml')
245            return t.generate(c=c).render()
246       
247        elif format == 'application/json':
248           
249            response.headers['Content-Type'] = format
250            t = ows_controller.templateLoader.load('wms_context_json.txt',
251                                                   cls=NewTextTemplate)
252            return t.generate(c=c).render()
253       
254        else:
255            raise InvalidParameterValue('Format %s not supported' % format)
256
Note: See TracBrowser for help on using the repository browser.