QGIS API Documentation  3.8.0-Zanzibar (11aff65)
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 "qgsmessagelog.h"
23 
24 #include <algorithm>
25 #include <functional>
26 
27 
28 namespace
29 {
30 
31 // Build a key entry from name and version
32  QString makeServiceKey( const QString &name, const QString &version )
33  {
34  return QString( "%1_%2" ).arg( name, version );
35  }
36 
37 // Compare two version strings:
38 // The strings are split into dot separated segment
39 // Each segment are compared up to the shortest number of segment of the
40 // lists. Remaining segments are dropped.
41 // If both segments can be interpreted as numbers the are compared as numbers, otherwise
42 // They are compared lexicographically.
43 // Return true if v1 is greater than v2
44  bool isVersionGreater( const QString &v1, const QString &v2 )
45  {
46  QStringList l1 = v1.split( '.' );
47  QStringList l2 = v2.split( '.' );
48  QStringList::iterator it1 = l1.begin();
49  QStringList::iterator it2 = l2.begin();
50  bool isint;
51  while ( it1 != l1.end() && it2 != l2.end() )
52  {
53  if ( *it1 != *it2 )
54  {
55  // Compare as numbers
56  int i1 = it1->toInt( &isint );
57  if ( isint )
58  {
59  int i2 = it2->toInt( &isint );
60  if ( isint && i1 != i2 )
61  {
62  return i1 > i2;
63  }
64  }
65  // Compare lexicographically
66  if ( !isint )
67  {
68  return *it1 > *it2;
69  }
70  }
71  ++it1;
72  ++it2;
73  }
74  // We reach the end of one of the list
75  return false;
76  }
77 
78 // Check that two versions are c
79 
80 
81 } // namespace
82 
84 {
85  cleanUp();
86 }
87 
88 QgsService *QgsServiceRegistry::getService( const QString &name, const QString &version )
89 {
90  QgsService *service = nullptr;
91  QString key;
92 
93  // Check that we have a service of that name
94  VersionTable::const_iterator v = mVersions.constFind( name );
95  if ( v != mVersions.constEnd() )
96  {
97  key = version.isEmpty() ? v->second : makeServiceKey( name, version );
98  ServiceTable::const_iterator it = mServices.constFind( key );
99  if ( it != mServices.constEnd() )
100  {
101  service = it->get();
102  }
103  else
104  {
105  // Return the dofault version
106  QgsMessageLog::logMessage( QString( "Service %1 %2 not found, returning default" ).arg( name, version ) );
107  service = mServices[v->second].get();
108  }
109  }
110  else
111  {
112  QgsMessageLog::logMessage( QString( "Service %1 is not registered" ).arg( name ) );
113  }
114  return service;
115 }
116 
118 {
119  QString name = service->name();
120  QString version = service->version();
121 
122  // Test if service is already registered
123  QString key = makeServiceKey( name, version );
124  if ( mServices.constFind( key ) != mServices.constEnd() )
125  {
126  QgsMessageLog::logMessage( QString( "Error Service %1 %2 is already registered" ).arg( name, version ) );
127  return;
128  }
129 
130  QgsMessageLog::logMessage( QString( "Adding service %1 %2" ).arg( name, version ) );
131  mServices.insert( key, std::shared_ptr<QgsService>( service ) );
132 
133  // Check the default version
134  // The first inserted service of a given name
135  // is the default one.
136  // this will ensure that native services are always
137  // the defaults.
138  VersionTable::const_iterator v = mVersions.constFind( name );
139  if ( v == mVersions.constEnd() )
140  {
141  // Insert the service as the default one
142  mVersions.insert( name, VersionTable::mapped_type( version, key ) );
143  }
144  /*
145  if ( v != mVersions.constEnd() )
146  {
147  if ( isVersionGreater( version, v->first ) )
148  {
149  // Replace the default version key
150  mVersions.insert( name, VersionTable::mapped_type( version, key ) );
151  }
152  }
153  else
154  {
155  // Insert the service as the default one
156  mVersions.insert( name, VersionTable::mapped_type( version, key ) );
157  }*/
158 
159 }
160 
161 int QgsServiceRegistry::unregisterService( const QString &name, const QString &version )
162 {
163  // Check that we have a service of that name
164  int removed = 0;
165  VersionTable::const_iterator v = mVersions.constFind( name );
166  if ( v != mVersions.constEnd() )
167  {
168  if ( version.isEmpty() )
169  {
170  // No version specified, remove all versions
171  ServiceTable::iterator it = mServices.begin();
172  while ( it != mServices.end() )
173  {
174  if ( ( *it )->name() == name )
175  {
176  QgsMessageLog::logMessage( QString( "Unregistering service %1 %2" ).arg( name, ( *it )->version() ) );
177  it = mServices.erase( it );
178  ++removed;
179  }
180  else
181  {
182  ++it;
183  }
184  }
185  // Remove from version table
186  mVersions.remove( name );
187  }
188  else
189  {
190  QString key = makeServiceKey( name, version );
191  ServiceTable::iterator found = mServices.find( key );
192  if ( found != mServices.end() )
193  {
194  QgsMessageLog::logMessage( QString( "Unregistering service %1 %2" ).arg( name, version ) );
195  mServices.erase( found );
196  removed = 1;
197 
198  // Find if we have other services of that name
199  // but with different version
200  //
201  QString maxVer;
202  std::function < void ( const ServiceTable::mapped_type & ) >
203  findGreaterVersion = [name, &maxVer]( const ServiceTable::mapped_type & service )
204  {
205  if ( service->name() == name &&
206  ( maxVer.isEmpty() || isVersionGreater( service->version(), maxVer ) ) )
207  maxVer = service->version();
208  };
209 
210  mVersions.remove( name );
211 
212  std::for_each( mServices.constBegin(), mServices.constEnd(), findGreaterVersion );
213  if ( !maxVer.isEmpty() )
214  {
215  // Set the new default service
216  QString key = makeServiceKey( name, maxVer );
217  mVersions.insert( name, VersionTable::mapped_type( version, key ) );
218  }
219  }
220  }
221  }
222  return removed;
223 }
224 
225 void QgsServiceRegistry::init( const QString &nativeModulePath, QgsServerInterface *serverIface )
226 {
227  mNativeLoader.loadModules( nativeModulePath, *this, serverIface );
228 }
229 
231 {
232  // Release all services
233  mVersions.clear();
234  mServices.clear();
235  mNativeLoader.unloadModules();
236 }
237 
238 
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