QGIS API Documentation  3.24.2-Tisler (13c1a02865)
qgsconfigcache.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsconfigcache.cpp
3  ------------------
4  begin : July 24th, 2010
5  copyright : (C) 2010 by Marco Hugentobler
6  email : marco dot hugentobler at sourcepole dot ch
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 "qgsconfigcache.h"
19 #include "qgsmessagelog.h"
20 #include "qgsserverexception.h"
21 #include "qgsstorebadlayerinfo.h"
22 #include "qgsserverprojectutils.h"
23 
24 #include <QFile>
25 
27 {
28  static QgsConfigCache *sInstance = nullptr;
29 
30  if ( !sInstance )
31  sInstance = new QgsConfigCache();
32 
33  return sInstance;
34 }
35 
36 QgsConfigCache::QgsConfigCache()
37 {
38  QObject::connect( &mFileSystemWatcher, &QFileSystemWatcher::fileChanged, this, &QgsConfigCache::removeChangedEntry );
39 }
40 
41 
42 const QgsProject *QgsConfigCache::project( const QString &path, const QgsServerSettings *settings )
43 {
44  if ( ! mProjectCache[ path ] )
45  {
46 
47  std::unique_ptr<QgsProject> prj( new QgsProject() );
48 
49  // This is required by virtual layers that call QgsProject::instance() inside the constructor :(
50  QgsProject::setInstance( prj.get() );
51 
52  QgsStoreBadLayerInfo *badLayerHandler = new QgsStoreBadLayerInfo();
53  prj->setBadLayerHandler( badLayerHandler );
54 
55  // Always skip original styles storage
56  QgsProject::ReadFlags readFlags = QgsProject::ReadFlag() | QgsProject::ReadFlag::FlagDontStoreOriginalStyles ;
57  if ( settings )
58  {
59  // Activate trust layer metadata flag
60  if ( settings->trustLayerMetadata() )
61  {
63  }
64  // Activate don't load layouts flag
65  if ( settings->getPrintDisabled() )
66  {
68  }
69  }
70 
71  if ( prj->read( path, readFlags ) )
72  {
73  if ( !badLayerHandler->badLayers().isEmpty() )
74  {
75  // if bad layers are not restricted layers so service failed
76  QStringList unrestrictedBadLayers;
77  // test bad layers through restrictedlayers
78  const QStringList badLayerIds = badLayerHandler->badLayers();
79  const QMap<QString, QString> badLayerNames = badLayerHandler->badLayerNames();
80  const QStringList resctrictedLayers = QgsServerProjectUtils::wmsRestrictedLayers( *prj );
81  for ( const QString &badLayerId : badLayerIds )
82  {
83  // if this bad layer is in restricted layers
84  // it doesn't need to be added to unrestricted bad layers
85  if ( badLayerNames.contains( badLayerId ) &&
86  resctrictedLayers.contains( badLayerNames.value( badLayerId ) ) )
87  {
88  continue;
89  }
90  unrestrictedBadLayers.append( badLayerId );
91  }
92  if ( !unrestrictedBadLayers.isEmpty() )
93  {
94  // This is a critical error unless QGIS_SERVER_IGNORE_BAD_LAYERS is set to TRUE
95  if ( ! settings || ! settings->ignoreBadLayers() )
96  {
98  QStringLiteral( "Error, Layer(s) %1 not valid in project %2" ).arg( unrestrictedBadLayers.join( QLatin1String( ", " ) ), path ),
99  QStringLiteral( "Server" ), Qgis::MessageLevel::Critical );
100  throw QgsServerException( QStringLiteral( "Layer(s) not valid" ) );
101  }
102  else
103  {
105  QStringLiteral( "Warning, Layer(s) %1 not valid in project %2" ).arg( unrestrictedBadLayers.join( QLatin1String( ", " ) ), path ),
106  QStringLiteral( "Server" ), Qgis::MessageLevel::Warning );
107  }
108  }
109  }
110  mProjectCache.insert( path, prj.release() );
111  mFileSystemWatcher.addPath( path );
112  }
113  else
114  {
116  QStringLiteral( "Error when loading project file '%1': %2 " ).arg( path, prj->error() ),
117  QStringLiteral( "Server" ), Qgis::MessageLevel::Critical );
118  }
119  }
120  return mProjectCache[ path ];
121 }
122 
123 QDomDocument *QgsConfigCache::xmlDocument( const QString &filePath )
124 {
125  //first open file
126  QFile configFile( filePath );
127  if ( !configFile.exists() )
128  {
129  QgsMessageLog::logMessage( "Error, configuration file '" + filePath + "' does not exist", QStringLiteral( "Server" ), Qgis::MessageLevel::Critical );
130  return nullptr;
131  }
132 
133  if ( !configFile.open( QIODevice::ReadOnly ) )
134  {
135  QgsMessageLog::logMessage( "Error, cannot open configuration file '" + filePath + "'", QStringLiteral( "Server" ), Qgis::MessageLevel::Critical );
136  return nullptr;
137  }
138 
139  // first get cache
140  QDomDocument *xmlDoc = mXmlDocumentCache.object( filePath );
141  if ( !xmlDoc )
142  {
143  //then create xml document
144  xmlDoc = new QDomDocument();
145  QString errorMsg;
146  int line, column;
147  if ( !xmlDoc->setContent( &configFile, true, &errorMsg, &line, &column ) )
148  {
149  QgsMessageLog::logMessage( "Error parsing file '" + filePath +
150  QStringLiteral( "': parse error %1 at row %2, column %3" ).arg( errorMsg ).arg( line ).arg( column ), QStringLiteral( "Server" ), Qgis::MessageLevel::Critical );
151  delete xmlDoc;
152  return nullptr;
153  }
154  mXmlDocumentCache.insert( filePath, xmlDoc );
155  mFileSystemWatcher.addPath( filePath );
156  xmlDoc = mXmlDocumentCache.object( filePath );
157  Q_ASSERT( xmlDoc );
158  }
159  return xmlDoc;
160 }
161 
162 void QgsConfigCache::removeChangedEntry( const QString &path )
163 {
164  mProjectCache.remove( path );
165 
166  //xml document must be removed last, as other config cache destructors may require it
167  mXmlDocumentCache.remove( path );
168 
169  mFileSystemWatcher.removePath( path );
170 }
171 
172 
173 void QgsConfigCache::removeEntry( const QString &path )
174 {
175  removeChangedEntry( path );
176 }
Cache for server configuration.
void removeEntry(const QString &path)
Removes an entry from cache.
static QgsConfigCache * instance()
Returns the current instance.
const QgsProject * project(const QString &path, const QgsServerSettings *settings=nullptr)
If the project is not cached yet, then the project is read from the path.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition: qgsproject.h:101
static void setInstance(QgsProject *project)
Set the current project singleton instance to project.
Definition: qgsproject.cpp:464
ReadFlag
Flags which control project read behavior.
Definition: qgsproject.h:126
@ FlagTrustLayerMetadata
Trust layer metadata. Improves project read time. Do not use it if layers' extent is not fixed during...
@ FlagDontStoreOriginalStyles
Skip the initial XML style storage for layers. Useful for minimising project load times in non-intera...
@ FlagDontLoadLayouts
Don't load print layouts. Improves project read time if layouts are not required, and allows projects...
Exception base class for server exceptions.
Provides a way to retrieve settings by prioritizing according to environment variables,...
bool getPrintDisabled() const
Returns true if WMS GetPrint request is disabled and the project's reading flag QgsProject::ReadFlag:...
bool ignoreBadLayers() const
Returns true if the bad layers are ignored and false when the presence of a bad layers invalidates th...
bool trustLayerMetadata() const
Returns true if the reading flag trust layer metadata is activated.
Stores layer ids of bad layers.
QMap< QString, QString > badLayerNames() const
Returns names of bad layers with ids.
QStringList badLayers() const
badLayers
SERVER_EXPORT QStringList wmsRestrictedLayers(const QgsProject &project)
Returns the restricted layer name list.