/*
* Copyright (c) 2011-2015, Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <algorithm>
#include "SystemClass.h"
#include "SubsystemLibrary.h"
#include "VirtualSubsystem.h"
#include "LoggingElementBuilderTemplate.h"
#include <cassert>
#include "PluginLocation.h"
#include "DynamicLibrary.hpp"
#include "Utility.h"
#include "Memory.hpp"
#define base CConfigurableElement
#ifndef PARAMETER_FRAMEWORK_PLUGIN_ENTRYPOINT_V1
#error Missing PARAMETER_FRAMEWORK_PLUGIN_ENTRYPOINT_V1 macro definition
#endif
#define QUOTE(X) #X
#define MACRO_TO_STR(X) QUOTE(X)
const char CSystemClass::entryPointSymbol[] =
MACRO_TO_STR(PARAMETER_FRAMEWORK_PLUGIN_ENTRYPOINT_V1);
using PluginEntryPointV1 = void (*)(CSubsystemLibrary *, core::log::Logger &);
using std::list;
using std::string;
// FIXME: integrate SystemClass to core namespace
using namespace core;
CSystemClass::CSystemClass(log::Logger &logger)
: _pSubsystemLibrary(new CSubsystemLibrary()), _logger(logger)
{
}
CSystemClass::~CSystemClass()
{
delete _pSubsystemLibrary;
// Destroy child subsystems *before* unloading the libraries (otherwise crashes will occur
// as unmapped code will be referenced)
clean();
}
bool CSystemClass::childrenAreDynamic() const
{
return true;
}
string CSystemClass::getKind() const
{
return "SystemClass";
}
bool CSystemClass::getMappingData(const std::string & /*strKey*/,
const std::string *& /*pStrValue*/) const
{
// Although it could make sense to have mapping in the system class,
// just like at subsystem level, it is currently not supported.
return false;
}
string CSystemClass::getFormattedMapping() const
{
return "";
}
bool CSystemClass::loadSubsystems(string &strError, const CSubsystemPlugins *pSubsystemPlugins,
bool bVirtualSubsystemFallback)
{
// Start clean
_pSubsystemLibrary->clean();
typedef TLoggingElementBuilderTemplate<CVirtualSubsystem> VirtualSubsystemBuilder;
// Add virtual subsystem builder
_pSubsystemLibrary->addElementBuilder("Virtual", new VirtualSubsystemBuilder(_logger));
// Set virtual subsytem as builder fallback if required
if (bVirtualSubsystemFallback) {
_pSubsystemLibrary->setDefaultBuilder(
utility::make_unique<VirtualSubsystemBuilder>(_logger));
}
// Add subsystem defined in shared libraries
core::Results errors;
bool bLoadPluginsSuccess = loadSubsystemsFromSharedLibraries(errors, pSubsystemPlugins);
// Fill strError for caller, he has to decide if there is a problem depending on
// bVirtualSubsystemFallback value
strError = utility::asString(errors);
return bLoadPluginsSuccess || bVirtualSubsystemFallback;
}
bool CSystemClass::loadSubsystemsFromSharedLibraries(core::Results &errors,
const CSubsystemPlugins *pSubsystemPlugins)
{
// Plugin list
list<string> lstrPluginFiles;
size_t pluginLocation;
for (pluginLocation = 0; pluginLocation < pSubsystemPlugins->getNbChildren();
pluginLocation++) {
// Get Folder for current Plugin Location
const CPluginLocation *pPluginLocation =
static_cast<const CPluginLocation *>(pSubsystemPlugins->getChild(pluginLocation));
string strFolder(pPluginLocation->getFolder());
if (!strFolder.empty()) {
strFolder += "/";
}
// Iterator on Plugin List:
list<string>::const_iterator it;
const list<string> &pluginList = pPluginLocation->getPluginList();
for (it = pluginList.begin(); it != pluginList.end(); ++it) {
// Fill Plugin files list
lstrPluginFiles.push_back(strFolder + *it);
}
}
// Actually load plugins
while (!lstrPluginFiles.empty()) {
// Because plugins might depend on one another, loading will be done
// as an iteration process that finishes successfully when the remaining
// list of plugins to load gets empty or unsuccessfully if the loading
// process failed to load at least one of them
// Attempt to load the complete list
if (!loadPlugins(lstrPluginFiles, errors)) {
// Unable to load at least one plugin
break;
}
}
if (!lstrPluginFiles.empty()) {
// Unable to load at least one plugin
errors.push_back("Unable to load the following plugins: " +
utility::asString(lstrPluginFiles, ", ") + ".");
return false;
}
return true;
}
// Plugin loading
bool CSystemClass::loadPlugins(list<string> &lstrPluginFiles, core::Results &errors)
{
assert(lstrPluginFiles.size());
bool bAtLeastOneSubsystemPluginSuccessfullyLoaded = false;
list<string>::iterator it = lstrPluginFiles.begin();
while (it != lstrPluginFiles.end()) {
string strPluginFileName = *it;
// Load attempt
try {
auto library = utility::make_unique<DynamicLibrary>(strPluginFileName);
// Load symbol from library
auto subSystemBuilder = library->getSymbol<PluginEntryPointV1>(entryPointSymbol);
// Store libraries handles
_subsystemLibraryHandleList.push_back(std::move(library));
// Fill library
subSystemBuilder(_pSubsystemLibrary, _logger);
} catch (std::exception &e) {
errors.push_back(e.what());
// Next plugin
++it;
continue;
}
// Account for this success
bAtLeastOneSubsystemPluginSuccessfullyLoaded = true;
// Remove successfully loaded plugin from list and select next
lstrPluginFiles.erase(it++);
}
return bAtLeastOneSubsystemPluginSuccessfullyLoaded;
}
const CSubsystemLibrary *CSystemClass::getSubsystemLibrary() const
{
return _pSubsystemLibrary;
}
void CSystemClass::checkForSubsystemsToResync(CSyncerSet &syncerSet, core::Results &infos)
{
size_t uiNbChildren = getNbChildren();
size_t uiChild;
for (uiChild = 0; uiChild < uiNbChildren; uiChild++) {
CSubsystem *pSubsystem = static_cast<CSubsystem *>(getChild(uiChild));
// Collect and consume the need for a resync
if (pSubsystem->needResync(true)) {
infos.push_back("Resynchronizing subsystem: " + pSubsystem->getName());
// get all subsystem syncers
pSubsystem->fillSyncerSet(syncerSet);
}
}
}
void CSystemClass::cleanSubsystemsNeedToResync()
{
size_t uiNbChildren = getNbChildren();
size_t uiChild;
for (uiChild = 0; uiChild < uiNbChildren; uiChild++) {
CSubsystem *pSubsystem = static_cast<CSubsystem *>(getChild(uiChild));
// Consume the need for a resync
pSubsystem->needResync(true);
}
}