****************************************************************************/
#include "PluginManager.h"
-#include "ICommandExecutor.h"
#include "Configuration.h"
-#include "Scene.h"
+#include "Log.h"
+#include "IPlugin.h"
+#include <IScene.h>
-#include <iostream>
-#include <sys/types.h>
#include <dirent.h>
#include <errno.h>
#include <dlfcn.h>
-#include "Log.h"
-#include <libgen.h> // basename
-#include <sys/stat.h>
-
-#include <list>
-using std::list;
+#include <stdlib.h>
-#include <string.h>
-using std::string;
-typedef list<string> tFileList;
-typedef list<string>::iterator tFileListIterator;
+StaticPluginCreateFuncList PluginManager::mStaticPluginCreateFuncList;
//===========================================================================
-// plugin configuration
+// register statically linked plugins (configured by build system)
//===========================================================================
-const char* gPluginLookupPath = NULL;
-
-const char* gRendererPluginDirectories[] = { "/renderer" };
-
-uint gRendererPluginDirectoriesCount = sizeof(gRendererPluginDirectories) / sizeof(gRendererPluginDirectories[0]);
-
-const char* gCommunicatorPluginDirectories[] = { "/communicator" };
-
-uint gCommunicatorPluginDirectoriesCount = sizeof(gCommunicatorPluginDirectories) / sizeof(gCommunicatorPluginDirectories[0]);
-
-const char* gScenePluginDirectories[] = { "/sceneprovider" };
-
-uint gScenePluginDirectoriesCount = sizeof(gScenePluginDirectories) / sizeof(gScenePluginDirectories[0]);
-
-const char* gHealthPluginDirectories[] = { "/health" };
-
-uint gHealthPluginDirectoriesCount = sizeof(gHealthPluginDirectories) / sizeof(gHealthPluginDirectories[0]);
+STATIC_PLUGIN_REGISTRATION
//===========================================================================
-// global functions for loading plugins
+// class implementation
//===========================================================================
-template<class T>
-T* getCreateFunction(string libname)
+PluginManager::PluginManager(ICommandExecutor& executor, Configuration& config)
+: mExecutor(executor)
+, mConfiguration(config)
{
- // cut off directories
- char* fileWithPath = const_cast<char*>(libname.c_str());
- string libFileName = basename(fileWithPath);
- LOG_DEBUG("LayerManagerService", "lib name without directory: " << libFileName);
+ LOG_DEBUG("PluginManager", "loading plugins from " << mConfiguration.getPluginPath());
- // cut off "lib" in front and cut off .so end"
- string createFunctionName = "create" + libFileName.substr(3, libFileName.length() - 6);
- LOG_DEBUG("LayerManagerService", "lib entry point name: " << createFunctionName);
+ // create static plugins
+ createStaticallyLinkedPlugins();
- // open library
- void *libraryHandle;
- dlerror(); // Clear any existing error
- libraryHandle = dlopen(libname.c_str(), RTLD_NOW | RTLD_GLOBAL /*LAZY*/);
- const char* dlopen_error = dlerror();
- if (!libraryHandle || dlopen_error)
- {
- LOG_ERROR("LayerManagerService", "dlopen failed: " << dlopen_error);
- dlclose(libraryHandle);
- return 0;
- }
+ // create dynamic plugins
+ getAllFilesInPluginPath(mConfiguration.getPluginPath());
+ createDynamicallyLinkedPlugins();
- // get entry point from shared lib
- dlerror(); // Clear any existing error
- LOG_DEBUG("LayerManagerService", "loading external function with name: " << createFunctionName);
-
- union
- {
- void* voidPointer;
- T* typedPointer;
- } functionPointer;
-
- // Note: direct cast is not allowed by ISO C++. e.g.
- // T* createFunction = reinterpret_cast<T*>(dlsym(libraryHandle, createFunctionName.c_str()));
- // compiler warning: "forbids casting between pointer-to-function and pointer-to-object"
-
- functionPointer.voidPointer = dlsym(libraryHandle, createFunctionName.c_str());
- T* createFunction = functionPointer.typedPointer;
+ LOG_INFO("PluginManager", "created " << mPluginList.size() << " plugins");
+}
+
+PluginManager::~PluginManager()
+{
+ PluginList::iterator iter = mPluginList.begin();
+ PluginList::iterator iterEnd = mPluginList.end();
- const char* dlsym_error = dlerror();
- if (!createFunction || dlsym_error)
+ for (; iter != iterEnd; ++iter)
{
- LOG_ERROR("LayerManagerService", "Failed to load shared lib entry point: " << dlsym_error);
+ IPlugin* plugin = *iter;
+ if (plugin)
+ {
+ LOG_INFO("PluginManager", "plugin " << plugin->pluginGetName() << " destroyed");
+ delete plugin;
+ }
}
-
- // Note: free these resources on shutdown
- //dlclose(libraryHandle);
-
- return createFunction;
+ mPluginList.clear();
}
-void getSharedLibrariesFromDirectory(tFileList& fileList, string dirName)
+void PluginManager::getRendererList(RendererList& list)
{
- // open directory
- DIR *directory = opendir(dirName.c_str());
- if (!directory)
+ PluginList::const_iterator iter = mPluginList.begin();
+ PluginList::const_iterator iterEnd = mPluginList.end();
+
+ for (; iter != iterEnd; ++iter)
{
- LOG_ERROR("LayerManagerService", "Error(" << errno << ") opening " << dirName);
- return;
+ IPlugin* plugin = *iter;
+ ilmPluginApi api = plugin->pluginGetApi();
+ if (PLUGIN_IS_RENDERER(api))
+ {
+ IRenderer* renderer = dynamic_cast<IRenderer*>(plugin);
+ list.push_back(renderer);
+ }
}
+}
+
+void PluginManager::getHealthMonitorList(HealthMonitorList& list)
+{
+ PluginList::const_iterator iter = mPluginList.begin();
+ PluginList::const_iterator iterEnd = mPluginList.end();
- // iterate content of directory
- struct dirent *itemInDirectory = 0;
- while ((itemInDirectory = readdir(directory)))
+ for (; iter != iterEnd; ++iter)
{
- unsigned char entryType = itemInDirectory->d_type;
- string entryName = itemInDirectory->d_name;
-
- bool regularFile;
- bool sharedLibExtension = ("so" == entryName.substr(entryName.find_last_of(".") + 1));
-
- if ((entryType == DT_LNK) || (entryType == DT_UNKNOWN))
+ IPlugin* plugin = *iter;
+ ilmPluginApi api = plugin->pluginGetApi();
+ if (PLUGIN_IS_HEALTHMONITOR(api))
{
- struct stat st;
- string fpath = dirName + "/" + itemInDirectory->d_name;
-
- if (!stat(fpath.c_str(), &st))
- regularFile = S_ISREG(st.st_mode);
- else
+ IHealthMonitor* monitor = dynamic_cast<IHealthMonitor*>(plugin);
+ if (monitor)
{
- regularFile = false;
- LOG_WARNING("LayerManagerService", "Could not stat() file " << fpath << ": " << errno);
+ list.push_back(monitor);
}
}
- else
- {
- regularFile = (entryType == DT_REG);
- }
-
-
- if (regularFile && sharedLibExtension)
- {
- LOG_DEBUG("LayerManagerService", "adding file " << entryName);
- fileList.push_back(dirName + "/" + entryName);
- }
- else
- {
- LOG_DEBUG("LayerManagerService", "ignoring file " << entryName);;
- }
}
-
- closedir(directory);
}
-void loadHealthPlugins(HealthMonitorList& healthMonitorList, ICommandExecutor* executor)
+void PluginManager::getSceneProviderList(SceneProviderList& list)
{
- tFileList sharedLibraryNameList;
-
- // search sceneprovider plugins in configured directories
- for (uint dirIndex = 0; dirIndex < gScenePluginDirectoriesCount; ++dirIndex)
- {
- char directoryName[1024];
- strncpy(directoryName, gPluginLookupPath, sizeof(directoryName) - 1);
- strncat(directoryName, gHealthPluginDirectories[dirIndex], sizeof(directoryName) - 1 - strlen(directoryName));
- LOG_DEBUG("LayerManagerService", "Searching for HealthMonitors in: " << directoryName);
- getSharedLibrariesFromDirectory(sharedLibraryNameList, directoryName);
- }
-
- LOG_DEBUG("LayerManagerService", sharedLibraryNameList.size() << " HealthMonitor plugins found");
-
- // iterate all communicator plugins and start them
- tFileListIterator iter = sharedLibraryNameList.begin();
- tFileListIterator iterEnd = sharedLibraryNameList.end();
+ PluginList::const_iterator iter = mPluginList.begin();
+ PluginList::const_iterator iterEnd = mPluginList.end();
for (; iter != iterEnd; ++iter)
{
- LOG_INFO("LayerManagerService", "Loading HealthMonitor plugin " << *iter);
-
- IHealthMonitor* (*createFunc)(ICommandExecutor* executor);
- createFunc = getCreateFunction<IHealthMonitor*(ICommandExecutor* executor)>(*iter);
-
- if (!createFunc)
+ IPlugin* plugin = *iter;
+ ilmPluginApi api = plugin->pluginGetApi();
+ if (PLUGIN_IS_SCENEPROVIDER(api))
{
- LOG_DEBUG("LayerManagerService", "Entry point of HealthMonitor not found");
- continue;
- }
-
- LOG_DEBUG("LayerManagerService", "Creating HealthMonitor instance");
- IHealthMonitor* newHealthMonitor = createFunc(executor);
-
- if (!newHealthMonitor)
- {
- LOG_ERROR("LayerManagerService","HealthMonitor initialization failed. Entry Function not callable");
- continue;
+ ISceneProvider* sceneprovider = dynamic_cast<ISceneProvider*>(plugin);
+ list.push_back(sceneprovider);
}
-
- healthMonitorList.push_back(newHealthMonitor);
}
}
-
-void loadScenePlugins(SceneProviderList& sceneProviderList, ICommandExecutor* executor)
+void PluginManager::getCommunicatorList(CommunicatorList& list)
{
- tFileList sharedLibraryNameList;
-
- // search sceneprovider plugins in configured directories
- for (uint dirIndex = 0; dirIndex < gScenePluginDirectoriesCount; ++dirIndex)
- {
- char directoryName[1024];
- strncpy(directoryName, gPluginLookupPath, sizeof(directoryName) - 1);
- strncat(directoryName, gScenePluginDirectories[dirIndex], sizeof(directoryName) - 1 - strlen(directoryName));
- LOG_DEBUG("LayerManagerService", "Searching for SceneProviders in: " << directoryName);
- getSharedLibrariesFromDirectory(sharedLibraryNameList, directoryName);
- }
-
- LOG_DEBUG("LayerManagerService", sharedLibraryNameList.size() << " SceneProvider plugins found");
-
- // iterate all communicator plugins and start them
- tFileListIterator iter = sharedLibraryNameList.begin();
- tFileListIterator iterEnd = sharedLibraryNameList.end();
+ PluginList::const_iterator iter = mPluginList.begin();
+ PluginList::const_iterator iterEnd = mPluginList.end();
for (; iter != iterEnd; ++iter)
{
- LOG_INFO("LayerManagerService", "Loading SceneProvider plugin " << *iter);
-
- ISceneProvider* (*createFunc)(ICommandExecutor*);
- createFunc = getCreateFunction<ISceneProvider*(ICommandExecutor*)>(*iter);
-
- if (!createFunc)
+ IPlugin* plugin = *iter;
+ ilmPluginApi api = plugin->pluginGetApi();
+ if (PLUGIN_IS_COMMUNICATOR(api))
{
- LOG_DEBUG("LayerManagerService", "Entry point of SceneProvider not found");
- continue;
+ ICommunicator* comm = dynamic_cast<ICommunicator*>(plugin);
+ list.push_back(comm);
}
-
- LOG_DEBUG("LayerManagerService", "Creating SceneProvider instance");
- ISceneProvider* newSceneProvider = createFunc(executor);
-
- if (!newSceneProvider)
- {
- LOG_ERROR("LayerManagerService","SceneProvider initialization failed. Entry Function not callable");
- continue;
- }
-
- sceneProviderList.push_back(newSceneProvider);
}
}
-void loadCommunicatorPlugins(CommunicatorList& communicatorList, ICommandExecutor* executor)
+bool PluginManager::registerStaticPluginCreateFunction(StaticPluginCreateFunc func)
{
- tFileList sharedLibraryNameList;
-
- // search communicator plugins in configured directories
- for (uint dirIndex = 0; dirIndex < gCommunicatorPluginDirectoriesCount; ++dirIndex)
+ bool result = false;
+ if (func)
{
- char directoryName[1024];
- strncpy(directoryName, gPluginLookupPath, sizeof(directoryName) - strlen(directoryName));
- strncat(directoryName, gCommunicatorPluginDirectories[dirIndex], sizeof(directoryName) -strlen(directoryName));
- LOG_DEBUG("LayerManagerService", "Searching for communicator in: " << directoryName);
- getSharedLibrariesFromDirectory(sharedLibraryNameList, directoryName);
+ mStaticPluginCreateFuncList.push_back(func);
+ result = true;
}
-
- LOG_DEBUG("LayerManagerService", sharedLibraryNameList.size() << " Communicator plugins found");
-
- // iterate all communicator plugins and start them
- tFileListIterator iter = sharedLibraryNameList.begin();
- tFileListIterator iterEnd = sharedLibraryNameList.end();
+ return result;
+}
+
+void PluginManager::createStaticallyLinkedPlugins()
+{
+ StaticPluginCreateFuncList::iterator iter = mStaticPluginCreateFuncList.begin();
+ StaticPluginCreateFuncList::iterator iterEnd = mStaticPluginCreateFuncList.end();
for (; iter != iterEnd; ++iter)
{
- LOG_INFO("LayerManagerService", "Loading Communicator plugin " << *iter);
-
- ICommunicator* (*createFunc)(ICommandExecutor*);
- createFunc = getCreateFunction<ICommunicator*(ICommandExecutor*)>(*iter);
+ StaticPluginCreateFunc func = *iter;
+ IPlugin* plugin = (*func)(mExecutor, mConfiguration);
+ LOG_INFO("PluginManager", "creating plugin " << plugin->pluginGetName() << " (static linking)");
+ mPluginList.push_back(plugin);
+ }
+}
+
+void PluginManager::getAllFilesInPluginPath(std::string path)
+{
+ DIR *directory = opendir(path.c_str());
+ struct dirent *itemInDirectory = 0;
+
+ while (directory && (itemInDirectory = readdir(directory)))
+ {
+ unsigned char entryType = itemInDirectory->d_type;
+ std::string entryName = itemInDirectory->d_name;
+ std::string fullPath = path + "/" + entryName;
- if (!createFunc)
+ if (entryName.at(0) == '.')
{
- LOG_DEBUG("LayerManagerService", "Entry point of Communicator not found");
continue;
}
- LOG_DEBUG("LayerManagerService", "Creating Communicator instance");
- ICommunicator* newCommunicator = createFunc(executor);
-
- if (!newCommunicator)
+ switch (entryType)
{
- LOG_ERROR("LayerManagerService","Communicator initialization failed. Entry Function not callable");
- continue;
+ case DT_REG:
+ case DT_LNK:
+ case DT_UNKNOWN:
+ mFileList.push_back(fullPath);
+ LOG_DEBUG("PluginManager", "considering File " << fullPath);
+ break;
+
+ case DT_DIR:
+ getAllFilesInPluginPath(fullPath);
+ break;
+
+ default:
+ LOG_DEBUG("PluginManager", "ignored file " << fullPath);
+ break;
}
-
- communicatorList.push_back(newCommunicator);
}
+
+ closedir(directory);
}
-void loadRendererPlugins(RendererList& rendererList, IScene* pScene)
+void PluginManager::createDynamicallyLinkedPlugins()
{
- tFileList sharedLibraryNameList;
-
- // search communicator plugins in configured directories
- for (uint dirIndex = 0; dirIndex < gRendererPluginDirectoriesCount; ++dirIndex)
- {
- char directoryName[1024];
- strncpy(directoryName, gPluginLookupPath, sizeof(directoryName) - 1);
- strncat(directoryName, gRendererPluginDirectories[dirIndex], sizeof(directoryName) - 1 - strlen(directoryName));
- LOG_DEBUG("LayerManagerService", "Searching for renderer in: " << directoryName);
- getSharedLibrariesFromDirectory(sharedLibraryNameList, directoryName);
- }
-
- LOG_DEBUG("LayerManagerService", sharedLibraryNameList.size() << " Renderer plugins found");
-
- // currently the use of only one renderer is enforced
- if (sharedLibraryNameList.size() > 1)
- {
- LOG_WARNING("LayerManagerService", "more than 1 Renderer plugin found. using only " << sharedLibraryNameList.front());
- while (sharedLibraryNameList.size() > 1)
- {
- sharedLibraryNameList.pop_back();
- }
- }
-
- // iterate all renderer plugins and start them
- tFileListIterator iter = sharedLibraryNameList.begin();
- tFileListIterator iterEnd = sharedLibraryNameList.end();
+ FileList::const_iterator iter = mFileList.begin();
+ FileList::const_iterator iterEnd = mFileList.end();
for (; iter != iterEnd; ++iter)
{
- LOG_INFO("LayerManagerService", "Loading Renderer plugin " << *iter);
- IRenderer* (*createFunc)(IScene*);
- createFunc = getCreateFunction<IRenderer*(IScene*)>(*iter);
- if (!createFunc)
- {
- LOG_DEBUG("LayerManagerService", "Entry point of Renderer not found");
- continue;
- }
-
- LOG_DEBUG("LayerManagerService", "Creating Renderer instance");
- IRenderer* newRenderer = createFunc(pScene);
- if (!newRenderer)
+ IPlugin* plugin = createDynamicallyLinkedPlugin(*iter);
+ if (plugin)
{
- LOG_ERROR("LayerManagerService","Renderer initialization failed. Entry Function not callable");
- continue;
+ mPluginList.push_back(plugin);
}
-
- rendererList.push_back(newRenderer);
}
}
-
-//===========================================================================
-// class implementation
-//===========================================================================
-PluginManager::PluginManager(ICommandExecutor& executor, Configuration& config)
-: mExecutor(executor)
-, mConfiguration(config)
-{
- createAndStartAllPlugins();
-}
-
-PluginManager::~PluginManager()
-{
- stopAndDestroyAllPlugins();
-}
-
-RendererList* PluginManager::getRendererList()
-{
- return &mRendererList;
-}
-
-CommunicatorList* PluginManager::getCommunicatorList()
-{
- return &mCommunicatorList;
-}
-
-SceneProviderList* PluginManager::getSceneProviderList()
-{
- return &mSceneProviderList;
-}
-
-HealthMonitorList* PluginManager::getHealthMonitorList()
+IPlugin* PluginManager::createDynamicallyLinkedPlugin(std::string path)
{
- return &mHealthMonitorList;
-}
-
-void PluginManager::createAndStartAllPlugins()
-{
- gPluginLookupPath = mConfiguration.getPluginPath().c_str();
+ IPlugin* returnValue = NULL;
+
+ // open library
+ void *libraryHandle;
+ dlerror(); // Clear any existing error
+ libraryHandle = dlopen(path.c_str(), RTLD_NOW | RTLD_GLOBAL);
+ const char* dlopen_error = dlerror();
+ if (dlopen_error)
+ {
+ LOG_DEBUG("PluginManager", "not a shared library: " << dlopen_error);
+ return NULL;
+ }
- LOG_INFO("LayerManagerService", "Used plugin directory is " << gPluginLookupPath);
+ // load entry point
+ union
+ {
+ void* data;
+ IPlugin* (*createFunc)(ICommandExecutor&, Configuration&);
+ } convertUnion;
- LOG_DEBUG("LayerManagerService", "Loading renderer plugins.");
- loadRendererPlugins(mRendererList, mExecutor.getScene());
+ int cutBegin = path.find_last_of('/') + 4; // remove '*/lib' from name
+ int cutEnd = path.find_first_of('.', cutBegin); // remove '.extension' from name
- LOG_DEBUG("LayerManagerService", "Loading communicator plugins.");
- loadCommunicatorPlugins(mCommunicatorList, &mExecutor);
+ std::string createFunctionName = "create";
+ createFunctionName += path.substr(cutBegin, cutEnd - cutBegin);
- LOG_DEBUG("LayerManagerService", "Loading scene provider plugins.");
- loadScenePlugins(mSceneProviderList, &mExecutor);
-
- LOG_DEBUG("LayerManagerService", "Loading health monitor plugins.");
- loadHealthPlugins(mHealthMonitorList, &mExecutor);
-}
-
-void PluginManager::stopAndDestroyAllPlugins()
-{
- LOG_DEBUG("LayerManagerService", "Removing all scene provider plugins.")
- {
- SceneProviderListIterator iter = mSceneProviderList.begin();
- SceneProviderListIterator iterEnd = mSceneProviderList.end();
- for (; iter != iterEnd; ++iter)
- {
- ISceneProvider* sceneProvider = *iter;
- delete sceneProvider;
- }
- mSceneProviderList.clear();
- }
+ convertUnion.data = dlsym(libraryHandle, createFunctionName.c_str());
- LOG_DEBUG("LayerManagerService", "Removing all communicator plugins.")
+ // create plugin instance from entry point
+ const char* dlsym_error = dlerror();
+ if (convertUnion.data && !dlsym_error)
{
- CommunicatorListIterator iter = mCommunicatorList.begin();
- CommunicatorListIterator iterEnd = mCommunicatorList.end();
- for (; iter != iterEnd; ++iter)
- {
- ICommunicator* comm = *iter;
- delete comm;
- }
- mCommunicatorList.clear();
+ returnValue = convertUnion.createFunc(mExecutor, mConfiguration);
+ LOG_INFO("PluginManager", "creating plugin " << returnValue->pluginGetName() << " (dynamic linking)");
}
-
- LOG_DEBUG("LayerManagerService", "Removing all renderer plugins.")
+ else
{
- RendererListIterator iter = mRendererList.begin();
- RendererListIterator iterEnd = mRendererList.end();
- for (; iter != iterEnd; ++iter)
- {
- IRenderer* renderer = *iter;
- delete renderer;
- }
- mRendererList.clear();
+ LOG_DEBUG("PluginManager", "not a valid Plugin: " << path << ": " << dlsym_error);
+ dlclose(libraryHandle);
+ returnValue = NULL;
}
-}
+
+ return returnValue;
+}
\ No newline at end of file