|
|
@@ -1,411 +0,0 @@
|
|
|
-#!/usr/bin/env python
|
|
|
-# coding=utf-8
|
|
|
-
|
|
|
-import urlparse
|
|
|
-import urllib
|
|
|
-from lxml import objectify
|
|
|
-try:
|
|
|
- from lxml import etree
|
|
|
-except:
|
|
|
- from xml.etree import ElementTree as etree
|
|
|
-
|
|
|
-import os,sys
|
|
|
-import tempfile
|
|
|
-import logging
|
|
|
-import ConfigParser
|
|
|
-import md5
|
|
|
-import mapscript
|
|
|
-from string import Template
|
|
|
-from osgeo import osr
|
|
|
-from osgeo import ogr
|
|
|
-import OWSExceptions
|
|
|
-from owslib import crs as CRS
|
|
|
-import shutil
|
|
|
-
|
|
|
-class OWS:
|
|
|
-
|
|
|
- capabilities = None
|
|
|
- url = None
|
|
|
- requestUrl = None
|
|
|
- mapobj = None
|
|
|
- qstring = None
|
|
|
- owsns11 = "http://www.opengis.net/ows/1.1"
|
|
|
- owsns = "http://www.opengis.net/ows"
|
|
|
- cachedir = None
|
|
|
- mapfileName = "mapfile.map"
|
|
|
- config = None
|
|
|
- parsedUrl = None
|
|
|
- service = None
|
|
|
- mapfilename = None
|
|
|
-
|
|
|
- def __init__(self,url=None,qstring=None,configFile=None):
|
|
|
- self.requestUrl = url
|
|
|
- configFiles = [ os.path.join(os.path.dirname(__file__),"config.cfg") ]
|
|
|
-
|
|
|
- if sys.platform == "win32":
|
|
|
- pass # TODO Default conf. file on windows platform
|
|
|
- elif sys.platform == "linux2":
|
|
|
- configFiles.append("/etc/owsviewer.cfg")
|
|
|
-
|
|
|
- if configFile:
|
|
|
- configFiles.append(configFile)
|
|
|
-
|
|
|
- self.config = ConfigParser.ConfigParser()
|
|
|
- self.config.read(configFiles)
|
|
|
-
|
|
|
- logging.debug("Creating cachedir for %s in %s" % (self.url,self.config.get("Proxy4OWS","cachedir")))
|
|
|
- logging.debug("%s initialized"%self.service)
|
|
|
-
|
|
|
- if url:
|
|
|
- self.url = url
|
|
|
- logging.debug("OWS.py::__init__()::url: '%s'" % url)
|
|
|
- self.__getCapabilities()
|
|
|
- if qstring:
|
|
|
- self.qstring = qstring
|
|
|
-
|
|
|
-
|
|
|
- def __getCapabilities(self):
|
|
|
- self.__getCacheDir()
|
|
|
- logging.debug("OWS.py::__getCapabilities::self.url: '%s'" % self.url)
|
|
|
- self.parsedUrl = urlparse.urlparse(self.url)
|
|
|
-
|
|
|
- if self.service == "WFS":
|
|
|
- from owslib.wfs import WebFeatureService
|
|
|
- # FIXME Make default version configurable
|
|
|
- try:
|
|
|
- self.capabilities = WebFeatureService(url=self.url,version="1.0.0")
|
|
|
- except:
|
|
|
- self.capabilities = WebFeatureService(url=self.url,version="1.1.0")
|
|
|
-
|
|
|
- elif self.service == "WCS":
|
|
|
- from owslib.wcs import WebCoverageService
|
|
|
- self.capabilities = WebCoverageService(url=self.url,version="1.0.0")
|
|
|
-
|
|
|
- def getParams(self):
|
|
|
- params = urlparse.parse_qs(self.qstring)
|
|
|
-
|
|
|
- if not "VERSION" in params.keys() and "version" in params.keys():
|
|
|
- params["VERSION"] = params.pop("version")
|
|
|
- if not "LAYERS" in params.keys() and "layers" in params.keys():
|
|
|
- params["LAYERS"] = params.pop("layers")
|
|
|
- if not "FORMAT" in params.keys() and "format" in params.keys():
|
|
|
- params["FORMAT"] = params.pop("format")
|
|
|
- if not "STYLES" in params.keys() and "styles" in params.keys():
|
|
|
- params["STYLES"] = params.pop("styles")
|
|
|
- else:
|
|
|
- params["STYLES"] = ['']
|
|
|
- if not "TRANSPARENT" in params.keys() and "transparent" in params.keys():
|
|
|
- params["TRANSPARENT"] = params.pop("transparent")
|
|
|
- return params
|
|
|
-
|
|
|
- def getOnlineResource(self,onlineresource,mapfilename=None):
|
|
|
- o = urlparse.urlparse(onlineresource)
|
|
|
- params = urlparse.parse_qs(o.query,keep_blank_values=True)
|
|
|
- params["owsUrl"] = self.url
|
|
|
- params["owsService"] = self.service
|
|
|
- params["map"] = self.getMapfileLocation(mapfilename)
|
|
|
-
|
|
|
- location = urlparse.urlunparse((o[0],o[1],o[2],o[3],urllib.urlencode(params,True),o[5]))
|
|
|
- logging.debug("Setting OnlineResource to %s"% location)
|
|
|
- return location
|
|
|
-
|
|
|
- def getMapfileLocation(self,mapfilename=None):
|
|
|
-
|
|
|
- # save the map if possible
|
|
|
- if mapfilename:
|
|
|
- mapfilename.replace("..","") # remove potential path change
|
|
|
-
|
|
|
- # mapfile must end with .map and cachedir must be at the
|
|
|
- # beginning of the mapfile name
|
|
|
- if mapfilename.endswith(".map") and \
|
|
|
- mapfilename.find(self.cachedir) == 0:
|
|
|
- return mapfilename
|
|
|
-
|
|
|
- else:
|
|
|
- # do not save anything
|
|
|
- return
|
|
|
- # save to new location otherwice
|
|
|
- else:
|
|
|
- return os.path.join(self.cachedir,self.mapfileName)
|
|
|
-
|
|
|
- def __getCacheDir(self):
|
|
|
-
|
|
|
- dirname = os.path.join(self.config.get("Proxy4OWS","cachedir"),
|
|
|
- "%s-%s" % (self.service, md5.new(self.url).hexdigest()))
|
|
|
-
|
|
|
- self.cachedir = dirname
|
|
|
-
|
|
|
- # get existing cache dir
|
|
|
- if not os.path.isdir(dirname):
|
|
|
- os.mkdir(dirname)
|
|
|
- logging.debug("Cachedir %s created" % dirname)
|
|
|
- os.chmod(dirname, 0777)
|
|
|
- open(os.path.join(self.cachedir,"url.txt"),"w").write(self.url)
|
|
|
- else:
|
|
|
- logging.debug("Cachedir %s found" % dirname)
|
|
|
-
|
|
|
-
|
|
|
- return self.cachedir
|
|
|
-
|
|
|
- def dispatch(self):
|
|
|
- """Dispatch given request
|
|
|
- """
|
|
|
- request = mapscript.OWSRequest()
|
|
|
- request.loadParams()
|
|
|
- mapobj = None
|
|
|
-
|
|
|
- self.request=request.getValueByName("REQUEST")
|
|
|
-
|
|
|
- # if no 'map' parameter in URL, create new mapfile
|
|
|
- if not request.getValueByName("map"):
|
|
|
- logging.debug("Creating new mapfile")
|
|
|
- mapobj = self.makeMap()
|
|
|
- else:
|
|
|
- # there is 'map' parameter in URL and the file exists, load it
|
|
|
- logging.debug("Using existing mapfile %s" % request.getValueByName("map"))
|
|
|
- if os.path.isfile(request.getValueByName("map")):
|
|
|
- mapobj = mapscript.mapObj(request.getValueByName("map"))
|
|
|
- # there is 'map' parameter in URL BUT the file does not exist:
|
|
|
- # create
|
|
|
- else:
|
|
|
- mapobj = self.makeMap(request.getValueByName("map"))
|
|
|
-
|
|
|
- # WFS Filter encoding, if available
|
|
|
- if request.getValueByName("fes"):
|
|
|
- self.setFilter(mapobj,request)
|
|
|
-
|
|
|
- # mapobj.getLayerByName(request.getValueByName("layers")).metadata.get("wfs_filter")
|
|
|
- # here is still fine, but it fails on dispatch:
|
|
|
- res = mapobj.OWSDispatch(request)
|
|
|
- if mapscript.MS_DONE == res:
|
|
|
- raise OWSExceptions.NoValidRequest("No valid OWS Request")
|
|
|
- elif mapscript.MS_FAILURE == res:
|
|
|
- pass
|
|
|
- #raise OWSExceptions.RequestFailed("Request failed")
|
|
|
-
|
|
|
- def getMapObj(self,mapfilename=None):
|
|
|
-
|
|
|
-
|
|
|
- if self.url is not None and self.capabilities is None:
|
|
|
- self.__getCapabilities()
|
|
|
-
|
|
|
- # nothing has changed in the capabilities document since last
|
|
|
- # request ?
|
|
|
- if os.path.exists(os.path.join(self.cachedir,"capabilities.xml")) and\
|
|
|
- "_capabilities" in dir(self.capabilities):
|
|
|
- oldCapsFile = open(os.path.join(self.cachedir,"capabilities.xml"))
|
|
|
- oldCaps = oldCapsFile.read()
|
|
|
- oldCapsFile.close()
|
|
|
- # the capabilities document is up-to-date, load existing
|
|
|
- # mapfile
|
|
|
- newXml = etree.tostring(self.capabilities._capabilities)
|
|
|
- if md5.new(oldCaps).hexdigest() == md5.new(newXml).hexdigest():
|
|
|
- newCapsFile = open(os.path.join(self.cachedir,"capabilities.xml"),"w")
|
|
|
- newCapsFile.write(newXml)
|
|
|
- mapfilename = self.getMapfileLocation()
|
|
|
- if os.path.exists(mapfilename):
|
|
|
- logging.debug("Capabilities unchanged, using existing mapfile %s" % self.getMapfileLocation())
|
|
|
- return mapscript.mapObj(mapfilename)
|
|
|
-
|
|
|
-
|
|
|
- # finally
|
|
|
-
|
|
|
- # clear existing cached files
|
|
|
- logging.debug("Cached capabilities document is outdated, creating new one")
|
|
|
- shutil.rmtree(self.cachedir)
|
|
|
- # reate new one
|
|
|
- self.__getCacheDir()
|
|
|
- return self._createNewMapObj(mapfilename)
|
|
|
-
|
|
|
-
|
|
|
- def _createNewMapObj(self,mapfilename=None):
|
|
|
-
|
|
|
- mapobj = mapscript.mapObj()
|
|
|
-
|
|
|
- mapobj.setMetaData("wms_onlineresource",self.getOnlineResource(self.config.get("MapServer","onlineresource"),mapfilename))
|
|
|
-
|
|
|
- logging.debug("Setting SRS to %s"%self.config.get("MapServer","srs"))
|
|
|
- mapobj.setMetaData("wms_srs",self.config.get("MapServer","srs"))
|
|
|
-
|
|
|
- mapobj.setProjection("init=epsg:4326")
|
|
|
- mapobj.setSize(500,500)
|
|
|
- mapobj.setExtent(-180,-90,90,180)
|
|
|
- mapobj.shapepath = self.cachedir
|
|
|
- mapobj.setMetaData("wms_encoding","utf-8")
|
|
|
-
|
|
|
- errfile = self.config.get("MapServer","errorfile")
|
|
|
- logging.debug("Setting ERRORFILE to %s"%errfile)
|
|
|
- if not os.path.exists(errfile) and errfile != "stderr":
|
|
|
- tmp = open(errfile,"w")
|
|
|
- tmp.close()
|
|
|
-
|
|
|
- # file
|
|
|
- if os.access(errfile, os.W_OK):
|
|
|
- mapobj.setConfigOption("MS_ERRORFILE",errfile)
|
|
|
- # stderr
|
|
|
- elif errfile == "stderr":
|
|
|
- mapobj.setConfigOption("MS_ERRORFILE",errfile)
|
|
|
- # no error file set
|
|
|
- else:
|
|
|
- logging.warning("Cannot set ERRORFILE to %s: %s " % (errfile,"Write access denided"))
|
|
|
-
|
|
|
- logging.debug("Setting IMAGEPATH to %s"%self.config.get("MapServer","imagepath"))
|
|
|
- mapobj.web.imagepath=self.config.get("MapServer","imagepath")
|
|
|
-
|
|
|
- mapobj.setMetaData("ows_enable_request","*")
|
|
|
-
|
|
|
- return mapobj
|
|
|
-
|
|
|
- def saveMapfile(self,mapobj,mapfilename):
|
|
|
-
|
|
|
- self.mapfilename = self.getMapfileLocation(mapfilename)
|
|
|
- if self.mapfilename:
|
|
|
-
|
|
|
- # save mapfile ONLY if GetCapabilities requested - it makes no
|
|
|
- # sense for other cases
|
|
|
- logging.info("Saving mapfile to %s" % self.mapfilename)
|
|
|
- mapobj.save(self.mapfilename)
|
|
|
-
|
|
|
- # cache capabilities document
|
|
|
- if "_capabilities" in dir(self.capabilities):
|
|
|
- logging.info("Saving service Capabilities to %s" % os.path.join(self.cachedir,"capabilities.xml"))
|
|
|
- open(os.path.join(self.cachedir,"capabilities.xml"),"w").write(etree.tostring(self.capabilities._capabilities))
|
|
|
-
|
|
|
- else:
|
|
|
- logging.info("Mapfile NOT saved")
|
|
|
-
|
|
|
- return self.mapfilename
|
|
|
-
|
|
|
- def getLayerUrl(self):
|
|
|
-
|
|
|
- layerurl = self.url
|
|
|
-
|
|
|
- if self.url.find("?") > -1:
|
|
|
- if not self.url.endswith("?") and\
|
|
|
- not self.url.endswith("&"):
|
|
|
- layerurl += "&"
|
|
|
- else:
|
|
|
- layerurl += "?"
|
|
|
-
|
|
|
- return layerurl
|
|
|
-
|
|
|
- def createLayerDefinitionFile(self, name,
|
|
|
- templatefile,time="",target=None):
|
|
|
-
|
|
|
- layerurl = self.getLayerUrl()
|
|
|
- defFileName = None
|
|
|
- if target:
|
|
|
- defFileName = target
|
|
|
- else:
|
|
|
- defFileName = os.path.join(self.cachedir,'%s.%s'%(name,self.service.lower()))
|
|
|
- if time:
|
|
|
- time = "<DefaultTime>"+time+"</DefaultTime>"
|
|
|
-
|
|
|
- if not os.path.isfile(defFileName):
|
|
|
- open(defFileName,'w').write(
|
|
|
- Template(open(templatefile).read()).substitute(
|
|
|
- dict(url= layerurl,
|
|
|
- name=name,time=time,extras="&BAND=1,2,3")))
|
|
|
- # FIXME always takes band 1,2,3 ^^
|
|
|
-
|
|
|
- logging.debug("Created %s layer definition file" % defFileName)
|
|
|
- else:
|
|
|
- logging.debug("Using existing layer definition file %s" % defFileName)
|
|
|
-
|
|
|
- return defFileName
|
|
|
-
|
|
|
- def getLayerExtent(self,layer,crs=None):
|
|
|
- """Get extent of layer in form of minx, miny, maxx,maxy
|
|
|
-
|
|
|
- :returns: [minx, miny, maxx, maxy]
|
|
|
- """
|
|
|
-
|
|
|
- bbox = None
|
|
|
- if layer.boundingBoxWGS84:
|
|
|
-
|
|
|
- dest = osr.SpatialReference()
|
|
|
- dest.ImportFromEPSG(crs.code)
|
|
|
-
|
|
|
- source = osr.SpatialReference()
|
|
|
- source.ImportFromEPSG(4326)
|
|
|
-
|
|
|
- bbox = []
|
|
|
-
|
|
|
- # TODO rewrite this using ogr CoordinateTransformation
|
|
|
- # http://www.gdal.org/ogr/osr_tutorial.html
|
|
|
- # WELL: it does NOT seem to be THAT better
|
|
|
- geom = ogr.CreateGeometryFromWkt("""POINT(%s %s)""" % (layer.boundingBoxWGS84[0],layer.boundingBoxWGS84[1]),source)
|
|
|
- geom.TransformTo(dest)
|
|
|
- bbox.append(geom.GetX())
|
|
|
- bbox.append(geom.GetY())
|
|
|
-
|
|
|
- geom = ogr.CreateGeometryFromWkt("""POINT(%s %s)""" % (layer.boundingBoxWGS84[2],layer.boundingBoxWGS84[3]),source)
|
|
|
- geom.TransformTo(dest)
|
|
|
- bbox.append(geom.GetX())
|
|
|
- bbox.append(geom.GetY())
|
|
|
-
|
|
|
- logging.debug("Setting extent for layer <%s> to %s" %\
|
|
|
- (layer.id,bbox))
|
|
|
- return bbox
|
|
|
-
|
|
|
- def setFilter(self,mapobj,request):
|
|
|
- """ Set WFS filter encoding
|
|
|
- """
|
|
|
- # get the layer
|
|
|
- layerobj = mapobj.getLayerByName(request.getValueByName("layers"))
|
|
|
-
|
|
|
- # get the filter
|
|
|
- fes = request.getValueByName("fes")
|
|
|
- logging.debug("FES received from HSLayers: %s" % fes)
|
|
|
-
|
|
|
- # cut off the opening and closing <Filter> tag
|
|
|
- # - this is needed for mapserver
|
|
|
- #root = etree.XML(fes)
|
|
|
- #msFilter = ""
|
|
|
- #for child in root:
|
|
|
- # msFilter += etree.tostring(child)
|
|
|
- #logging.debug("Setting the filter %s" % msFilter)
|
|
|
-
|
|
|
- # set the filter
|
|
|
- layerobj.setMetaData("wfs_filter",fes)
|
|
|
- #layerobj.setMetaData("wfs_filter",msFilter)
|
|
|
-
|
|
|
- # save the mapfile - debugging
|
|
|
- mapobj.save("mapfile.fes")
|
|
|
-
|
|
|
-
|
|
|
-def getService(configFile=None):
|
|
|
-
|
|
|
- qstring = os.environ["QUERY_STRING"]
|
|
|
- params = urlparse.parse_qs(qstring)
|
|
|
-
|
|
|
- for p in params:
|
|
|
- if p.lower() == "owsurl":
|
|
|
- v = params[p]
|
|
|
- del params[p]
|
|
|
- params["owsUrl"] = v
|
|
|
-
|
|
|
- if p.lower() == "owsservice":
|
|
|
- v = params[p]
|
|
|
- del params[p]
|
|
|
- params["owsService"] = v
|
|
|
-
|
|
|
-
|
|
|
- if "owsUrl" in params.keys() and\
|
|
|
- "owsService" in params.keys():
|
|
|
- owsUrl = urllib.unquote(params["owsUrl"][0])
|
|
|
-
|
|
|
- if params["owsService"][0].lower() == "wfs":
|
|
|
- from wfs import WFS
|
|
|
- logging.debug("OWS.py::getService()::owsUrl: '%s'" % owsUrl)
|
|
|
- return WFS(owsUrl,qstring,configFile = configFile )
|
|
|
- elif params["owsService"][0].lower() == "wcs":
|
|
|
- from wcs import WCS
|
|
|
- return WCS(owsUrl,qstring, configFile = configFile)
|
|
|
- elif params["owsService"][0].lower() == "wms":
|
|
|
- from wms import WMS
|
|
|
- return WMS(owsUrl,qstring, configFile = configFile)
|
|
|
- else:
|
|
|
- raise OWSExceptions.MissingParameterValue("""owsUrl or owsService""")
|
|
|
-
|
|
|
-
|