Skip to content

Commit

Permalink
[SERVER] Server refactoring and Python bindings/tests
Browse files Browse the repository at this point in the history
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 Jun 29, 2015
1 parent ab86897 commit 00fa636
Show file tree
Hide file tree
Showing 51 changed files with 2,601 additions and 490 deletions.
2 changes: 1 addition & 1 deletion python/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
43 changes: 43 additions & 0 deletions python/server/qgsconfigcache.sip
Original file line number Diff line number Diff line change
@@ -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();

};


53 changes: 53 additions & 0 deletions python/server/qgsserver.sip
Original file line number Diff line number Diff line change
@@ -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& );
};
7 changes: 6 additions & 1 deletion python/server/qgsserverinterface.sip
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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 */
Expand Down
121 changes: 121 additions & 0 deletions python/server/qgsserverprojectparser.sip
Original file line number Diff line number Diff line change
@@ -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;

};

68 changes: 68 additions & 0 deletions python/server/qgswcserver.sip
Original file line number Diff line number Diff line change
@@ -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
38 changes: 38 additions & 0 deletions python/server/qgswcsprojectparser.sip
Original file line number Diff line number Diff line change
@@ -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;

};

Loading

6 comments on commit 00fa636

@nyalldawson
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@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
Copy link
Contributor Author

@elpaso elpaso commented on 00fa636 Jul 2, 2015

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

@jef-n
Copy link
Member

@jef-n jef-n commented on 00fa636 Jul 2, 2015

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@elpaso
Copy link
Contributor Author

@elpaso elpaso commented on 00fa636 Jul 2, 2015

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@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
Copy link
Member

@jef-n jef-n commented on 00fa636 Jul 2, 2015

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does it build on windows now?

@elpaso
Copy link
Contributor Author

@elpaso elpaso commented on 00fa636 Jul 3, 2015

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@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.