ServicesServer.hh 11.4 KB
/*
 * ServicesServer.h
 *
 *  Created on: Nov 12, 2012
 *      Author: g.schneller
 */

#ifndef SERVICESSERVER_H_
#define SERVICESSERVER_H_


#include <map>
#include <string>
#include <typeinfo>
#include <list>
#include <boost/any.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/functional/factory.hpp>
#include <boost/shared_ptr.hpp>
#include <vector>
#include <string>
#include "log4cxx/logger.h"

#include "dsgpatt_Singleton.hh"
#include "Demangle.hh"

#include "AMDA_exception.hh"

namespace AMDA {
    namespace Parameters {

        //use class
        class ServicesServer;
        class ParamGet;
        class Process;
        class ParamOutput;
        class Parameter;
        class StatisticProcess;

        typedef boost::shared_ptr<ServicesServer> ServicesServerSPtr;

        // ParamGet factory definition
        typedef boost::function < ParamGet*(Parameter &) > ParamGetFactory;
        typedef std::map<std::string, ParamGetFactory> ParamGetFactories;

        // Process factory definition
        typedef boost::function < Process*(Parameter &) > ProcessFactory;
        typedef std::map<std::string, ProcessFactory> ProcessFactories;

        // ParamOutput factory definition
        typedef boost::function < ParamOutput*() > ParamOutputFactory;
        typedef std::map<std::string, ParamOutputFactory> ParamOutputFactories;

        // StatisticProcess factory definition
        typedef boost::function < StatisticProcess*(Parameter &, const int&) > StatisticProcessFactory;
        typedef std::map<std::string, StatisticProcessFactory> StatisticProcessFactories;

        // map to link  process with pluging
        typedef std::map<std::string, std::map<std::string, std::string>> AMDA_ProcessPluginMaps;

        class FileConfigurator;
        typedef boost::shared_ptr<FileConfigurator> ParameterConfiguratorSPtr;

        /**
         * @class ServicesServer
         * @brief To call to register needed Services or to notify implemented Services
         * @details This Singleton class is frequently called into the registerPlugin method to notify one or more Services implementation as Process, ParamGet and ParamOutput.
         */
        class ServicesServer : public ::Singleton<ServicesServer> {
        public:
            // Design pattern
            friend class Singleton<ServicesServer>;
            typedef std::list<boost::any> ServiceList;

            struct exception : virtual AMDA_exception {
            };

            /**
             *  @brief Add a Service implementation
             */
            template<typename T>
            void addService(T v) {
                _serviceList.push_back(v);
            }

            /**
             *  @brief Add a Service implementation
             */
            template<typename T>
            void declareService() {
                typedef typename std::map<std::string, T> TServiceImpList;
                for (ServiceList::const_reverse_iterator rit = _serviceList.rbegin(); rit != _serviceList.rend(); ++rit) {
                    if ((*rit).type() == typeid (TServiceImpList)) {
                        std::stringstream oss;
                        oss << "Service already declared: " << Helpers::Demangle(typeid (T).name());
                        BOOST_THROW_EXCEPTION(exception() << AMDA::ex_msg(oss.str()));
                    }
                }
                _serviceList.push_back(TServiceImpList());
            }

            /**
             *  @brief Add a Service implementation
             */
            template<typename T>
            void addServiceImpl(std::string name, T t) {
                typedef typename std::map<std::string, T> TServiceImpList;
                ServiceList::iterator it = _serviceList.begin();
                for (; it != _serviceList.end(); ++it) {
                    if ((*it).type() == typeid (TServiceImpList)) {
                        TServiceImpList& list = boost::any_cast<TServiceImpList&>(*it);
                        list.insert(make_pair(name, t));
                        break;
                    }
                }
                if (it == _serviceList.end()) {
                    _serviceList.push_back(TServiceImpList());
                    ServiceList::iterator it = _serviceList.end();
                    TServiceImpList& list = boost::any_cast<TServiceImpList&>(*(--it));
                    list.insert(make_pair(name, t));
                }
            }

            /**
             * @brief Search a Service implementation by this type.
             * @return Service or NULL if not found.
             */
            template<typename T>
            T getService() const {
                for (ServiceList::const_reverse_iterator rit = _serviceList.rbegin(); rit != _serviceList.rend(); ++rit) {
                    if ((*rit).type() == typeid (T)) {
                        return boost::any_cast<T>(*rit);
                    }
                }
                return NULL;
            }

            /**
             * @brief Search a Service implementation by this type.
             * @return Service or NULL if not found.
             */
            template<typename T>
            T getService(const std::string& pImplName){
                if (_PLUGINS_DYNAMIC_LOADING)
                         loadPlugin(pImplName);
                typedef typename std::map<std::string, T> TServiceImpList;
                for (ServiceList::const_reverse_iterator rit = _serviceList.rbegin(); rit != _serviceList.rend(); ++rit) {
                    if ((*rit).type() == typeid (TServiceImpList)) {
                        TServiceImpList list = boost::any_cast<TServiceImpList>(*rit);
                        typename TServiceImpList::iterator it = list.find(pImplName);
                        if (it != list.end()) {
                            return it->second;
                        } else {
                            return NULL;
                        }
                    }
                }
                return NULL;
            }

            ParamOutput* getParamOutput(std::string paramOutputId) {
                if (_PLUGINS_DYNAMIC_LOADING)
                    loadPlugin(paramOutputId, "paramOutputs");
                return _paramOutputFactory[paramOutputId]();
            }

            void addParamOutputFactory(std::string paramOutputId, ParamOutputFactory paramOutputFactory) {
                _paramOutputFactory[paramOutputId] = paramOutputFactory;
            }

            StatisticProcess* getStatisticProcess(std::string processId, Parameter &parameter, int index) {
                if (_PLUGINS_DYNAMIC_LOADING)
                    loadPlugin(processId, "statisticProcess");
                return _statisticProcessFactory[processId](parameter, index);
            }

            void addStatisticProcessFactory(std::string processId, StatisticProcessFactory statisticProcessFactory) {
                _statisticProcessFactory[processId] = statisticProcessFactory;
            }

            ParamGet* getParamGet(std::string paramGetId, Parameter &parameter) {
                return _paramGetFactory[paramGetId](parameter);
            }

            void addParamGetFactory(std::string paramGetId, ParamGetFactory paramGetFactory) {
                _paramGetFactory[paramGetId] = paramGetFactory;
            }

            Process* getProcess(std::string processId, Parameter &parameter) {
                if (_PLUGINS_DYNAMIC_LOADING)
                    loadPlugin(processId, "process");
                auto lIt = _processFactory.find(processId);
                return (lIt == _processFactory.end()) ? nullptr : lIt->second(parameter);
            }

            void addProcessFactory(std::string processId, ProcessFactory processFactory) {
                _processFactory[processId] = processFactory;
            }

            // Get methods

            ParameterConfiguratorSPtr& getConfigurator() {
                return _configurator;
            }

            // Set methods

            void setConfigurator(ParameterConfiguratorSPtr &configurator) {
                _configurator = configurator;
            }

            // link Process with the corresponding Plugin

            void linkProcessWithPlugin(std::string process, std::string pluginPath) {
                if (pluginPath != "")
                    _processPluginMaps["process"].insert(std::pair<std::string, std::string>(process, pluginPath));
            }

            void linkStatisticProcessWithPlugin(std::string process, std::string pluginPath) {
                if (pluginPath != "")
                    _processPluginMaps["statisticProcess"].insert(std::pair<std::string, std::string>(process, pluginPath));
            }

            void linkParamOutputsWithPlugin(std::string process, std::string pluginPath) {
                if (pluginPath != "")
                    _processPluginMaps["paramOutputs"].insert(std::pair<std::string, std::string>(process, pluginPath));
            }

            void linkParamGetWithPlugin(std::string process, std::string pluginPath) {
                _processPluginMaps["paramGet"].insert(std::pair<std::string, std::string>(process, pluginPath));
            }

            bool generatePluginsXml(const char* filePath);

            bool fillPluginsMap(std::string xmlFile, std::string xsdFile);

            void setPluginsDynamicLoading(bool isPluginsDynamicLoading) {
                _PLUGINS_DYNAMIC_LOADING = isPluginsDynamicLoading;
            }

            bool getPluginsDynamicLoading() {
                return _PLUGINS_DYNAMIC_LOADING;
            }

            bool loadPlugin(const std::string& process, const std::string& type = "");

            bool loadPluginByType(const std::string& type);

            bool loadPluginsFromRequest(const char* requestXML);

            std::list<std::string> getPluginsToLoad() {
                return _pluginsToLoad;
            }

        private:

            ServicesServer();
            virtual ~ServicesServer();

            /**
             * Factory of ParamGet
             * for a string are a sourceParmGet, use
             * @code ParamGet p = _paramGetFactory[souceParamGet]()
             */
            ParamGetFactories _paramGetFactory;

            /**
             * Factory of Process
             * for a string are a sourceProcess, use
             * @code Process p = _processFactory[souceProcess]()
             */
            ProcessFactories _processFactory;

            /**
             * Factory of ParamOutput
             * for a string are a sourceParmOutput, use
             * @code ParamOutput p = _paramOutputFactory[souceParamGet]()
             */
            ParamOutputFactories _paramOutputFactory;

            /**
             * Factory of StatisticProcess
             */
            StatisticProcessFactories _statisticProcessFactory;

            ParameterConfiguratorSPtr _configurator;

            /**
             * Map of processes and corresponding plugins  
             */
            AMDA_ProcessPluginMaps _processPluginMaps;

            /**
             * List of services.
             */
            ServiceList _serviceList;

            static bool _PLUGINS_DYNAMIC_LOADING;

            std::list<std::string> _pluginsToLoad;

            std::list<std::string> _outputs{"<download", "<dataMining", "<plot", "<statistic", "<int:ervalTrue", "<intervalTrue"};

            static log4cxx::LoggerPtr _logger;
        };

    } /* namespace Parameters */
} /* namespace AMDA */
#endif /* SERVICESSERVER_H_ */