QGIS API Documentation  3.4.15-Madeira (e83d02e274)
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 "qgsserviceregistry.h"
26 #include "qgsservicemodule.h"
27 #include "qgslogger.h"
28 #include "qgsmessagelog.h"
29 #include "qgis.h"
30 
31 
32 typedef void unloadHook_t( QgsServiceModule * );
33 
41 {
42  public:
43 
48  QgsServiceNativeModuleEntry( const QString &location )
49  : mLocation( location )
50  {}
51 
52  QString mLocation;
55 };
56 
57 void QgsServiceNativeLoader::loadModules( const QString &modulePath, QgsServiceRegistry &registrar,
58  QgsServerInterface *serverIface )
59 {
60  QDir moduleDir( modulePath );
61  moduleDir.setSorting( QDir::Name | QDir::IgnoreCase );
62  moduleDir.setFilter( QDir::Files );
63 
64 #if defined(Q_OS_WIN) || defined(__CYGWIN__)
65  moduleDir.setNameFilters( QStringList( "*.dll" ) );
66 #else
67  moduleDir.setNameFilters( QStringList( "*.so" ) );
68 #endif
69 
70  qDebug() << QString( "Checking %1 for native services modules" ).arg( moduleDir.path() );
71  //QgsDebugMsg( QStringLiteral( "Checking %1 for native services modules" ).arg( moduleDir.path() ) );
72 
73  for ( const QFileInfo &fi : moduleDir.entryInfoList() )
74  {
75  QgsServiceModule *module = loadNativeModule( fi.filePath() );
76  if ( module )
77  {
78  // Register services
79  module->registerSelf( registrar, serverIface );
80  }
81  }
82 }
83 
84 
86 
88 {
89  QgsServiceNativeModuleEntry *entry = findModuleEntry( location );
90  if ( entry )
91  {
92  return entry->mModule;
93  }
94 
95  QLibrary lib( location );
96  //QgsDebugMsg( QStringLiteral( "Loading native module %1" ).arg( location ) );
97  qDebug() << QString( "Loading native module %1" ).arg( location );
98  if ( !lib.load() )
99  {
100  QgsMessageLog::logMessage( QString( "Failed to load library %1: %2" ).arg( lib.fileName(), lib.errorString() ) );
101  return nullptr;
102  }
103  // Load entry point
105  entryPointFunc = reinterpret_cast<serviceEntryPoint_t *>( cast_to_fptr( lib.resolve( "QGS_ServiceModule_Init" ) ) );
106 
107  if ( entryPointFunc )
108  {
109  QgsServiceModule *module = entryPointFunc();
110  if ( module )
111  {
112  entry = new QgsServiceNativeModuleEntry( location );
113  entry->mModule = module;
114  entry->mUnloadHook = reinterpret_cast<unloadHook_t *>( cast_to_fptr( lib.resolve( "QGS_ServiceModule_Exit" ) ) );
115 
116  // Add entry
117  mModules.insert( location, ModuleTable::mapped_type( entry ) );
118  return module;
119  }
120  else
121  {
122  QgsMessageLog::logMessage( QString( "No entry point for module %1" ).arg( lib.fileName() ) );
123  }
124  }
125  else
126  {
127  QgsMessageLog::logMessage( QString( "Error: entry point returned null for %1" ).arg( lib.fileName() ) );
128  }
129 
130  // No module found: release library
131  lib.unload();
132  return nullptr;
133 }
134 
136 {
137  ModuleTable::iterator it = mModules.begin();
138  ModuleTable::iterator end = mModules.end();
139 
140  while ( it != end )
141  {
142  unloadModuleEntry( it->get() );
143  ++it;
144  }
145 
146  mModules.clear();
147 }
148 
149 QgsServiceNativeModuleEntry *QgsServiceNativeLoader::findModuleEntry( const QString &location )
150 {
151  QgsServiceNativeModuleEntry *entry = nullptr;
152  ModuleTable::iterator item = mModules.find( location );
153  if ( item != mModules.end() )
154  {
155  entry = item->get();
156  }
157  return entry;
158 }
159 
160 void QgsServiceNativeLoader::unloadModuleEntry( QgsServiceNativeModuleEntry *entry )
161 {
162  // Call cleanup function if it exists
163  if ( entry->mUnloadHook )
164  {
165  entry->mUnloadHook( entry->mModule );
166  }
167 
168  QLibrary lib( entry->mLocation );
169  lib.unload();
170 }
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:171
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.