OWS.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. #!/usr/bin/env python
  2. # coding=utf-8
  3. import urlparse
  4. import urllib
  5. from lxml import objectify
  6. from lxml import etree
  7. import os,sys
  8. import tempfile
  9. import logging
  10. import ConfigParser
  11. import md5
  12. import mapscript
  13. from string import Template
  14. from osgeo import osr
  15. from osgeo import ogr
  16. import OWSExceptions
  17. class OWS:
  18. capabilities = None
  19. url = None
  20. requestUrl = None
  21. mapobj = None
  22. qstring = None
  23. owsns11 = "http://www.opengis.net/ows/1.1"
  24. owsns = "http://www.opengis.net/ows"
  25. cachedir = None
  26. mapfileName = "mapfile.map"
  27. config = None
  28. parsedUrl = None
  29. service = None
  30. mapfilename = None
  31. def __init__(self,url=None,qstring=None,configFile=None):
  32. self.requestUrl = url
  33. if url:
  34. self.url = url
  35. logging.debug("OWS.py::__init__()::url: '%s'" % url)
  36. self.__getCapabilities()
  37. if qstring:
  38. self.qstring = qstring
  39. configFiles = [
  40. os.path.join(os.path.dirname(__file__),"config.cfg")
  41. ]
  42. if sys.platform == "win32":
  43. pass # TODO Default conf. file on windows platform
  44. elif sys.platform == "linux2":
  45. configFiles.append("/etc/owsviewer.cfg")
  46. if configFile:
  47. configFiles.append(configFile)
  48. self.config = ConfigParser.ConfigParser()
  49. self.config.read(configFiles)
  50. logging.debug("Creating cachedir for %s in %s" % (self.url,self.config.get("OWSProxy","cachedir")))
  51. logging.debug("%s initialized"%self.service)
  52. def __getCapabilities(self):
  53. logging.debug("OWS.py::__getCapabilities::self.url: '%s'" % self.url)
  54. self.parsedUrl = urlparse.urlparse(self.url)
  55. if self.service == "WFS":
  56. from owslib.wfs import WebFeatureService
  57. self.capabilities = WebFeatureService(url=self.url,version="1.1.0")
  58. logging.debug("OWS Capabilities: %s",self.capabilities)
  59. elif self.service == "WCS":
  60. from owslib.wcs import WebCoverageService
  61. self.capabilities = WebCoverageService(url=self.url,version="1.0.0")
  62. def getParams(self):
  63. return urlparse.parse_qs(self.qstring)
  64. def getOnlineResource(self,onlineresource,mapfilename=None):
  65. o = urlparse.urlparse(onlineresource)
  66. params = urlparse.parse_qs(o.query,keep_blank_values=True)
  67. params["owsUrl"] = self.url
  68. params["owsService"] = self.service
  69. params["map"] = self.getMapfileLocation(mapfilename)
  70. location = urlparse.urlunparse((o[0],o[1],o[2],o[3],urllib.urlencode(params,True),o[5]))
  71. logging.debug("Setting OnlineResource to %s"% location)
  72. return location
  73. def getMapfileLocation(self,mapfilename=None):
  74. # save the map if possible
  75. if mapfilename:
  76. mapfilename.replace("..","") # remove potential path change
  77. # mapfile must end with .map and cachedir must be at the
  78. # beginning of the mapfile name
  79. if mapfilename.endswith(".map") and \
  80. mapfilename.find(self.cachedir) == 0:
  81. return mapfilename
  82. else:
  83. # do not save anything
  84. return
  85. # save to new location otherwice
  86. else:
  87. return os.path.join(self.cachedir,self.mapfileName)
  88. def __getCacheDir(self):
  89. self.cachedir = tempfile.mkdtemp(prefix="%s-%s"%(self.service,
  90. md5.new(self.url).hexdigest()),
  91. dir=self.config.get("OWSProxy","cachedir"))
  92. os.chmod(self.cachedir, 0777)
  93. logging.debug("Cachedir %s created" % self.cachedir)
  94. open(os.path.join(self.cachedir,"url.txt"),"w").write(self.url)
  95. return self.cachedir
  96. def dispatch(self):
  97. """Dispatch given request
  98. """
  99. request = mapscript.OWSRequest()
  100. request.loadParams()
  101. mapobj = None
  102. self.request=request.getValueByName("REQUEST")
  103. # if no 'map' parameter in URL, create new mapfile
  104. if not request.getValueByName("map"):
  105. logging.debug("Creating new mapfile")
  106. mapobj = self.makeMap()
  107. else:
  108. # there is 'map' parameter in URL and the file exists, load it
  109. logging.debug("Using existing mapfile %s" % request.getValueByName("map"))
  110. if os.path.isfile(request.getValueByName("map")):
  111. mapobj = mapscript.mapObj(request.getValueByName("map"))
  112. # there is 'map' parameter in URL BUT the file does not exist:
  113. # create
  114. else:
  115. mapobj = self.makeMap(request.getValueByName("map"))
  116. # WFS Filter encoding, if available
  117. if request.getValueByName("fes"):
  118. self.setFilter(mapobj,request)
  119. # mapobj.getLayerByName(request.getValueByName("layers")).metadata.get("wfs_filter")
  120. # here is still fine, but it fails on dispatch:
  121. res = mapobj.OWSDispatch(request)
  122. if mapscript.MS_DONE == res:
  123. raise OWSExceptions.NoValidRequest("No valid OWS Request")
  124. elif mapscript.MS_FAILURE == res:
  125. pass
  126. #raise OWSExceptions.RequestFailed("Request failed")
  127. def getMapObj(self,mapfilename=None):
  128. self.__getCacheDir()
  129. if self.url is not None and self.capabilities is None:
  130. self.__getCapabilities()
  131. mapobj = mapscript.mapObj()
  132. mapobj.setMetaData("wms_onlineresource",self.getOnlineResource(self.config.get("MapServer","onlineresource"),mapfilename))
  133. logging.debug("Setting SRS to %s"%self.config.get("MapServer","srs"))
  134. mapobj.setMetaData("wms_srs",self.config.get("MapServer","srs"))
  135. mapobj.setProjection("init=epsg:4326")
  136. mapobj.setSize(500,500)
  137. mapobj.setExtent(-180,-90,90,180)
  138. mapobj.shapepath = self.cachedir
  139. mapobj.setMetaData("wms_encoding","utf-8")
  140. errfile = self.config.get("MapServer","errorfile")
  141. logging.debug("Setting ERRORFILE to %s"%errfile)
  142. if not os.path.exists(errfile) and errfile != "stderr":
  143. tmp = open(errfile,"w")
  144. tmp.close()
  145. # file
  146. if os.access(errfile, os.W_OK):
  147. mapobj.setConfigOption("MS_ERRORFILE",errfile)
  148. # stderr
  149. elif errfile == "stderr":
  150. mapobj.setConfigOption("MS_ERRORFILE",errfile)
  151. # no error file set
  152. else:
  153. logging.warning("Cannot set ERRORFILE to %s: %s " % (errfile,"Write access denided"))
  154. logging.debug("Setting IMAGEPATH to %s"%self.config.get("MapServer","imagepath"))
  155. mapobj.web.imagepath=self.config.get("MapServer","imagepath")
  156. mapobj.setMetaData("ows_enable_request","*")
  157. return mapobj
  158. def saveMapfile(self,mapobj,mapfilename):
  159. self.mapfilename = self.getMapfileLocation(mapfilename)
  160. if self.mapfilename:
  161. # save mapfile ONLY if GetCapabilities requested - it makes no
  162. # sense for other cases
  163. logging.info("Saving mapfile to %s" % self.mapfilename)
  164. mapobj.save(self.mapfilename)
  165. else:
  166. logging.info("Mapfile NOT saved")
  167. return self.mapfilename
  168. def getLayerUrl(self):
  169. layerurl = self.url
  170. if self.url.find("?") > -1:
  171. if not self.url.endswith("?") and\
  172. not self.url.endswith("&"):
  173. layerurl += "&"
  174. else:
  175. layerurl += "?"
  176. return layerurl
  177. def createLayerDefinitionFile(self, name,
  178. templatefile,time=None,target=None):
  179. layerurl = self.getLayerUrl()
  180. defFileName = None
  181. if target:
  182. defFileName = target
  183. else:
  184. defFileName = os.path.join(self.cachedir,'%s.%s'%(name,self.service.lower()))
  185. if time:
  186. time = "<DefaultTime>"+time+"</DefaultTime>"
  187. else:
  188. time = ""
  189. open(defFileName,'w').write(
  190. Template(open(templatefile).read()).substitute(
  191. dict(url= layerurl, name=name,time=time)))
  192. logging.debug("Created %s layer definition file" % defFileName)
  193. return defFileName
  194. def getLayerExtent(self,layer,crs=None,wkt=None):
  195. """Get extent of layer in form of minx, miny, maxx,maxy
  196. """
  197. bbox = None
  198. if layer.boundingBoxWGS84:
  199. dest = osr.SpatialReference()
  200. if crs:
  201. try:
  202. crsSplit = crs.split(":")
  203. epsg = int(crsSplit[len(crsSplit)-1])
  204. dest.ImportFromEPSG(epsg)
  205. except (ValueError):
  206. logging.debug("Unable to parse crs '%s'" % crs)
  207. else:
  208. dest.ImportFromWkt(wkt)
  209. source = osr.SpatialReference()
  210. source.ImportFromEPSG(4326)
  211. bbox = []
  212. # TODO rewrite this using ogr CoordinateTransformation
  213. # http://www.gdal.org/ogr/osr_tutorial.html
  214. geom = ogr.CreateGeometryFromWkt("""POINT(%s %s)""" % (layer.boundingBoxWGS84[0],layer.boundingBoxWGS84[1]),source)
  215. geom.TransformTo(dest)
  216. bbox.append(geom.GetX())
  217. bbox.append(geom.GetY())
  218. geom = ogr.CreateGeometryFromWkt("""POINT(%s %s)""" % (layer.boundingBoxWGS84[2],layer.boundingBoxWGS84[3]),source)
  219. geom.TransformTo(dest)
  220. bbox.append(geom.GetX())
  221. bbox.append(geom.GetY())
  222. logging.debug("Setting extent for layer <%s> to %s" %\
  223. (layer.id,bbox))
  224. return bbox
  225. def setFilter(self,mapobj,request):
  226. """ Set WFS filter encoding
  227. """
  228. # get the layer
  229. layerobj = mapobj.getLayerByName(request.getValueByName("layers"))
  230. # get the filter
  231. fes = request.getValueByName("fes")
  232. logging.debug("FES received from HSLayers: %s" % fes)
  233. # cut off the opening and closing <Filter> tag
  234. # - this is needed for mapserver
  235. root = etree.XML(fes)
  236. msFilter = ""
  237. for child in root:
  238. msFilter += etree.tostring(child)
  239. logging.debug("Setting the filter %s" % msFilter)
  240. # set the filter
  241. layerobj.setMetaData("wfs_filter",msFilter)
  242. def getService():
  243. qstring = os.environ["QUERY_STRING"]
  244. params = urlparse.parse_qs(qstring)
  245. for p in params:
  246. if p.lower() == "owsurl":
  247. v = params[p]
  248. del params[p]
  249. params["owsUrl"] = v
  250. if p.lower() == "owsservice":
  251. v = params[p]
  252. del params[p]
  253. params["owsService"] = v
  254. if "owsUrl" in params.keys() and\
  255. "owsService" in params.keys():
  256. owsUrl = urllib.unquote(params["owsUrl"][0])
  257. if params["owsService"][0].lower() == "wfs":
  258. from wfs import WFS
  259. logging.debug("OWS.py::getService()::owsUrl: '%s'" % owsUrl)
  260. return WFS(owsUrl,qstring)
  261. elif params["owsService"][0].lower() == "wcs":
  262. from wcs import WCS
  263. return WCS(owsUrl,qstring)
  264. else:
  265. raise OWSExceptions.MissingParameterValue("""owsUrl or owsService""")