QGIS server python plugins

Python plugins support for QGIS server was finally merged and brings a full set of amazing possibilities for new services implementations

  Today it’s a great day for QGIS Server: Python plugins, the project that took me busy during the past two months, has been merged to master and will be available starting with the next QGIS release. The project has been discussed and approved in Essen during the last QGIS HF (see my presentation about server plugins), thanks to the input and suggestions coming from Marco Hugentobler and Martin Dobias it is now implemented in the more complete and flexible way. In this article I will introduce the core concepts and the main features of python plugins for QGIS server.

QGIS server plugins architecture

QGIS server provides some core services: WFS, WMS, WCS. What we wanted to achieve was a system to easily add new services and modify existing services through python plugins. Mi first experiments were limited to a 404 handler that intercepts unhandled requests and hooks into python plugins capturing every stdout output, this was indeed not enough flexible for a full fledged plugins implementation.

The main loop

QGIS server is not different from most web services implementations: it listens for incoming requests, parses the URL query string parameters and returns its output accordingly to the incoming request. The standard loop before introducing python plugins looked like the following:
  • Get the request
    • create GET/POST/SOAP request handler
    • if SERVICE is WMS/WFS/WCS
      • create WMS/WFS/WCS server passing in request handler
        • call server’s executeRequest()
          • call request handler output method
    • else Exception

Plugins come into play

Server python plugins are loaded once when the FCGI application starts and they should register one or more QgsServerFilter (from this point, you might find useful a quick look to the server plugins API docs). Each filter should implement at least one of three callbacks (aka: hooks):
    1. requestReady
    2. sendResponse
    3. responseComplete
All filters have access to the request/response object (QgsRequestHandler) and can manipulate all its properties (input/output) and can raise exceptions (while in a quite particular way as we’ll see below). Here is a pseudo code showing how and when the filter’s callbacks are called:
  • Get the request
    • create GET/POST/SOAP request handler
    • pass request to serverIface
    • call plugins requestReady filters
    • if there is not a response
      • if SERVICE is WMS/WFS/WCS
        • create WMS/WFS/WCS server
          • call server’s executeRequest and possibily call sendResponse plugin filters when streaming output or store the byte stream output and content type in the request handler
      • call plugins responseComplete filters
    • call plugins sendResponse filters

    • request handler output the response

requestReady

This is called when the request is ready: incoming URL and data have been parsed and before entering the core services (WMS, WFS etc.) switch, this is the point where you can manipulate the input and perform actions like:
  • authentication/authorization
  • redirects
  • add/remove certain parameters (typenames for example)
  • raise exceptions
You could even substitute a core service completely by changing SERVICE parameter and hence bypassing the core service completely (not that this make much sense though).
Implementation details of server plugins will be discussed in depth in a future article, by now please refer to  QGIS HelloServer plugin for a complete implementation of the examples and methods cited in this article.
 

sendResponse

This is called whenever output is sent to FCGI stdout (and from there, to the client), this is normally done after core services have finished their process and after responseComplete hook was called, but in a few cases XML can become so huge that a streaming XML implementation was needed (WFS GetFeature is one of them), in this case, sendResponse is called multiple times before the response is complete (and before responseComplete is called). The obvious consequence is that sendResponse is normally called once but might be exceptionally called multiple times and in that case (and only in that case) it is also called before responseComplete. SendResponse is the best place for direct manipulation of core service’s output and while responseComplete is typically also an option, sendResponse is the only viable option  in case of streaming services.

responseComplete

This is called once when core services (if hit) finish their process and the request is ready to be sent to the client. As discussed above, this is  normally called before sendResponse except for streaming services (or other plugin filters) that might have called sendResponse earlier. responseComplete is the ideal place to provide new services implementation (WPS or custom services) and to perform direct manipulation of the output coming from core services (for example to add a watermark upon a WMS image).

Raising exception from a plugin

Some work has still to be done on this topic: the current implementation can distinguish between handled and unhandled exceptions by setting a QgsRequestHandler property to an instance of QgsMapServiceException, this way the main C++ code can catch handled python exceptions and ignore unhandled exceptions (or better: log them). This approach basically works but it does not satisfy my pythonic way of handle exceptions: I would rather prefer to raise exceptions from python code to see them bubbling up into C++ loop for being handled there.

Conclusions

The new plugin system is very flexible and allows for basic input/output (i.e. request/response) manipulation and for new services implementation while it remains unobtrusive and has negligible impact on performances, in the next article I will discuss server plugin implementation in depth.  

See also the second part of this article.

See all QGIS Server related posts

Trackbacks/Pingbacks

  1.  QGIS server python plugins tutorial | ItOpen - Open Web Solutions, WebGis Development