| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411 |
- #!/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""")
-
|