ServicesServer.hh 7.13 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 "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 &, int) > StatisticProcessFactory;
typedef std::map<std::string, StatisticProcessFactory> StatisticProcessFactories;

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) const {
    	 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)  {
		return _paramOutputFactory[paramOutputId]();
	}

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

	StatisticProcess* getStatisticProcess(std::string processId, Parameter &parameter, int index)  {
		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) {
    	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;
    }

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;

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

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