diff --git a/bindings/python/mapnik/ogcserver/wms111.py b/bindings/python/mapnik/ogcserver/wms111.py index e4469a730..42c193f96 100644 --- a/bindings/python/mapnik/ogcserver/wms111.py +++ b/bindings/python/mapnik/ogcserver/wms111.py @@ -128,73 +128,74 @@ class ServiceHandler(WMSBaseServiceHandler): def __init__(self, conf, mapfactory, opsonlineresource): self.conf = conf self.mapfactory = mapfactory + self.opsonlineresource = opsonlineresource if self.conf.has_option('service', 'allowedepsgcodes'): self.allowedepsgcodes = map(lambda code: 'epsg:%s' % code, self.conf.get('service', 'allowedepsgcodes').split(',')) else: raise ServerConfigurationError('Allowed EPSG codes not properly configured.') - - capetree = ElementTree.fromstring(self.capabilitiesxmltemplate) - - elements = capetree.findall('Capability//OnlineResource') - for element in elements: - element.set('{http://www.w3.org/1999/xlink}href', opsonlineresource) - - self.processServiceCapabilities(capetree) - - rootlayerelem = capetree.find('{http://www.opengis.net/wms}Capability/{http://www.opengis.net/wms}Layer') - - for epsgcode in self.allowedepsgcodes: - rootlayercrs = ElementTree.Element('SRS') - rootlayercrs.text = epsgcode.upper() - rootlayerelem.append(rootlayercrs) - - for layer in self.mapfactory.layers.values(): - layerproj = Projection(layer.srs) - layername = ElementTree.Element('Name') - layername.text = layer.name - env = layer.envelope() - llp = layerproj.inverse(Coord(env.minx, env.miny)) - urp = layerproj.inverse(Coord(env.maxx, env.maxy)) - latlonbb = ElementTree.Element('LatLonBoundingBox') - latlonbb.set('minx', str(llp.x)) - latlonbb.set('miny', str(llp.y)) - latlonbb.set('maxx', str(urp.x)) - latlonbb.set('maxy', str(urp.y)) - layerbbox = ElementTree.Element('BoundingBox') - layerbbox.set('SRS', layerproj.epsgstring()) - layerbbox.set('minx', str(env.minx)) - layerbbox.set('miny', str(env.miny)) - layerbbox.set('maxx', str(env.maxx)) - layerbbox.set('maxy', str(env.maxy)) - layere = ElementTree.Element('Layer') - layere.append(layername) - if layer.title: - layertitle = ElementTree.Element('Title') - layertitle.text = layer.title - layere.append(layertitle) - if layer.abstract: - layerabstract = ElementTree.Element('Abstract') - layerabstract.text = layer.abstract - layere.append(layerabstract) - if layer.queryable: - layere.set('queryable', '1') - layere.append(latlonbb) - layere.append(layerbbox) - if len(layer.wmsextrastyles) > 0: - for extrastyle in [layer.wmsdefaultstyle] + list(layer.wmsextrastyles): - style = ElementTree.Element('Style') - stylename = ElementTree.Element('Name') - stylename.text = extrastyle - styletitle = ElementTree.Element('Title') - styletitle.text = extrastyle - style.append(stylename) - style.append(styletitle) - layere.append(style) - rootlayerelem.append(layere) - - self.capabilities = '\n' + ElementTree.tostring(capetree) + self.capabilities = None def GetCapabilities(self, params): + if not self.capabilities: + capetree = ElementTree.fromstring(self.capabilitiesxmltemplate) + + elements = capetree.findall('Capability//OnlineResource') + for element in elements: + element.set('{http://www.w3.org/1999/xlink}href', self.opsonlineresource) + + self.processServiceCapabilities(capetree) + + rootlayerelem = capetree.find('{http://www.opengis.net/wms}Capability/{http://www.opengis.net/wms}Layer') + + for epsgcode in self.allowedepsgcodes: + rootlayercrs = ElementTree.Element('SRS') + rootlayercrs.text = epsgcode.upper() + rootlayerelem.append(rootlayercrs) + + for layer in self.mapfactory.layers.values(): + layerproj = Projection(layer.srs) + layername = ElementTree.Element('Name') + layername.text = layer.name + env = layer.envelope() + llp = layerproj.inverse(Coord(env.minx, env.miny)) + urp = layerproj.inverse(Coord(env.maxx, env.maxy)) + latlonbb = ElementTree.Element('LatLonBoundingBox') + latlonbb.set('minx', str(llp.x)) + latlonbb.set('miny', str(llp.y)) + latlonbb.set('maxx', str(urp.x)) + latlonbb.set('maxy', str(urp.y)) + layerbbox = ElementTree.Element('BoundingBox') + layerbbox.set('SRS', layerproj.epsgstring()) + layerbbox.set('minx', str(env.minx)) + layerbbox.set('miny', str(env.miny)) + layerbbox.set('maxx', str(env.maxx)) + layerbbox.set('maxy', str(env.maxy)) + layere = ElementTree.Element('Layer') + layere.append(layername) + if layer.title: + layertitle = ElementTree.Element('Title') + layertitle.text = layer.title + layere.append(layertitle) + if layer.abstract: + layerabstract = ElementTree.Element('Abstract') + layerabstract.text = layer.abstract + layere.append(layerabstract) + if layer.queryable: + layere.set('queryable', '1') + layere.append(latlonbb) + layere.append(layerbbox) + if len(layer.wmsextrastyles) > 0: + for extrastyle in [layer.wmsdefaultstyle] + list(layer.wmsextrastyles): + style = ElementTree.Element('Style') + stylename = ElementTree.Element('Name') + stylename.text = extrastyle + styletitle = ElementTree.Element('Title') + styletitle.text = extrastyle + style.append(stylename) + style.append(styletitle) + layere.append(style) + rootlayerelem.append(layere) + self.capabilities = '\n' + ElementTree.tostring(capetree) response = Response('application/vnd.ogc.wms_xml', self.capabilities) return response diff --git a/bindings/python/mapnik/ogcserver/wms130.py b/bindings/python/mapnik/ogcserver/wms130.py index a65715baa..f4165dfe1 100644 --- a/bindings/python/mapnik/ogcserver/wms130.py +++ b/bindings/python/mapnik/ogcserver/wms130.py @@ -134,81 +134,82 @@ class ServiceHandler(WMSBaseServiceHandler): def __init__(self, conf, mapfactory, opsonlineresource): self.conf = conf self.mapfactory = mapfactory + self.opsonlineresource = opsonlineresource if self.conf.has_option('service', 'allowedepsgcodes'): self.allowedepsgcodes = map(lambda code: 'epsg:%s' % code, self.conf.get('service', 'allowedepsgcodes').split(',')) else: raise ServerConfigurationError('Allowed EPSG codes not properly configured.') - - capetree = ElementTree.fromstring(self.capabilitiesxmltemplate) - - elements = capetree.findall('{http://www.opengis.net/wms}Capability//{http://www.opengis.net/wms}OnlineResource') - for element in elements: - element.set('{http://www.w3.org/1999/xlink}href', opsonlineresource) - - self.processServiceCapabilities(capetree) - - rootlayerelem = capetree.find('{http://www.opengis.net/wms}Capability/{http://www.opengis.net/wms}Layer') - - for epsgcode in self.allowedepsgcodes: - rootlayercrs = ElementTree.Element('CRS') - rootlayercrs.text = epsgcode.upper() - rootlayerelem.append(rootlayercrs) - - for layer in self.mapfactory.layers.values(): - layerproj = Projection(layer.srs) - layername = ElementTree.Element('Name') - layername.text = layer.name - env = layer.envelope() - layerexgbb = ElementTree.Element('EX_GeographicBoundingBox') - ll = layerproj.inverse(Coord(env.minx, env.miny)) - ur = layerproj.inverse(Coord(env.maxx, env.maxy)) - exgbb_wbl = ElementTree.Element('westBoundLongitude') - exgbb_wbl.text = str(ll.x) - layerexgbb.append(exgbb_wbl) - exgbb_ebl = ElementTree.Element('eastBoundLongitude') - exgbb_ebl.text = str(ur.x) - layerexgbb.append(exgbb_ebl) - exgbb_sbl = ElementTree.Element('southBoundLatitude') - exgbb_sbl.text = str(ll.y) - layerexgbb.append(exgbb_sbl) - exgbb_nbl = ElementTree.Element('northBoundLatitude') - exgbb_nbl.text = str(ur.y) - layerexgbb.append(exgbb_nbl) - layerbbox = ElementTree.Element('BoundingBox') - layerbbox.set('CRS', layerproj.epsgstring()) - layerbbox.set('minx', str(env.minx)) - layerbbox.set('miny', str(env.miny)) - layerbbox.set('maxx', str(env.maxx)) - layerbbox.set('maxy', str(env.maxy)) - layere = ElementTree.Element('Layer') - layere.append(layername) - if layer.title: - layertitle = ElementTree.Element('Title') - layertitle.text = layer.title - layere.append(layertitle) - if layer.abstract: - layerabstract = ElementTree.Element('Abstract') - layerabstract.text = layer.abstract - layere.append(layerabstract) - if layer.queryable: - layere.set('queryable', '1') - layere.append(layerexgbb) - layere.append(layerbbox) - if len(layer.wmsextrastyles) > 0: - for extrastyle in [layer.wmsdefaultstyle] + list(layer.wmsextrastyles): - style = ElementTree.Element('Style') - stylename = ElementTree.Element('Name') - stylename.text = extrastyle - styletitle = ElementTree.Element('Title') - styletitle.text = extrastyle - style.append(stylename) - style.append(styletitle) - layere.append(style) - rootlayerelem.append(layere) - - self.capabilities = '' + ElementTree.tostring(capetree) + self.capabilities = None def GetCapabilities(self, params): + if not self.capabilities: + capetree = ElementTree.fromstring(self.capabilitiesxmltemplate) + + elements = capetree.findall('{http://www.opengis.net/wms}Capability//{http://www.opengis.net/wms}OnlineResource') + for element in elements: + element.set('{http://www.w3.org/1999/xlink}href', self.opsonlineresource) + + self.processServiceCapabilities(capetree) + + rootlayerelem = capetree.find('{http://www.opengis.net/wms}Capability/{http://www.opengis.net/wms}Layer') + + for epsgcode in self.allowedepsgcodes: + rootlayercrs = ElementTree.Element('CRS') + rootlayercrs.text = epsgcode.upper() + rootlayerelem.append(rootlayercrs) + + for layer in self.mapfactory.layers.values(): + layerproj = Projection(layer.srs) + layername = ElementTree.Element('Name') + layername.text = layer.name + env = layer.envelope() + layerexgbb = ElementTree.Element('EX_GeographicBoundingBox') + ll = layerproj.inverse(Coord(env.minx, env.miny)) + ur = layerproj.inverse(Coord(env.maxx, env.maxy)) + exgbb_wbl = ElementTree.Element('westBoundLongitude') + exgbb_wbl.text = str(ll.x) + layerexgbb.append(exgbb_wbl) + exgbb_ebl = ElementTree.Element('eastBoundLongitude') + exgbb_ebl.text = str(ur.x) + layerexgbb.append(exgbb_ebl) + exgbb_sbl = ElementTree.Element('southBoundLatitude') + exgbb_sbl.text = str(ll.y) + layerexgbb.append(exgbb_sbl) + exgbb_nbl = ElementTree.Element('northBoundLatitude') + exgbb_nbl.text = str(ur.y) + layerexgbb.append(exgbb_nbl) + layerbbox = ElementTree.Element('BoundingBox') + layerbbox.set('CRS', layerproj.epsgstring()) + layerbbox.set('minx', str(env.minx)) + layerbbox.set('miny', str(env.miny)) + layerbbox.set('maxx', str(env.maxx)) + layerbbox.set('maxy', str(env.maxy)) + layere = ElementTree.Element('Layer') + layere.append(layername) + if layer.title: + layertitle = ElementTree.Element('Title') + layertitle.text = layer.title + layere.append(layertitle) + if layer.abstract: + layerabstract = ElementTree.Element('Abstract') + layerabstract.text = layer.abstract + layere.append(layerabstract) + if layer.queryable: + layere.set('queryable', '1') + layere.append(layerexgbb) + layere.append(layerbbox) + if len(layer.wmsextrastyles) > 0: + for extrastyle in [layer.wmsdefaultstyle] + list(layer.wmsextrastyles): + style = ElementTree.Element('Style') + stylename = ElementTree.Element('Name') + stylename.text = extrastyle + styletitle = ElementTree.Element('Title') + styletitle.text = extrastyle + style.append(stylename) + style.append(styletitle) + layere.append(style) + rootlayerelem.append(layere) + self.capabilities = '' + ElementTree.tostring(capetree) response = Response('text/xml', self.capabilities) return response diff --git a/bindings/python/mapnik/ogcserver/wsgi.py b/bindings/python/mapnik/ogcserver/wsgi.py new file mode 100644 index 000000000..dd4ee56c8 --- /dev/null +++ b/bindings/python/mapnik/ogcserver/wsgi.py @@ -0,0 +1,97 @@ +# +# This file is part of Mapnik (c++ mapping toolkit) +# +# Copyright (C) 2006 Jean-Francois Doyon +# +# Mapnik is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# +# $Id$ + +from exceptions import OGCException, ServerConfigurationError +from configparser import SafeConfigParser +from cgi import parse_qs +from wms111 import ExceptionHandler as ExceptionHandler111 +from wms130 import ExceptionHandler as ExceptionHandler130 +from common import Version + +class WSGIApp: + + def __init__(self, configpath): + conf = SafeConfigParser() + conf.readfp(open(configpath)) + self.conf = conf + if not conf.has_option_with_value('server', 'module'): + raise ServerConfigurationError('The factory module is not defined in the configuration file.') + try: + mapfactorymodule = __import__(conf.get('server', 'module')) + except ImportError: + raise ServerConfigurationError('The factory module could not be loaded.') + if hasattr(mapfactorymodule, 'WMSFactory'): + self.mapfactory = getattr(mapfactorymodule, 'WMSFactory')() + else: + raise ServerConfigurationError('The factory module does not have a WMSFactory class.') + if conf.has_option('server', 'debug'): + self.debug = int(conf.get('server', 'debug')) + else: + self.debug = 0 + + def __call__(self, environ, start_response): + reqparams = {} + for key, value in parse_qs(environ['QUERY_STRING'], True).items(): + reqparams[key.lower()] = value[0] + onlineresource = 'http://%s:%s%s?' % (environ['SERVER_NAME'], environ['SERVER_PORT'], environ['SCRIPT_NAME']) + try: + if not reqparams.has_key('request'): + raise OGCException('Missing request parameter.') + request = reqparams['request'] + del reqparams['request'] + if request == 'GetCapabilities' and not reqparams.has_key('service'): + raise OGCException('Missing service parameter.') + if request in ['GetMap', 'GetFeatureInfo']: + service = 'WMS' + else: + service = reqparams['service'] + if reqparams.has_key('service'): + del reqparams['service'] + try: + mapnikmodule = __import__('mapnik.ogcserver.' + service) + except: + raise OGCException('Unsupported service "%s".' % service) + ServiceHandlerFactory = getattr(mapnikmodule.ogcserver, service).ServiceHandlerFactory + servicehandler = ServiceHandlerFactory(self.conf, self.mapfactory, onlineresource, reqparams.get('version', None)) + if reqparams.has_key('version'): + del reqparams['version'] + if request not in servicehandler.SERVICE_PARAMS.keys(): + raise OGCException('Operation "%s" not supported.' % request, 'OperationNotSupported') + ogcparams = servicehandler.processParameters(request, reqparams) + try: + requesthandler = getattr(servicehandler, request) + except: + raise OGCException('Operation "%s" not supported.' % request, 'OperationNotSupported') + response = requesthandler(ogcparams) + except: + version = reqparams.get('version', None) + if not version: + version = Version('1.3.0') + else: + version = Version(version) + if version >= '1.3.0': + eh = ExceptionHandler130(self.debug) + else: + eh = ExceptionHandler111(self.debug) + response = eh.getresponse(reqparams) + start_response('200 OK', [('Content-Type', response.content_type)]) + yield response.content + \ No newline at end of file