Skip to content

Commit 09e9df1

Browse files
committedMar 27, 2019
Add WMS render context
1 parent 51ab846 commit 09e9df1

File tree

3 files changed

+574
-0
lines changed

3 files changed

+574
-0
lines changed
 

‎src/server/services/wms/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ SET (wms_SRCS
2020
qgswmsrenderer.cpp
2121
qgswmsparameters.cpp
2222
qgslayerrestorer.cpp
23+
qgswmsrendercontext.cpp
2324
)
2425

2526
SET (wms_MOC_HDRS
Lines changed: 454 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,454 @@
1+
/***************************************************************************
2+
qgswmsrendercontext.cpp
3+
---------------------
4+
begin : March 22, 2019
5+
copyright : (C) 2019 by Paul Blottiere
6+
email : paul.blottiere@oslandia.com
7+
***************************************************************************/
8+
9+
/***************************************************************************
10+
* *
11+
* This program is free software; you can redistribute it and/or modify *
12+
* it under the terms of the GNU General Public License as published by *
13+
* the Free Software Foundation; either version 2 of the License, or *
14+
* (at your option) any later version. *
15+
* *
16+
***************************************************************************/
17+
18+
#include "qgslayertree.h"
19+
20+
#include "qgswmsrendercontext.h"
21+
#include "qgsserverprojectutils.h"
22+
23+
using namespace QgsWms;
24+
25+
QgsWmsRenderContext::QgsWmsRenderContext( const QgsProject *project, QgsServerInterface *interface )
26+
: mProject( project )
27+
, mInterface( interface )
28+
, mFlags()
29+
{
30+
}
31+
32+
void QgsWmsRenderContext::setParameters( const QgsWmsParameters &parameters )
33+
{
34+
mParameters = parameters;
35+
36+
initRestrictedLayers();
37+
initNicknameLayers();
38+
39+
searchLayersToRender();
40+
removeUnwantedLayers();
41+
checkLayerReadPermissions();
42+
43+
std::reverse( mLayersToRender.begin(), mLayersToRender.end() );
44+
}
45+
46+
void QgsWmsRenderContext::setFlag( const Flag flag, const bool on )
47+
{
48+
if ( on )
49+
{
50+
mFlags |= flag;
51+
}
52+
else
53+
{
54+
mFlags &= ~flag;
55+
}
56+
}
57+
58+
bool QgsWmsRenderContext::testFlag( Flag flag ) const
59+
{
60+
return mFlags.testFlag( flag );
61+
}
62+
63+
QgsWmsParameters QgsWmsRenderContext::parameters() const
64+
{
65+
return mParameters;
66+
}
67+
68+
const QgsServerSettings &QgsWmsRenderContext::settings() const
69+
{
70+
return *mInterface->serverSettings();
71+
}
72+
73+
const QgsProject *QgsWmsRenderContext::project() const
74+
{
75+
return mProject;
76+
}
77+
78+
QDomElement QgsWmsRenderContext::sld( const QgsMapLayer &layer ) const
79+
{
80+
QDomElement sld;
81+
82+
const QString nickname = layerNickname( layer );
83+
if ( mSlds.contains( nickname ) )
84+
{
85+
sld = mSlds[ nickname ];
86+
}
87+
88+
return sld;
89+
}
90+
91+
QString QgsWmsRenderContext::style( const QgsMapLayer &layer ) const
92+
{
93+
QString style;
94+
95+
const QString nickname = layerNickname( layer );
96+
if ( mStyles.contains( nickname ) )
97+
{
98+
style = mStyles[ nickname ];
99+
}
100+
101+
return style;
102+
}
103+
104+
QgsWmsParametersLayer QgsWmsRenderContext::parameters( const QgsMapLayer &layer ) const
105+
{
106+
QgsWmsParametersLayer parameters;
107+
108+
for ( const auto &params : mParameters.layersParameters() )
109+
{
110+
if ( params.mNickname == layerNickname( layer ) )
111+
{
112+
parameters = params;
113+
break;
114+
}
115+
}
116+
117+
return parameters;
118+
}
119+
120+
QList<QgsMapLayer *> QgsWmsRenderContext::layersToRender() const
121+
{
122+
return mLayersToRender;
123+
}
124+
125+
QList<QgsMapLayer *> QgsWmsRenderContext::layers() const
126+
{
127+
return mNicknameLayers.values();
128+
}
129+
130+
double QgsWmsRenderContext::scaleDenominator() const
131+
{
132+
double denominator = -1;
133+
134+
if ( mScaleDenominator >= 0 )
135+
{
136+
denominator = mScaleDenominator;
137+
}
138+
else if ( mFlags & UseScaleDenominator && ! mParameters.scale().isEmpty() )
139+
{
140+
denominator = mParameters.scaleAsDouble();
141+
}
142+
143+
return denominator;
144+
}
145+
146+
void QgsWmsRenderContext::setScaleDenominator( double scaleDenominator )
147+
{
148+
mScaleDenominator = scaleDenominator;
149+
removeUnwantedLayers();
150+
}
151+
152+
bool QgsWmsRenderContext::updateExtent() const
153+
{
154+
bool update = false;
155+
156+
if ( mFlags & UpdateExtent && ! mParameters.bbox().isEmpty() )
157+
{
158+
update = true;
159+
}
160+
161+
return update;
162+
}
163+
164+
QString QgsWmsRenderContext::layerNickname( const QgsMapLayer &layer ) const
165+
{
166+
QString name = layer.shortName();
167+
if ( QgsServerProjectUtils::wmsUseLayerIds( *mProject ) )
168+
{
169+
name = layer.id();
170+
}
171+
else if ( name.isEmpty() )
172+
{
173+
name = layer.name();
174+
}
175+
176+
return name;
177+
}
178+
179+
void QgsWmsRenderContext::initNicknameLayers()
180+
{
181+
for ( QgsMapLayer *ml : mProject->mapLayers() )
182+
{
183+
mNicknameLayers[ layerNickname( *ml ) ] = ml;
184+
}
185+
186+
// init groups
187+
const QString rootName { QgsServerProjectUtils::wmsRootName( *mProject ) };
188+
const QgsLayerTreeGroup *root = mProject->layerTreeRoot();
189+
190+
initLayerGroupsRecursive( root, rootName.isEmpty() ? mProject->title() : rootName );
191+
}
192+
193+
void QgsWmsRenderContext::initLayerGroupsRecursive( const QgsLayerTreeGroup *group, const QString &groupName )
194+
{
195+
if ( !groupName.isEmpty() )
196+
{
197+
mLayerGroups[groupName] = QList<QgsMapLayer *>();
198+
for ( QgsLayerTreeLayer *layer : group->findLayers() )
199+
{
200+
mLayerGroups[groupName].append( layer->layer() );
201+
}
202+
}
203+
204+
for ( const QgsLayerTreeNode *child : group->children() )
205+
{
206+
if ( child->nodeType() == QgsLayerTreeNode::NodeGroup )
207+
{
208+
QString name = child->customProperty( QStringLiteral( "wmsShortName" ) ).toString();
209+
210+
if ( name.isEmpty() )
211+
name = child->name();
212+
213+
initLayerGroupsRecursive( static_cast<const QgsLayerTreeGroup *>( child ), name );
214+
215+
}
216+
}
217+
}
218+
219+
void QgsWmsRenderContext::initRestrictedLayers()
220+
{
221+
mRestrictedLayers.clear();
222+
223+
// get name of restricted layers/groups in project
224+
QStringList restricted = QgsServerProjectUtils::wmsRestrictedLayers( *mProject );
225+
226+
// extract restricted layers from excluded groups
227+
QStringList restrictedLayersNames;
228+
QgsLayerTreeGroup *root = mProject->layerTreeRoot();
229+
230+
for ( const QString &l : restricted )
231+
{
232+
QgsLayerTreeGroup *group = root->findGroup( l );
233+
if ( group )
234+
{
235+
QList<QgsLayerTreeLayer *> groupLayers = group->findLayers();
236+
for ( QgsLayerTreeLayer *treeLayer : groupLayers )
237+
{
238+
restrictedLayersNames.append( treeLayer->name() );
239+
}
240+
}
241+
else
242+
{
243+
restrictedLayersNames.append( l );
244+
}
245+
}
246+
247+
// build output with names, ids or short name according to the configuration
248+
QList<QgsLayerTreeLayer *> layers = root->findLayers();
249+
for ( QgsLayerTreeLayer *layer : layers )
250+
{
251+
if ( restrictedLayersNames.contains( layer->name() ) )
252+
{
253+
mRestrictedLayers.append( layerNickname( *layer->layer() ) );
254+
}
255+
}
256+
}
257+
258+
void QgsWmsRenderContext::searchLayersToRender()
259+
{
260+
mLayersToRender.clear();
261+
mStyles.clear();
262+
mSlds.clear();
263+
264+
if ( ! mParameters.sldBody().isEmpty() )
265+
{
266+
searchLayersToRenderSld();
267+
}
268+
else
269+
{
270+
searchLayersToRenderStyle();
271+
}
272+
273+
if ( mFlags & AddQueryLayers )
274+
{
275+
for ( const QString &layer : mParameters.queryLayersNickname() )
276+
{
277+
if ( mNicknameLayers.contains( layer )
278+
&& !mLayersToRender.contains( mNicknameLayers[layer] ) )
279+
{
280+
mLayersToRender.append( mNicknameLayers[layer] );
281+
}
282+
}
283+
}
284+
}
285+
286+
void QgsWmsRenderContext::searchLayersToRenderSld()
287+
{
288+
const QString sld = mParameters.sldBody();
289+
290+
if ( sld.isEmpty() )
291+
{
292+
return;
293+
}
294+
295+
QDomDocument doc;
296+
( void )doc.setContent( sld, true );
297+
QDomElement docEl = doc.documentElement();
298+
299+
QDomElement root = doc.firstChildElement( "StyledLayerDescriptor" );
300+
QDomElement namedElem = root.firstChildElement( "NamedLayer" );
301+
302+
if ( docEl.isNull() )
303+
{
304+
return;
305+
}
306+
307+
QDomNodeList named = docEl.elementsByTagName( "NamedLayer" );
308+
for ( int i = 0; i < named.size(); ++i )
309+
{
310+
QDomNodeList names = named.item( i ).toElement().elementsByTagName( "Name" );
311+
if ( !names.isEmpty() )
312+
{
313+
QString lname = names.item( 0 ).toElement().text();
314+
QString err;
315+
if ( mNicknameLayers.contains( lname ) )
316+
{
317+
mSlds[lname] = namedElem;
318+
mLayersToRender.append( mNicknameLayers[ lname ] );
319+
}
320+
else if ( mLayerGroups.contains( lname ) )
321+
{
322+
for ( QgsMapLayer *layer : mLayerGroups[lname] )
323+
{
324+
const QString name = layerNickname( *layer );
325+
mSlds[name] = namedElem;
326+
mLayersToRender.insert( 0, layer );
327+
}
328+
}
329+
else
330+
{
331+
throw QgsBadRequestException( QStringLiteral( "LayerNotDefined" ),
332+
QStringLiteral( "Layer \"%1\" does not exist" ).arg( lname ) );
333+
}
334+
}
335+
}
336+
}
337+
338+
void QgsWmsRenderContext::searchLayersToRenderStyle()
339+
{
340+
for ( const QgsWmsParametersLayer &param : mParameters.layersParameters() )
341+
{
342+
const QString nickname = param.mNickname;
343+
const QString style = param.mStyle;
344+
345+
if ( mNicknameLayers.contains( nickname ) )
346+
{
347+
if ( !style.isEmpty() )
348+
{
349+
mStyles[nickname] = style;
350+
}
351+
352+
mLayersToRender.append( mNicknameLayers[ nickname ] );
353+
}
354+
else if ( mLayerGroups.contains( nickname ) )
355+
{
356+
// Reverse order of layers from a group
357+
QList<QString> layersFromGroup;
358+
for ( QgsMapLayer *layer : mLayerGroups[nickname] )
359+
{
360+
const QString nickname = layerNickname( *layer );
361+
if ( !style.isEmpty() )
362+
{
363+
mStyles[ nickname ] = style;
364+
}
365+
layersFromGroup.push_front( nickname );
366+
}
367+
368+
for ( const auto name : layersFromGroup )
369+
{
370+
mLayersToRender.append( mNicknameLayers[ name ] );
371+
}
372+
}
373+
else
374+
{
375+
throw QgsBadRequestException( QStringLiteral( "LayerNotDefined" ),
376+
QStringLiteral( "Layer \"%1\" does not exist" ).arg( nickname ) );
377+
}
378+
}
379+
}
380+
381+
bool QgsWmsRenderContext::layerScaleVisibility( const QString &name ) const
382+
{
383+
bool visible = false;
384+
385+
if ( ! mNicknameLayers.contains( name ) )
386+
{
387+
return visible;
388+
}
389+
390+
const QgsMapLayer *layer = mNicknameLayers[ name ];
391+
bool scaleBasedVisibility = layer->hasScaleBasedVisibility();
392+
bool useScaleConstraint = ( scaleDenominator() > 0 && scaleBasedVisibility );
393+
394+
if ( !useScaleConstraint || layer->isInScaleRange( scaleDenominator() ) )
395+
{
396+
visible = true;
397+
}
398+
399+
return visible;
400+
}
401+
402+
void QgsWmsRenderContext::removeUnwantedLayers()
403+
{
404+
QList<QgsMapLayer *> layers;
405+
406+
for ( QgsMapLayer *layer : mLayersToRender )
407+
{
408+
const QString nickname = layerNickname( *layer );
409+
410+
if ( !layerScaleVisibility( nickname ) )
411+
continue;
412+
413+
if ( mRestrictedLayers.contains( nickname ) )
414+
continue;
415+
416+
if ( mFlags & UseWfsLayersOnly )
417+
{
418+
if ( layer->type() != QgsMapLayer::VectorLayer )
419+
{
420+
continue;
421+
}
422+
423+
const QStringList wfsLayers = QgsServerProjectUtils::wfsLayerIds( *mProject );
424+
if ( ! wfsLayers.contains( layer->id() ) )
425+
{
426+
continue;
427+
}
428+
}
429+
430+
layers.append( layer );
431+
}
432+
433+
mLayersToRender = layers;
434+
}
435+
436+
void QgsWmsRenderContext::checkLayerReadPermissions()
437+
{
438+
#ifdef HAVE_SERVER_PYTHON_PLUGINS
439+
for ( const auto layer : mLayersToRender )
440+
{
441+
if ( !accessControl()->layerReadPermission( layer ) )
442+
{
443+
throw QgsSecurityException( QStringLiteral( "You are not allowed to access to the layer: %1" ).arg( layer->name() ) );
444+
}
445+
}
446+
#endif
447+
}
448+
449+
#ifdef HAVE_SERVER_PYTHON_PLUGINS
450+
QgsAccessControl *QgsWmsRenderContext::accessControl()
451+
{
452+
return mInterface->accessControls();
453+
}
454+
#endif
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
/***************************************************************************
2+
qgswmsrendercontext.h
3+
---------------------
4+
begin : March 22, 2019
5+
copyright : (C) 2019 by Paul Blottiere
6+
email : paul.blottiere@oslandia.com
7+
***************************************************************************/
8+
9+
/***************************************************************************
10+
* *
11+
* This program is free software; you can redistribute it and/or modify *
12+
* it under the terms of the GNU General Public License as published by *
13+
* the Free Software Foundation; either version 2 of the License, or *
14+
* (at your option) any later version. *
15+
* *
16+
***************************************************************************/
17+
18+
#ifndef QGSWMSRENDERCONTEXT_H
19+
#define QGSWMSRENDERCONTEXT_H
20+
21+
#include "qgswmsparameters.h"
22+
#include "qgsproject.h"
23+
#include "qgsserverinterface.h"
24+
25+
namespace QgsWms
26+
{
27+
class QgsWmsRenderContext
28+
{
29+
public:
30+
enum Flag
31+
{
32+
UseScaleDenominator = 0x01,
33+
UseOpacity = 0x02,
34+
UseFilter = 0x04,
35+
UseSelection = 0x08,
36+
AddHighlightLayers = 0x10,
37+
UpdateExtent = 0x20,
38+
SetAccessControl = 0x40,
39+
AddQueryLayers = 0x80,
40+
UseWfsLayersOnly = 0x100,
41+
AddExternalLayers = 0x200
42+
};
43+
Q_DECLARE_FLAGS( Flags, Flag )
44+
45+
QgsWmsRenderContext() = default;
46+
47+
QgsWmsRenderContext( const QgsProject *project, QgsServerInterface *interface );
48+
49+
void setParameters( const QgsWmsParameters &parameters );
50+
51+
QgsWmsParameters parameters() const;
52+
53+
const QgsServerSettings &settings() const;
54+
55+
const QgsProject *project() const;
56+
57+
void setFlag( Flag flag, bool on = true );
58+
59+
bool testFlag( Flag flag ) const;
60+
61+
QList<QgsMapLayer *> layers() const;
62+
63+
QList<QgsMapLayer *> layersToRender() const;
64+
65+
QDomElement sld( const QgsMapLayer &layer ) const;
66+
67+
QString style( const QgsMapLayer &layer ) const;
68+
69+
double scaleDenominator() const;
70+
71+
void setScaleDenominator( double scaleDenominator );
72+
73+
bool updateExtent() const;
74+
75+
QgsWmsParametersLayer parameters( const QgsMapLayer &layer ) const;
76+
77+
#ifdef HAVE_SERVER_PYTHON_PLUGINS
78+
QgsAccessControl *accessControl();
79+
#endif
80+
81+
private:
82+
QString layerNickname( const QgsMapLayer &layer ) const;
83+
84+
void initNicknameLayers();
85+
void initRestrictedLayers();
86+
void initLayerGroupsRecursive( const QgsLayerTreeGroup *group, const QString &groupName );
87+
88+
void searchLayersToRender();
89+
void searchLayersToRenderSld();
90+
void searchLayersToRenderStyle();
91+
void removeUnwantedLayers();
92+
93+
void checkLayerReadPermissions();
94+
95+
bool layerScaleVisibility( const QString &name ) const;
96+
97+
const QgsProject *mProject = nullptr;
98+
QgsServerInterface *mInterface = nullptr;
99+
QgsWmsParameters mParameters;
100+
Flags mFlags = nullptr;
101+
double mScaleDenominator = -1.0;
102+
103+
// nickname of all layers defined within the project
104+
QMap<QString, QgsMapLayer *> mNicknameLayers;
105+
106+
// map of layers to use for rendering
107+
QList<QgsMapLayer *> mLayersToRender;
108+
109+
// list of layers which are not usable
110+
QStringList mRestrictedLayers;
111+
112+
QMap<QString, QList<QgsMapLayer *> > mLayerGroups;
113+
114+
QMap<QString, QDomElement> mSlds;
115+
QMap<QString, QString> mStyles;
116+
};
117+
};
118+
119+
#endif

0 commit comments

Comments
 (0)
Please sign in to comment.