- Add WSGI handler
- Add a performance improvement that should make maps a little faster
This commit is contained in:
parent
76a820beeb
commit
737fcdd516
3 changed files with 229 additions and 130 deletions
|
@ -128,73 +128,74 @@ class ServiceHandler(WMSBaseServiceHandler):
|
||||||
def __init__(self, conf, mapfactory, opsonlineresource):
|
def __init__(self, conf, mapfactory, opsonlineresource):
|
||||||
self.conf = conf
|
self.conf = conf
|
||||||
self.mapfactory = mapfactory
|
self.mapfactory = mapfactory
|
||||||
|
self.opsonlineresource = opsonlineresource
|
||||||
if self.conf.has_option('service', 'allowedepsgcodes'):
|
if self.conf.has_option('service', 'allowedepsgcodes'):
|
||||||
self.allowedepsgcodes = map(lambda code: 'epsg:%s' % code, self.conf.get('service', 'allowedepsgcodes').split(','))
|
self.allowedepsgcodes = map(lambda code: 'epsg:%s' % code, self.conf.get('service', 'allowedepsgcodes').split(','))
|
||||||
else:
|
else:
|
||||||
raise ServerConfigurationError('Allowed EPSG codes not properly configured.')
|
raise ServerConfigurationError('Allowed EPSG codes not properly configured.')
|
||||||
|
self.capabilities = None
|
||||||
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 = '<?xml version="1.0" encoding="UTF-8" standalone="no"?>\n' + ElementTree.tostring(capetree)
|
|
||||||
|
|
||||||
def GetCapabilities(self, params):
|
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 = '<?xml version="1.0" encoding="UTF-8" standalone="no"?>\n' + ElementTree.tostring(capetree)
|
||||||
response = Response('application/vnd.ogc.wms_xml', self.capabilities)
|
response = Response('application/vnd.ogc.wms_xml', self.capabilities)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
|
@ -134,81 +134,82 @@ class ServiceHandler(WMSBaseServiceHandler):
|
||||||
def __init__(self, conf, mapfactory, opsonlineresource):
|
def __init__(self, conf, mapfactory, opsonlineresource):
|
||||||
self.conf = conf
|
self.conf = conf
|
||||||
self.mapfactory = mapfactory
|
self.mapfactory = mapfactory
|
||||||
|
self.opsonlineresource = opsonlineresource
|
||||||
if self.conf.has_option('service', 'allowedepsgcodes'):
|
if self.conf.has_option('service', 'allowedepsgcodes'):
|
||||||
self.allowedepsgcodes = map(lambda code: 'epsg:%s' % code, self.conf.get('service', 'allowedepsgcodes').split(','))
|
self.allowedepsgcodes = map(lambda code: 'epsg:%s' % code, self.conf.get('service', 'allowedepsgcodes').split(','))
|
||||||
else:
|
else:
|
||||||
raise ServerConfigurationError('Allowed EPSG codes not properly configured.')
|
raise ServerConfigurationError('Allowed EPSG codes not properly configured.')
|
||||||
|
self.capabilities = None
|
||||||
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 = '<?xml version="1.0" encoding="UTF-8"?>' + ElementTree.tostring(capetree)
|
|
||||||
|
|
||||||
def GetCapabilities(self, params):
|
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 = '<?xml version="1.0" encoding="UTF-8"?>' + ElementTree.tostring(capetree)
|
||||||
response = Response('text/xml', self.capabilities)
|
response = Response('text/xml', self.capabilities)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
97
bindings/python/mapnik/ogcserver/wsgi.py
Normal file
97
bindings/python/mapnik/ogcserver/wsgi.py
Normal file
|
@ -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
|
||||||
|
|
Loading…
Add table
Reference in a new issue