QGIS API Documentation  3.10.0-A Coruña (6c816b4204)
qgsservicenativeloader.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsservicerenativeloader.cpp
3 
4  Define Loader for native service modules
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 <QLibrary>
21 #include <QDir>
22 #include <QDebug>
23 
24 #include "qgsservicenativeloader.h"
25 #include "qgsservicemodule.h"
26 #include "qgsmessagelog.h"
27 #include "qgis.h"
28 
29 
30 typedef void unloadHook_t( QgsServiceModule * );
31 
39 {
40  public:
41 
46  QgsServiceNativeModuleEntry( const QString &location )
47  : mLocation( location )
48  {}
49 
50  QString mLocation;
53 };
54 
55 void QgsServiceNativeLoader::loadModules( const QString &modulePath, QgsServiceRegistry &registrar,
56  QgsServerInterface *serverIface )
57 {
58  QDir moduleDir( modulePath );
59  moduleDir.setSorting( QDir::Name | QDir::IgnoreCase );
60  moduleDir.setFilter( QDir::Files );
61 
62 #if defined(Q_OS_WIN) || defined(__CYGWIN__)
63  moduleDir.setNameFilters( QStringList( "*.dll" ) );
64 #else
65  moduleDir.setNameFilters( QStringList( "*.so" ) );
66 #endif
67 
68  qDebug() << QString( "Checking %1 for native services modules" ).arg( moduleDir.path() );
69  //QgsDebugMsg( QStringLiteral( "Checking %1 for native services modules" ).arg( moduleDir.path() ) );
70 
71  for ( const QFileInfo &fi : moduleDir.entryInfoList() )
72  {
73  QgsServiceModule *module = loadNativeModule( fi.filePath() );
74  if ( module )
75  {
76  // Register services
77  module->registerSelf( registrar, serverIface );
78  }
79  }
80 }
81 
82 
84 
86 {
87  QgsServiceNativeModuleEntry *entry = findModuleEntry( location );
88  if ( entry )
89  {
90  return entry->mModule;
91  }
92 
93  QLibrary lib( location );
94  //QgsDebugMsg( QStringLiteral( "Loading native module %1" ).arg( location ) );
95  qDebug() << QString( "Loading native module %1" ).arg( location );
96  if ( !lib.load() )
97  {
98  QgsMessageLog::logMessage( QString( "Failed to load library %1: %2" ).arg( lib.fileName(), lib.errorString() ) );
99  return nullptr;
100  }
101  // Load entry point
103  entryPointFunc = reinterpret_cast<serviceEntryPoint_t *>( cast_to_fptr( lib.resolve( "QGS_ServiceModule_Init" ) ) );
104 
105  if ( entryPointFunc )
106  {
107  QgsServiceModule *module = entryPointFunc();
108  if ( module )
109  {
110  entry = new QgsServiceNativeModuleEntry( location );
111  entry->mModule = module;
112  entry->mUnloadHook = reinterpret_cast<unloadHook_t *>( cast_to_fptr( lib.resolve( "QGS_ServiceModule_Exit" ) ) );
113 
114  // Add entry
115  mModules.insert( location, ModuleTable::mapped_type( entry ) );
116  return module;
117  }
118  else
119  {
120  QgsMessageLog::logMessage( QString( "No entry point for module %1" ).arg( lib.fileName() ) );
121  }
122  }
123  else
124  {
125  QgsMessageLog::logMessage( QString( "Error: entry point returned null for %1" ).arg( lib.fileName() ) );
126  }
127 
128  // No module found: release library
129  lib.unload();
130  return nullptr;
131 }
132 
134 {
135  ModuleTable::iterator it = mModules.begin();
136  ModuleTable::iterator end = mModules.end();
137 
138  while ( it != end )
139  {
140  unloadModuleEntry( it->get() );
141  ++it;
142  }
143 
144  mModules.clear();
145 }
146 
147 QgsServiceNativeModuleEntry *QgsServiceNativeLoader::findModuleEntry( const QString &location )
148 {
149  QgsServiceNativeModuleEntry *entry = nullptr;
150  ModuleTable::iterator item = mModules.find( location );
151  if ( item != mModules.end() )
152  {
153  entry = item->get();
154  }
155  return entry;
156 }
157 
158 void QgsServiceNativeLoader::unloadModuleEntry( QgsServiceNativeModuleEntry *entry )
159 {
160  // Call cleanup function if it exists
161  if ( entry->mUnloadHook )
162  {
163  entry->mUnloadHook( entry->mModule );
164  }
165 
166  QLibrary lib( entry->mLocation );
167  lib.unload();
168 }
QgsServiceModule * loadNativeModule(const QString &location)
Load the native module from path.
QgsServiceModule * serviceEntryPoint_t()
QgsServiceNativeModuleEntry(const QString &location)
Constructor for QgsServiceNativeModuleEntry.
Class defining the service module interface for QGIS server services.
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).
#define cast_to_fptr(f)
Definition: qgis.h:173
virtual void registerSelf(QgsServiceRegistry &registry, QgsServerInterface *serverIface=nullptr)=0
Asks the module to register all provided services.
void unloadHook_t(QgsServiceModule *)
QgsServerInterface Class defining interfaces exposed by QGIS Server and made available to plugins...
QgsServiceRegistry Class defining the registry manager for QGIS server services.
Native module (location, the module itself and the unload function).
void loadModules(const QString &modulePath, QgsServiceRegistry &registrar, QgsServerInterface *serverIface=nullptr)
Load all modules from path.