QGIS API Documentation  3.4.15-Madeira (e83d02e274)
qgsserviceregistry.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsserviceregistry.cpp
3 
4  Class defining the service manager for QGIS server services.
5  -------------------
6  begin : 2016-12-05
7  copyright : (C) 2016 by David Marteau
8  email : david dot marteau at 3liz dot com
9  ***************************************************************************/
10 
11 /***************************************************************************
12  * *
13  * This program is free software; you can redistribute it and/or modify *
14  * it under the terms of the GNU General Public License as published by *
15  * the Free Software Foundation; either version 2 of the License, or *
16  * (at your option) any later version. *
17  * *
18  ***************************************************************************/
19 
20 #include "qgsserviceregistry.h"
21 #include "qgsservice.h"
22 #include "qgslogger.h"
23 #include "qgsmessagelog.h"
24 
25 #include <algorithm>
26 #include <functional>
27 
28 
29 namespace
30 {
31 
32 // Build a key entry from name and version
33  QString makeServiceKey( const QString &name, const QString &version )
34  {
35  return QString( "%1_%2" ).arg( name, version );
36  }
37 
38 // Compare two version strings:
39 // The strings are split into dot separated segment
40 // Each segment are compared up to the shortest number of segment of the
41 // lists. Remaining segments are dropped.
42 // If both segments can be interpreted as numbers the are compared as numbers, otherwise
43 // They are compared lexicographically.
44 // Return true if v1 is greater than v2
45  bool isVersionGreater( const QString &v1, const QString &v2 )
46  {
47  QStringList l1 = v1.split( '.' );
48  QStringList l2 = v2.split( '.' );
49  QStringList::iterator it1 = l1.begin();
50  QStringList::iterator it2 = l2.begin();
51  bool isint;
52  while ( it1 != l1.end() && it2 != l2.end() )
53  {
54  if ( *it1 != *it2 )
55  {
56  // Compare as numbers
57  int i1 = it1->toInt( &isint );
58  if ( isint )
59  {
60  int i2 = it2->toInt( &isint );
61  if ( isint && i1 != i2 )
62  {
63  return i1 > i2;
64  }
65  }
66  // Compare lexicographically
67  if ( !isint )
68  {
69  return *it1 > *it2;
70  }
71  }
72  ++it1;
73  ++it2;
74  }
75  // We reach the end of one of the list
76  return false;
77  }
78 
79 // Check that two versions are c
80 
81 
82 } // namespace
83 
85 {
86  cleanUp();
87 }
88 
89 QgsService *QgsServiceRegistry::getService( const QString &name, const QString &version )
90 {
91  QgsService *service = nullptr;
92  QString key;
93 
94  // Check that we have a service of that name
95  VersionTable::const_iterator v = mVersions.constFind( name );
96  if ( v != mVersions.constEnd() )
97  {
98  key = version.isEmpty() ? v->second : makeServiceKey( name, version );
99  ServiceTable::const_iterator it = mServices.constFind( key );
100  if ( it != mServices.constEnd() )
101  {
102  service = it->get();
103  }
104  else
105  {
106  // Return the dofault version
107  QgsMessageLog::logMessage( QString( "Service %1 %2 not found, returning default" ).arg( name, version ) );
108  service = mServices[v->second].get();
109  }
110  }
111  else
112  {
113  QgsMessageLog::logMessage( QString( "Service %1 is not registered" ).arg( name ) );
114  }
115  return service;
116 }
117 
119 {
120  QString name = service->name();
121  QString version = service->version();
122 
123  // Test if service is already registered
124  QString key = makeServiceKey( name, version );
125  if ( mServices.constFind( key ) != mServices.constEnd() )
126  {
127  QgsMessageLog::logMessage( QString( "Error Service %1 %2 is already registered" ).arg( name, version ) );
128  return;
129  }
130 
131  QgsMessageLog::logMessage( QString( "Adding service %1 %2" ).arg( name, version ) );
132  mServices.insert( key, std::shared_ptr<QgsService>( service ) );
133 
134  // Check the default version
135  // The first inserted service of a given name
136  // is the default one.
137  // this will ensure that native services are always
138  // the defaults.
139  VersionTable::const_iterator v = mVersions.constFind( name );
140  if ( v == mVersions.constEnd() )
141  {
142  // Insert the service as the default one
143  mVersions.insert( name, VersionTable::mapped_type( version, key ) );
144  }
145  /*
146  if ( v != mVersions.constEnd() )
147  {
148  if ( isVersionGreater( version, v->first ) )
149  {
150  // Replace the default version key
151  mVersions.insert( name, VersionTable::mapped_type( version, key ) );
152  }
153  }
154  else
155  {
156  // Insert the service as the default one
157  mVersions.insert( name, VersionTable::mapped_type( version, key ) );
158  }*/
159 
160 }
161 
162 int QgsServiceRegistry::unregisterService( const QString &name, const QString &version )
163 {
164  // Check that we have a service of that name
165  int removed = 0;
166  VersionTable::const_iterator v = mVersions.constFind( name );
167  if ( v != mVersions.constEnd() )
168  {
169  if ( version.isEmpty() )
170  {
171  // No version specified, remove all versions
172  ServiceTable::iterator it = mServices.begin();
173  while ( it != mServices.end() )
174  {
175  if ( ( *it )->name() == name )
176  {
177  QgsMessageLog::logMessage( QString( "Unregistering service %1 %2" ).arg( name, ( *it )->version() ) );
178  it = mServices.erase( it );
179  ++removed;
180  }
181  else
182  {
183  ++it;
184  }
185  }
186  // Remove from version table
187  mVersions.remove( name );
188  }
189  else
190  {
191  QString key = makeServiceKey( name, version );
192  ServiceTable::iterator found = mServices.find( key );
193  if ( found != mServices.end() )
194  {
195  QgsMessageLog::logMessage( QString( "Unregistering service %1 %2" ).arg( name, version ) );
196  mServices.erase( found );
197  removed = 1;
198 
199  // Find if we have other services of that name
200  // but with different version
201  //
202  QString maxVer;
203  std::function < void ( const ServiceTable::mapped_type & ) >
204  findGreaterVersion = [name, &maxVer]( const ServiceTable::mapped_type & service )
205  {
206  if ( service->name() == name &&
207  ( maxVer.isEmpty() || isVersionGreater( service->version(), maxVer ) ) )
208  maxVer = service->version();
209  };
210 
211  mVersions.remove( name );
212 
213  std::for_each( mServices.constBegin(), mServices.constEnd(), findGreaterVersion );
214  if ( !maxVer.isEmpty() )
215  {
216  // Set the new default service
217  QString key = makeServiceKey( name, maxVer );
218  mVersions.insert( name, VersionTable::mapped_type( version, key ) );
219  }
220  }
221  }
222  }
223  return removed;
224 }
225 
226 void QgsServiceRegistry::init( const QString &nativeModulePath, QgsServerInterface *serverIface )
227 {
228  mNativeLoader.loadModules( nativeModulePath, *this, serverIface );
229 }
230 
232 {
233  // Release all services
234  mVersions.clear();
235  mServices.clear();
236  mNativeLoader.unloadModules();
237 }
238 
239 
void cleanUp()
Clean up registered service and unregister modules.
virtual QString name() const =0
~QgsServiceRegistry()
Destructor.
void unloadModules()
Unload all modules.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
void init(const QString &nativeModulepath, QgsServerInterface *serverIface=nullptr)
Initialize registry, load modules and auto register services.
void registerService(QgsService *service)
Register a service by its name and version.
QgsService Class defining interfaces for QGIS server services.
Definition: qgsservice.h:39
QgsServerInterface Class defining interfaces exposed by QGIS Server and made available to plugins...
QgsService * getService(const QString &name, const QString &version=QString())
Retrieve a service from its name.
int unregisterService(const QString &name, const QString &version=QString())
Unregister service from its name and version.
void loadModules(const QString &modulePath, QgsServiceRegistry &registrar, QgsServerInterface *serverIface=nullptr)
Load all modules from path.
virtual QString version() const =0