Skip to content
Permalink
Browse files

[SERVER] Server refactoring and Python bindings/tests

This is a refactoring of the server component, the
server is now wrapped into a new QgsServer class with
python bindings and an examples python test.
  • Loading branch information
elpaso committed May 29, 2015
1 parent ab86897 commit 00fa63618bb2cbad3359287b2103f897be315106
Showing with 2,601 additions and 490 deletions.
  1. +1 −1 python/CMakeLists.txt
  2. +43 −0 python/server/qgsconfigcache.sip
  3. +53 −0 python/server/qgsserver.sip
  4. +6 −1 python/server/qgsserverinterface.sip
  5. +121 −0 python/server/qgsserverprojectparser.sip
  6. +68 −0 python/server/qgswcserver.sip
  7. +38 −0 python/server/qgswcsprojectparser.sip
  8. +125 −0 python/server/qgswfserver.sip
  9. +47 −0 python/server/qgswfsprojectparser.sip
  10. +125 −0 python/server/qgswmsconfigparser.sip
  11. +111 −0 python/server/qgswmserver.sip
  12. +151 −0 python/server/qgswmsprojectparser.sip
  13. +13 −1 python/server/server.sip
  14. +12 −3 src/server/CMakeLists.txt
  15. +6 −426 src/server/qgis_map_serv.cpp
  16. +1 −1 src/server/qgsconfigcache.h
  17. +2 −2 src/server/qgsgetrequesthandler.cpp
  18. +1 −1 src/server/qgsgetrequesthandler.h
  19. +70 −21 src/server/qgshttprequesthandler.cpp
  20. +15 −2 src/server/qgshttprequesthandler.h
  21. +3 −1 src/server/qgspostrequesthandler.cpp
  22. +1 −1 src/server/qgspostrequesthandler.h
  23. +14 −4 src/server/qgsrequesthandler.h
  24. +588 −0 src/server/qgsserver.cpp
  25. +117 −0 src/server/qgsserver.h
  26. +2 −2 src/server/qgsserverfilter.cpp
  27. +3 −3 src/server/qgsserverfilter.h
  28. +2 −1 src/server/qgsserverinterface.cpp
  29. +9 −5 src/server/qgsserverinterface.h
  30. +6 −1 src/server/qgsserverinterfaceimpl.cpp
  31. +5 −2 src/server/qgsserverinterfaceimpl.h
  32. +3 −0 src/server/qgsserverplugins.cpp
  33. +3 −1 src/server/qgsserverplugins.h
  34. +1 −1 src/server/qgsserverprojectparser.h
  35. +2 −3 src/server/qgssoaprequesthandler.cpp
  36. +1 −1 src/server/qgssoaprequesthandler.h
  37. +1 −1 src/server/qgswcsprojectparser.h
  38. +1 −1 src/server/qgswfsprojectparser.h
  39. +1 −1 src/server/qgswmsconfigparser.h
  40. +1 −1 src/server/qgswmsprojectparser.h
  41. +1 −1 src/server/qgswmsserver.cpp
  42. +3 −0 tests/src/python/CMakeLists.txt
  43. +119 −0 tests/src/python/test_qgsserver.py
  44. +133 −0 tests/testdata/qgis_server/getcapabilities.txt
  45. +152 −0 tests/testdata/qgis_server/getprojectsettings.txt
  46. BIN tests/testdata/qgis_server/testlayer.dbf
  47. +1 −0 tests/testdata/qgis_server/testlayer.prj
  48. +1 −0 tests/testdata/qgis_server/testlayer.qpj
  49. BIN tests/testdata/qgis_server/testlayer.shp
  50. BIN tests/testdata/qgis_server/testlayer.shx
  51. +418 −0 tests/testdata/qgis_server/testproject.qgs
@@ -182,7 +182,7 @@ IF (WITH_SERVER AND WITH_SERVER_PLUGINS)
SET(PY_MODULES ${PY_MODULES} server)

FILE(GLOB sip_files_server
server/*.sip
server/server.sip
)
SET(SIP_EXTRA_FILES_DEPEND ${sip_files_core} ${sip_files_server})
SET(SIP_EXTRA_OPTIONS ${PYQT4_SIP_FLAGS} -o -a ${CMAKE_BINARY_DIR}/python/qgis.server.api)
@@ -0,0 +1,43 @@
/***************************************************************************
qgsconfigcache.sip
-------------------
begin : 2015-05-19
copyright : (C) 2015 by Alessandro Pasotti
email : a dot pasotti at itopen dot it
***************************************************************************/

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

/**
* \class QgsConfigCache
* \brief A cache for xml documents (by configuration file path)
*/


class QgsConfigCache: QObject
{
%TypeHeaderCode
#include "qgsconfigcache.h"
%End
public:
static QgsConfigCache* instance();
~QgsConfigCache();

QgsServerProjectParser* serverConfiguration( const QString& filePath );
QgsWCSProjectParser* wcsConfiguration( const QString& filePath );
QgsWFSProjectParser* wfsConfiguration( const QString& filePath );
QgsWMSConfigParser* wmsConfiguration( const QString& filePath, const QMap<QString, QString>& parameterMap = QMap< QString, QString >() );

private:
QgsConfigCache();

};


@@ -0,0 +1,53 @@
/***************************************************************************
qgsserver.sip
Qgis Mapserver
-------------------
begin : 2015-05-21
copyright : (C) 2015 by Alessandro Pasotti
email : a dot pasotti at itopen dot it
***************************************************************************/

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/



class QgsServer
{
%TypeHeaderCode
#include "qgsserver.h"
%End

public:
QgsServer();
~QgsServer();
// Original init for the fcgi application:
//void init( int argc, char* argv[] );
// init for python bindings:
void init( );
QByteArray handleRequest( const QString queryString = QString( ) );
// TODO: if HAVE_SERVER_PYTHON
QByteArray handleRequest( const QString queryString,
const bool returnHeaders,
const bool returnBody );
QByteArray handleRequestGetBody( const QString queryString = QString( ) );
QByteArray handleRequestGetHeaders( const QString queryString = QString( ) );
//QgsServerContext& serverContext ( ) /KeepReference/;
%If (HAVE_SERVER_PYTHON_PLUGINS)
QgsServerInterface* serverInterface( );
// Needs %MethodCode
//QMultiMap<int, QgsServerFilter*> pluginFilters( );
%End

// The following is needed because otherwise SIP fails trying to create copy
// ctor
private:
QgsServer( const QgsServer& );
QgsServer & operator=( const QgsServer& );
};
@@ -1,7 +1,7 @@
/***************************************************************************
qgsserverinterface.sip

Class defining the interface made available to server plugins.
Class defining the interface made available to QGIS Server plugins.
-------------------
begin : 2014-09-10
copyright : (C) 2014 by Alessandro Pasotti
@@ -51,6 +51,11 @@ class QgsServerInterface
// Commented because of problems with typedef QgsServerFiltersMap, provided
// methods to alter the filters map into QgsRequestHandler API
// virtual QgsServerFiltersMap filters( ) = 0;
/** Returns the configFilePath as seen by the server, this value is only
* available after requestReady has been called.*/
virtual QString configFilePath( ) = 0;
/** Set the config file path */
virtual void setConfigFilePath( QString configFilePath) = 0;

private:
/** Constructor */
@@ -0,0 +1,121 @@
/***************************************************************************
qgsserverprojectparser.sip
------------------------
begin : March 2, 2015
copyright : (C) 2015 by Alessandro Pasotti
email : a dot pasotti at itopen dot it
***************************************************************************/

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/


class QgsServerProjectParser
{
%TypeHeaderCode
#include "qgsserverprojectparser.h"

%End
public:
/**Takes ownership of the document*/
QgsServerProjectParser( QDomDocument* xmlDoc, const QString& filePath );

QString projectPath();

const QDomDocument* xmlDocument();

/**Returns project layers by id*/
void projectLayerMap( QMap<QString, QgsMapLayer*>& layerMap ) const;

/**Converts a (possibly relative) path to absolute*/
QString convertToAbsolutePath( const QString& file ) const;

/**Creates a maplayer object from <maplayer> element. The layer cash owns the maplayer, so don't delete it
@return the maplayer or 0 in case of error*/
QgsMapLayer* createLayerFromElement( const QDomElement& elem, bool useCache = true ) const;

QgsMapLayer* mapLayerFromLayerId( const QString& lId, bool useCache = true ) const;

/**Returns the layer id under a <legendlayer> tag in the QGIS projectfile*/
QString layerIdFromLegendLayer( const QDomElement& legendLayer ) const;

/**@param considerMapExtent Take user-defined map extent instead of data-calculated extent if present in project file*/
void combineExtentAndCrsOfGroupChildren( QDomElement& groupElement, QDomDocument& doc, bool considerMapExtent = false ) const;

void addLayerProjectSettings( QDomElement& layerElem, QDomDocument& doc, QgsMapLayer* currentLayer ) const;

QgsRectangle layerBoundingBoxInProjectCRS( const QDomElement& layerElem, const QDomDocument &doc ) const;

bool crsSetForLayer( const QDomElement& layerElement, QSet<QString> &crsSet ) const;

const QgsCoordinateReferenceSystem& projectCRS() const;

QgsRectangle mapRectangle() const;

QStringList supportedOutputCrsList() const;

const QList<QDomElement>& projectLayerElements() const;

const QList<QDomElement>& legendGroupElements() const;

QString projectTitle() const;

QDomElement legendElem() const;

QDomElement propertiesElem() const;

const QSet<QString>& restrictedLayers() const;
bool useLayerIDs() const;

const QHash< QString, QDomElement >& projectLayerElementsByName() const;
const QHash< QString, QDomElement >& projectLayerElementsById() const;

// SIP doesn't like QMap:
// void layerFromLegendLayer( const QDomElement& legendLayerElem, QMap< int, QgsMapLayer*>& layers, bool useCache = true ) const;

QStringList wfsLayerNames() const;
QStringList wcsLayerNames() const;

QDomElement firstComposerLegendElement() const;

QList<QDomElement> publishedComposerElements() const;

//QList< QPair< QString, QgsLayerCoordinateTransform > > layerCoordinateTransforms() const;

/**Returns the text of the <layername> element for a layer element
@return id or a null string in case of error*/
QString layerName( const QDomElement& layerElem ) const;

QString serviceUrl() const;
QString wfsServiceUrl() const;
QString wcsServiceUrl() const;

QStringList wfsLayers() const;
QStringList wcsLayers() const;

void addJoinLayersForElement( const QDomElement& layerElem ) const;

void addValueRelationLayersForLayer( const QgsVectorLayer *vl ) const;
/**Add layers which are necessary for the evaluation of the expression function 'getFeature( layer, attributField, value)'*/
void addGetFeatureLayers( const QDomElement& layerElem ) const;

/**Returns the text of the <id> element for a layer element
@return id or a null string in case of error*/
QString layerId( const QDomElement& layerElem ) const;

QgsRectangle projectExtent() const;

int numberOfLayers() const;

bool updateLegendDrawingOrder() const;

void serviceCapabilities( QDomElement& parentElement, QDomDocument& doc, const QString& service, bool sia2045 = false ) const;

};

@@ -0,0 +1,68 @@
/***************************************************************************
qgswcsserver.h
-------------------
begin : December 9, 2013
copyright : (C) 2013 by René-Luc D'Hont
email : rldhont at 3liz dot com
***************************************************************************/

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#ifndef QGSWCSSERVER_H
#define QGSWCSSERVER_H

#include <QDomDocument>
#include <QMap>
#include <QString>
#include <map>
#include "qgis.h"
#include "qgsowsserver.h"

class QgsWCSProjectParser;
class QgsRequestHandler;

/**This class handles all the wcs server requests. The parameters and values have to be passed in the form of
a map<QString, QString>. This map is usually generated by a subclass of QgsWMSRequestHandler, which makes QgsWCSServer
independent from any server side technology*/

class QgsWCSServer: public QgsOWSServer
{
public:
/**Constructor. Takes parameter map and a pointer to a renderer object (does not take ownership)*/
QgsWCSServer( const QString& configFilePath, QMap<QString, QString>& parameters, QgsWCSProjectParser* pp,
QgsRequestHandler* rh );
~QgsWCSServer();

void executeRequest() override;

/**Returns an XML file with the capabilities description (as described in the WFS specs)*/
QDomDocument getCapabilities();

/**Returns an XML file with the describe Coverage (as described in the WCS specs)*/
QDomDocument describeCoverage();

/**Creates a file which is the result of the getCoverage request.*/
QByteArray* getCoverage();

/**Sets configuration parser for administration settings. Does not take ownership*/
void setAdminConfigParser( QgsWCSProjectParser* parser ) { mConfigParser = parser; }

private:
/**Don't use the default constructor*/
QgsWCSServer();

/**Get service address from REQUEST_URI if not specified in the configuration*/
QString serviceUrl() const;

QgsWCSProjectParser* mConfigParser;

};

#endif
@@ -0,0 +1,38 @@
/***************************************************************************
qgswcsprojectparser.h
------------------------
begin : May 2, 2015
copyright : (C) 2015 by Alessandro Pasotti
email : a dot pasotti at itopen dot it
***************************************************************************/

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/


class QgsWCSProjectParser
{
%TypeHeaderCode
#include "qgswcsprojectparser.h"

%End
public:
QgsWCSProjectParser( const QString& filePath );
~QgsWCSProjectParser();

void serviceCapabilities( QDomElement& parentElement, QDomDocument& doc ) const;
QString wcsServiceUrl() const;
QString serviceUrl() const;
void wcsContentMetadata( QDomElement& parentElement, QDomDocument& doc ) const;
QStringList wcsLayers() const;
void describeCoverage( const QString& aCoveName, QDomElement& parentElement, QDomDocument& doc ) const;
QList<QgsMapLayer*> mapLayerFromCoverage( const QString& cName, bool useCache = true ) const;

};

6 comments on commit 00fa636

@nyalldawson

This comment has been minimized.

Copy link
Collaborator

@nyalldawson nyalldawson replied Jul 2, 2015

@elpaso I've had to disable this test on Travis - it was proving to be very flaky and fails about half the time for no apparent reason. Are you able to investigate what's happening so that we can reenable it?

@elpaso

This comment has been minimized.

Copy link
Contributor Author

@elpaso elpaso replied Jul 2, 2015

@nyalldawson can you give some more informations on the failures? It works fine for me.

@elpaso

This comment has been minimized.

Copy link
Contributor Author

@elpaso elpaso replied Jul 2, 2015

@nyalldawson: Fixed in PR #2190, sorry @jef-n I had to revert you setenv/putenv commit which was the reason for some ugly random failures and some repeatable test failures which you "fixed" patching the test (the ampersand regex).
Some other test failures were due to a couple of real fixes introduced by @mhugent , I've updated the reference getcapabilities e and getprojectsettings output documents.

@jef-n

This comment has been minimized.

Copy link
Member

@jef-n jef-n replied Jul 2, 2015

does it build on windows now?

@elpaso

This comment has been minimized.

Copy link
Contributor Author

@elpaso elpaso replied Jul 3, 2015

@jef-n no idea. Can't you just re-add your patch with an #ifdef for win build? Make sure the test passes on windows.

UPDATE: just seen you've already done that.

Please sign in to comment.
You can’t perform that action at this time.