// %pacpus:license{ // This file is part of the PACPUS framework distributed under the // CECILL-C License, Version 1.0. // %pacpus:license} /// @version $Id: ComponentManager.cpp 76 2013-01-10 17:05:10Z kurdejma $ #include #include #include #include #include #include using namespace pacpus; DECLARE_STATIC_LOGGER("pacpus.core.ComponentManager"); ComponentManager * ComponentManager::mInstance = NULL; ComponentManager * ComponentManager::create() { return getInstance(); } ComponentManager * ComponentManager::getInstance() { LOG_TRACE("getInstance()"); LOG_TRACE("before: mInstance = " << mInstance); if (!mInstance) { LOG_INFO("creating new instance..."); mInstance = new ComponentManager(); LOG_DEBUG("mInstance = " << mInstance); } LOG_TRACE("after : mInstance = " << mInstance); return mInstance; } void ComponentManager::destroy() { LOG_TRACE("destroy"); LOG_TRACE("before: mInstance = " << mInstance); delete mInstance; mInstance = NULL; LOG_TRACE("after : mInstance = " << mInstance); } ComponentManager::ComponentManager() { LOG_TRACE("constructor"); xmlTree_ = XmlConfigFile::create(); LOG_DEBUG("component manager was created"); } ComponentManager::~ComponentManager() { LOG_TRACE("destructor"); for (ComponentMap::iterator it = componentMap_.begin(), itend = componentMap_.end(); it != itend; ++it) { bool unregisteredSuccessfully = unregisterComponent(it.key()); } LOG_DEBUG("component manager was deleted"); } bool ComponentManager::registerComponentFactory(ComponentFactoryBase* addr, const QString& type) { LOG_TRACE("registerComponentFactory(type="<< type << ")"); if (factoryMap_.contains(type)) { LOG_WARN("cannot register a component factory of type '" << type << "'. It already belongs to the manager"); return false; } factoryMap_[type] = addr; LOG_INFO("registered component factory '" << type << "'"); return true; } bool ComponentManager::unregisterComponentFactory(const QString& type) { LOG_TRACE("unregisterComponentFactory(type="<< type << ")"); if (!factoryMap_.contains(type)) { LOG_WARN("cannot unregister component factory '" << type << "'. It was not registered"); return false; } factoryMap_.remove(type); LOG_INFO("unregistered component factory '" << type << "'"); return true; } bool ComponentManager::registerComponent(ComponentBase* addr, const QString& name) { LOG_TRACE("registerComponent(name="<< name << ")"); if (componentMap_.contains(name)) { LOG_WARN("cannot register component '" << name << "'. A component with the same name exists already"); return false; } componentMap_[name] = addr; LOG_INFO("registered component " << name); return true; } bool ComponentManager::unregisterComponent(const QString& name) { LOG_TRACE("unregisterComponent(name="<< name << ")"); if (!componentMap_.contains(name)) { LOG_WARN("cannot unregister component '" << name << "'. It was not registered"); return false; } // FIXME: delete component ComponentBase* component = componentMap_.value(name, NULL); //delete component; // FIXME: remove from map (causes segfault in QMap::qMapLessThanKey on Windows) //componentMap_.remove(name); LOG_INFO("unregistered component '" << name << "'"); return true; } bool ComponentManager::createComponent(const QString& type, const QString& name) { LOG_TRACE("createComponent(type=" << type << ", " << "name="<< name << ")"); if (factoryMap_.contains(type)) { ComponentFactoryBase* factory = factoryMap_.value(type); assert(factory); factory->addComponent(name); return true; } LOG_WARN("cannot create component '" << name << "'" << ". Component factory for type '" << type << "'" << " does not exist or was not registered" ); return false; } bool ComponentManager::loadPlugin(const QString& filename) { LOG_TRACE("loadPlugin(filename=" << filename << ")"); pluginLoader_.setFileName(filename); if (!pluginLoader_.load()) { LOG_ERROR("cannot load plugin '" << filename << "'" << ". Plugin loader returned error: " << pluginLoader_.errorString() ); return false; } QObject * plugin = pluginLoader_.instance(); if (NULL == plugin) { LOG_WARN("cannot create an instance of the plugin '" << filename << "'" << ". Plugin loader returned error: " << pluginLoader_.errorString() ); return false; } pluginList_.append(plugin); LOG_INFO("loaded plugin '" << qobject_cast(plugin)->name() << "'" << " from file '" << pluginLoader_.fileName() << "'" ); return true; } bool ComponentManager::createConnection(const QString& outputSignature, const QString& inputSignature, const QString& type, int priority = 0) { QStringList output = outputSignature.split("."); QStringList input = inputSignature.split("."); if(getComponent(output[0])==NULL) { LOG_WARN("cannot make connection : component " << output[0] << " not found"); return false;} if(getComponent(output[0])->getOutput(output[1]) == NULL) { LOG_WARN("cannot make connection : component " << output[0] << " doesn't have output " << output[1]); return false;} if(getComponent(input[0])==NULL) { LOG_WARN("cannot make connection : component " << input[0] << " not found"); return false;} if(getComponent(input[0])->getInput(input[1]) == NULL) { LOG_WARN("cannot make connection : component " << input[0] << " doesn't have intput " << input[1]); return false;} // NOTE Create communicationInterface if needed ?? return connectInterface(getComponent(output[0])->getOutput(output[1]), getComponent(input[0])->getInput(input[1]), priority); } std::size_t ComponentManager::loadComponents(const QString& configFilename) { LOG_TRACE("loadComponents(filename=" << configFilename << ")"); // load the components tree in memory xmlTree_->loadFile(configFilename); { // Load the plugins containing the components QStringList plugins = xmlTree_->getAllPluginsNames(); Q_FOREACH (QString plugin, plugins) { if (!loadPlugin(plugin)) { LOG_WARN("cannot load plugin '" << plugin << "'"); } else { LOG_INFO("successfully loaded plugin '" << plugin << "'"); } } } QDomNodeList componentsNodeList = xmlTree_->getAllComponents(); XmlComponentConfig cfg; // First, create all the components in the XML list for (int i = 0; i < componentsNodeList.size(); ++i) { cfg.localCopy(componentsNodeList.item(i).toElement()); QString componentType = cfg.getComponentType(); QString componentName = cfg.getComponentName(); LOG_DEBUG("try to create component '" << componentName << "'"); // create the component and automatically add it to the component manager list if (!createComponent(componentType, componentName)) { LOG_ERROR("cannot create component '" << componentName << "'"); continue; } } int componentsToConfigureCount = componentMap_.count(); // Second, try to configure the components without regarding the dependencies for (int i = 0; i < componentsNodeList.size(); ++i) { cfg.localCopy(componentsNodeList.item(i).toElement()); QString componentName = cfg.getComponentName(); LOG_DEBUG("try to configure component '" << componentName << "'"); // copy locally the config parameters of the component ComponentBase * component = getComponent(componentName); if (NULL == component) { LOG_WARN("component '" << componentName << "' does not exist"); } else { component->param.localCopy(cfg.qDomElement()); component->setConfigurationState(component->configureComponent(cfg)); } } // for // Third, if some components requested a delayed configuration, retry for (int i = 0; i < componentsNodeList.size(); ++i) { cfg.localCopy(componentsNodeList.item(i).toElement()); QString componentName = cfg.getComponentName(); ComponentBase * component = getComponent(componentName); if (NULL == component) { LOG_WARN("component '" << componentName << "' does not exist"); } else { // Pacpus 2.0 : add inputs and outputs component->addInputs(); component->addOutputs(); if (ComponentBase::CONFIGURATION_DELAYED == component->configurationState()) { LOG_DEBUG("try to configure component '" << componentName << "'"); // copy locally the config parameters of the component component->param.localCopy(cfg.qDomElement()); component->setConfigurationState(component->configureComponent(cfg)); } if (ComponentBase::CONFIGURED_OK == component->configurationState()) { --componentsToConfigureCount; } else { LOG_ERROR("cannot configure component '" << componentName << "'" << ". Dependencies with other components are too complex" << ". It was not configured, please review your configuration and/or your component" ); component->setConfigurationState(ComponentBase::CONFIGURED_FAILED); } } } // for LOG_INFO(componentMap_.count() << " component(s) were loaded"); if (componentsToConfigureCount > 0) { LOG_WARN(componentsToConfigureCount << " component(s) were not configured"); } // Fourthly, create connections find in the XML list QDomNodeList connectionsNodeList = xmlTree_->getAllConnections(); for (int i = 0; i < connectionsNodeList.size(); ++i) { cfg.localCopy(connectionsNodeList.item(i).toElement()); QString connectionInput = cfg.getConnectionInput(); QString connectionOutput = cfg.getConnectionOutput(); QString connectionType = cfg.getConnectionType(); int connectionPriority = cfg.getConnectionPriority(); //TODO set connection mode from string //InputInterfaceBase::GetLast; //InputInterfaceBase::NeverSkip; //InputInterfaceBase::TimeBounded; if (!createConnection(connectionOutput, connectionInput, connectionType,connectionPriority)) { LOG_ERROR("cannot create connection '" << connectionOutput+"=>"+connectionInput << "'"); continue; } } // for return componentMap_.count(); } bool ComponentManager::start() { LOG_TRACE("start()"); bool result = true; for (ComponentMap::iterator it = componentMap_.begin(), itend = componentMap_.end(); it != itend; ++it) { result &= start(it.key()); } return result; } bool ComponentManager::start(const QString& componentName) { LOG_TRACE("start(component=" << componentName << ")"); ComponentBase* component = getComponent(componentName); if (!component) { LOG_WARN("cannot start component '" << componentName << "'. It does not exist!"); return false; } LOG_INFO("starting component '" << componentName << "'..."); if (!component->startComponent()) { LOG_WARN("cannot start component '" << componentName << "'. It can already be started"); } return true; } bool ComponentManager::stop() { LOG_TRACE("stop()"); bool result = true; for (ComponentMap::iterator it = componentMap_.begin(), itend = componentMap_.end(); it != itend; ++it) { result &= stop(*it); } return result; } bool ComponentManager::stop(ComponentBase* component) const { if (!component) { LOG_WARN("NULL component pointer"); return false; } if (!component->stopComponent()) { return false; } return true; } bool ComponentManager::stop(const QString& componentName) { LOG_TRACE("stop(component=" << componentName << ")"); ComponentBase* component = getComponent(componentName); if (!component) { LOG_WARN("cannot stop component '" << componentName << "'" << ". It does not exist"); return false; } LOG_INFO("stopping component '" << componentName << "'..."); if (!stop(component)) { LOG_WARN("cannot stop component '" << componentName << "'" << ". It can be already stopped"); } return true; } ComponentBase* ComponentManager::getComponent(const QString& name) { LOG_TRACE("getComponent(name=" << name << ")"); ComponentMap::iterator it = componentMap_.find(name); if (it != componentMap_.end()) { return *it; } LOG_WARN("cannot retrieve component '" << name << "'" << ". It does not exist"); return NULL; } QStringList ComponentManager::getAllComponentsName() const { LOG_TRACE("getAllComponentsName()"); return xmlTree_->getAllComponentsNames(); }