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

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

Added some wms request logging that writes the parameeters and the header information to a file. Hopefully this will enable statistics to be generated on the data usage.

Also made some changes to the demo page so that it works in IE.

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