Skip to content

Commit 1e8aec4

Browse files
authored
Merge pull request #9385 from pblottiere/server_external_clean
[server] Update external layer management
2 parents 477ec2a + 63c0278 commit 1e8aec4

File tree

8 files changed

+151
-32
lines changed

8 files changed

+151
-32
lines changed

src/server/services/wms/qgswmsparameters.cpp

+56-2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
#include "qgsdatasourceuri.h"
2020
#include "qgsmessagelog.h"
2121

22+
const QString EXTERNAL_LAYER_PREFIX = QStringLiteral( "EXTERNAL_WMS:" );
23+
2224
namespace QgsWms
2325
{
2426
//
@@ -1408,6 +1410,10 @@ namespace QgsWms
14081410
for ( int i = 0; i < layers.size(); i++ )
14091411
{
14101412
QString layer = layers[i];
1413+
1414+
if ( isExternalLayer( layer ) )
1415+
continue;
1416+
14111417
QgsWmsParametersLayer param;
14121418
param.mNickname = layer;
14131419

@@ -1492,6 +1498,21 @@ namespace QgsWms
14921498
return params;
14931499
}
14941500

1501+
QList<QgsWmsParametersExternalLayer> QgsWmsParameters::externalLayersParameters() const
1502+
{
1503+
QList<QgsWmsParametersExternalLayer> externalLayers;
1504+
1505+
QStringList layers = allLayersNickname();
1506+
QStringList::const_iterator rit = std::remove_if( layers.begin(), layers.end(), QgsWmsParameters::isExternalLayer );
1507+
1508+
for ( QStringList::const_iterator it = layers.begin(); it != rit; ++it )
1509+
{
1510+
externalLayers << externalLayerParameter( *it );
1511+
}
1512+
1513+
return externalLayers;
1514+
}
1515+
14951516
QString QgsWmsParameters::backgroundColor() const
14961517
{
14971518
return mWmsParameters[ QgsWmsParameter::BGCOLOR ].toString();
@@ -1577,13 +1598,30 @@ namespace QgsWms
15771598
}
15781599

15791600
//layers
1580-
QStringList layers;
1601+
QStringList allLayers;
15811602
wmsParam = idParameter( QgsWmsParameter::LAYERS, mapId );
15821603
if ( wmsParam.isValid() )
15831604
{
1584-
layers = wmsParam.toStringList();
1605+
allLayers = wmsParam.toStringList();
15851606
}
15861607

1608+
// external layers
1609+
QStringList layers;
1610+
QList<QgsWmsParametersExternalLayer> eParams;
1611+
1612+
for ( const auto &layer : qgis::as_const( allLayers ) )
1613+
{
1614+
if ( isExternalLayer( layer ) )
1615+
{
1616+
eParams << externalLayerParameter( layer );
1617+
}
1618+
else
1619+
{
1620+
layers << layer;
1621+
}
1622+
}
1623+
param.mExternalLayers = eParams;
1624+
15871625
QStringList styles;
15881626
wmsParam = idParameter( QgsWmsParameter::STYLES, mapId );
15891627
if ( wmsParam.isValid() )
@@ -1763,4 +1801,20 @@ namespace QgsWms
17631801

17641802
return p;
17651803
}
1804+
1805+
QgsWmsParametersExternalLayer QgsWmsParameters::externalLayerParameter( const QString &name ) const
1806+
{
1807+
QgsWmsParametersExternalLayer param;
1808+
1809+
param.mName = name;
1810+
param.mName.remove( 0, EXTERNAL_LAYER_PREFIX.size() );
1811+
param.mUri = externalWMSUri( param.mName );
1812+
1813+
return param;
1814+
}
1815+
1816+
bool QgsWmsParameters::isExternalLayer( const QString &name )
1817+
{
1818+
return name.startsWith( EXTERNAL_LAYER_PREFIX );
1819+
}
17661820
}

src/server/services/wms/qgswmsparameters.h

+17
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@ namespace QgsWms
5555
QString mStyle;
5656
};
5757

58+
struct QgsWmsParametersExternalLayer
59+
{
60+
QString mName;
61+
QString mUri;
62+
};
63+
5864
struct QgsWmsParametersHighlightLayer
5965
{
6066
QString mName;
@@ -79,6 +85,7 @@ namespace QgsWms
7985
float mGridX = 0;
8086
float mGridY = 0;
8187
QList<QgsWmsParametersLayer> mLayers; // list of layers for this composer map
88+
QList<QgsWmsParametersExternalLayer> mExternalLayers; // list of external layers for this composer map
8289
QList<QgsWmsParametersHighlightLayer> mHighlightLayers; // list of highlight layers for this composer map
8390
};
8491

@@ -944,6 +951,12 @@ namespace QgsWms
944951
*/
945952
QList<QgsWmsParametersHighlightLayer> highlightLayersParameters() const;
946953

954+
/**
955+
* Returns parameters for each external layer.
956+
* \since QGIS 3.8
957+
*/
958+
QList<QgsWmsParametersExternalLayer> externalLayersParameters() const;
959+
947960
/**
948961
* Returns HIGHLIGHT_GEOM as a list of string in WKT.
949962
* \returns highlight geometries
@@ -1165,6 +1178,8 @@ namespace QgsWms
11651178
QStringList atlasPk() const;
11661179

11671180
private:
1181+
static bool isExternalLayer( const QString &name );
1182+
11681183
bool loadParameter( const QString &name, const QString &value ) override;
11691184

11701185
void save( const QgsWmsParameter &parameter, bool multi = false );
@@ -1174,6 +1189,8 @@ namespace QgsWms
11741189
void raiseError( const QString &msg ) const;
11751190
void log( const QString &msg ) const;
11761191

1192+
QgsWmsParametersExternalLayer externalLayerParameter( const QString &name ) const;
1193+
11771194
QMultiMap<QString, QgsWmsParametersFilter> layerFilters( const QStringList &layers ) const;
11781195

11791196
QMap<QgsWmsParameter::Name, QgsWmsParameter> mWmsParameters;

src/server/services/wms/qgswmsrenderer.cpp

+25-27
Original file line numberDiff line numberDiff line change
@@ -653,13 +653,14 @@ namespace QgsWms
653653

654654
if ( !map->keepLayerSet() )
655655
{
656-
if ( cMapParams.mLayers.isEmpty() )
656+
if ( cMapParams.mLayers.isEmpty() && cMapParams.mExternalLayers.isEmpty() )
657657
{
658658
map->setLayers( mapSettings.layers() );
659659
}
660660
else
661661
{
662662
QList<QgsMapLayer *> layerSet = stylizedLayers( cMapParams.mLayers );
663+
layerSet << externalLayers( cMapParams.mExternalLayers );
663664
layerSet << highlightLayers( cMapParams.mHighlightLayers );
664665
std::reverse( layerSet.begin(), layerSet.end() );
665666
map->setLayers( layerSet );
@@ -856,6 +857,9 @@ namespace QgsWms
856857
setLayerAccessControlFilter( layer );
857858
}
858859

860+
// add external layers
861+
layers = layers << externalLayers( mWmsParameters.externalLayersParameters() );
862+
859863
// add highlight layers above others
860864
layers = layers << highlightLayers( mWmsParameters.highlightLayersParameters() );
861865

@@ -2914,6 +2918,25 @@ namespace QgsWms
29142918
return highlightLayers;
29152919
}
29162920

2921+
QList<QgsMapLayer *> QgsRenderer::externalLayers( const QList<QgsWmsParametersExternalLayer> &params )
2922+
{
2923+
QList<QgsMapLayer *> layers;
2924+
2925+
for ( const QgsWmsParametersExternalLayer &param : params )
2926+
{
2927+
std::unique_ptr<QgsMapLayer> layer = qgis::make_unique< QgsRasterLayer >( param.mUri, param.mName, QStringLiteral( "wms" ) );
2928+
2929+
if ( layer->isValid() )
2930+
{
2931+
// to delete later
2932+
mTemporaryLayers.append( layer.release() );
2933+
layers << mTemporaryLayers.last();
2934+
}
2935+
}
2936+
2937+
return layers;
2938+
}
2939+
29172940
QList<QgsMapLayer *> QgsRenderer::sldStylizedLayers( const QString &sld ) const
29182941
{
29192942
QList<QgsMapLayer *> layers;
@@ -2976,19 +2999,7 @@ namespace QgsWms
29762999
{
29773000
QString nickname = param.mNickname;
29783001
QString style = param.mStyle;
2979-
if ( nickname.startsWith( "EXTERNAL_WMS:" ) )
2980-
{
2981-
QString externalLayerId = nickname;
2982-
externalLayerId.remove( 0, 13 );
2983-
QgsMapLayer *externalWMSLayer = createExternalWMSLayer( externalLayerId );
2984-
if ( externalWMSLayer )
2985-
{
2986-
layers.append( externalWMSLayer );
2987-
mNicknameLayers[nickname] = externalWMSLayer; //might be used later in GetPrint request
2988-
mTemporaryLayers.append( externalWMSLayer );
2989-
}
2990-
}
2991-
else if ( mNicknameLayers.contains( nickname ) && !mRestrictedLayers.contains( nickname ) )
3002+
if ( mNicknameLayers.contains( nickname ) && !mRestrictedLayers.contains( nickname ) )
29923003
{
29933004
if ( !style.isEmpty() )
29943005
{
@@ -3032,19 +3043,6 @@ namespace QgsWms
30323043
return layers;
30333044
}
30343045

3035-
QgsMapLayer *QgsRenderer::createExternalWMSLayer( const QString &externalLayerId ) const
3036-
{
3037-
QString wmsUri = mWmsParameters.externalWMSUri( externalLayerId.toUpper() );
3038-
QgsMapLayer *wmsLayer = new QgsRasterLayer( wmsUri, externalLayerId, QStringLiteral( "wms" ) );
3039-
if ( !wmsLayer->isValid() )
3040-
{
3041-
delete wmsLayer;
3042-
return nullptr;
3043-
}
3044-
3045-
return wmsLayer;
3046-
}
3047-
30483046
void QgsRenderer::removeTemporaryLayers()
30493047
{
30503048
qDeleteAll( mTemporaryLayers );

src/server/services/wms/qgswmsrenderer.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,9 @@ namespace QgsWms
122122
// Build and returns highlight layers
123123
QList<QgsMapLayer *> highlightLayers( QList<QgsWmsParametersHighlightLayer> params );
124124

125+
// Build and returns external layers
126+
QList<QgsMapLayer *> externalLayers( const QList<QgsWmsParametersExternalLayer> &params );
127+
125128
// Init a map with nickname for layers' project
126129
void initNicknameLayers();
127130

@@ -289,9 +292,6 @@ namespace QgsWms
289292
* */
290293
bool configurePrintLayout( QgsPrintLayout *c, const QgsMapSettings &mapSettings, bool atlasPrint = false );
291294

292-
//! Creates external WMS layer. Caller takes ownership
293-
QgsMapLayer *createExternalWMSLayer( const QString &externalLayerId ) const;
294-
295295
void removeTemporaryLayers();
296296

297297
void handlePrintErrors( const QgsLayout *layout ) const;

tests/src/python/test_qgsserver_wms_getmap.py

+26
Original file line numberDiff line numberDiff line change
@@ -1457,6 +1457,32 @@ def test_wms_getmap_datasource_error(self):
14571457

14581458
self.assertTrue('ServerException' in str(r))
14591459

1460+
@unittest.skipIf(os.environ.get('TRAVIS', '') == 'true', 'Can\'t rely on external resources for continuous integration')
1461+
def test_wms_getmap_external(self):
1462+
# 1 bits
1463+
qs = "?" + "&".join(["%s=%s" % i for i in list({
1464+
"MAP": urllib.parse.quote(self.projectPath),
1465+
"SERVICE": "WMS",
1466+
"REQUEST": "GetMap",
1467+
"LAYERS": "EXTERNAL_WMS:landsat",
1468+
"landsat:layers": "GEBCO_LATEST",
1469+
"landsat:dpiMode": "7",
1470+
"landsat:url": "https://www.gebco.net/data_and_products/gebco_web_services/web_map_service/mapserv",
1471+
"landsat:crs": "EPSG:4326",
1472+
"landsat:styles": "default",
1473+
"landsat:format": "image/jpeg",
1474+
"landsat:bbox": "-90,-180,90,180",
1475+
"landsat:version": "1.3.0",
1476+
"STYLES": "",
1477+
"BBOX": "-90,-180,90,180",
1478+
"HEIGHT": "500",
1479+
"WIDTH": "500",
1480+
"CRS": "EPSG:4326"
1481+
}.items())])
1482+
1483+
r, h = self._result(self._execute_request(qs))
1484+
self._img_diff_error(r, h, "WMS_GetMap_External", 20000)
1485+
14601486

14611487
if __name__ == '__main__':
14621488
unittest.main()

tests/src/python/test_qgsserver_wms_getprint.py

+24
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,30 @@ def test_wms_getprint_atlas_getProjectSettings(self):
437437
self.assertTrue('atlasEnabled="1"' in str(r))
438438
self.assertTrue('<PrimaryKeyAttribute>' in str(r))
439439

440+
@unittest.skipIf(os.environ.get('TRAVIS', '') == 'true', 'Can\'t rely on external resources for continuous integration')
441+
def test_wms_getprint_external(self):
442+
qs = "?" + "&".join(["%s=%s" % i for i in list({
443+
"MAP": urllib.parse.quote(self.projectPath),
444+
"SERVICE": "WMS",
445+
"VERSION": "1.1.1",
446+
"REQUEST": "GetPrint",
447+
"TEMPLATE": "layoutA4",
448+
"map0:EXTENT": "-90,-180,90,180",
449+
"map0:LAYERS": "EXTERNAL_WMS:landsat",
450+
"landsat:layers": "GEBCO_LATEST",
451+
"landsat:dpiMode": "7",
452+
"landsat:url": "https://www.gebco.net/data_and_products/gebco_web_services/web_map_service/mapserv",
453+
"landsat:crs": "EPSG:4326",
454+
"landsat:styles": "default",
455+
"landsat:format": "image/jpeg",
456+
"landsat:bbox": "-90,-180,90,180",
457+
"landsat:version": "1.3.0",
458+
"CRS": "EPSG:4326"
459+
}.items())])
460+
461+
r, h = self._result(self._execute_request(qs))
462+
self._img_diff_error(r, h, "WMS_GetPrint_External")
463+
440464

441465
if __name__ == '__main__':
442466
unittest.main()
Loading
Loading

0 commit comments

Comments
 (0)