diff --git a/fairmq/CMakeLists.txt b/fairmq/CMakeLists.txt index a8524124..7092f6ba 100644 --- a/fairmq/CMakeLists.txt +++ b/fairmq/CMakeLists.txt @@ -5,10 +5,13 @@ # GNU Lesser General Public Licence version 3 (LGPL) version 3, # # copied verbatim in the file "LICENSE" # ################################################################################ +#Temporary for test +add_subdirectory (options/ProgOptionTest) Set(INCLUDE_DIRECTORIES ${CMAKE_SOURCE_DIR}/fairmq ${CMAKE_SOURCE_DIR}/fairmq/devices ${CMAKE_SOURCE_DIR}/fairmq/tools + ${CMAKE_SOURCE_DIR}/fairmq/options ) Set(SYSTEM_INCLUDE_DIRECTORIES @@ -71,6 +74,9 @@ set(SRCS "devices/FairMQProxy.cxx" "devices/FairMQSplitter.cxx" "devices/FairMQMerger.cxx" + "options/FairProgOptions.cxx" + "options/FairMQProgOptions.cxx" + "options/FairMQChannel.cxx" "FairMQPoller.cxx" "examples/req-rep/FairMQExampleClient.cxx" "examples/req-rep/FairMQExampleServer.cxx" diff --git a/fairmq/FairMQLogger.h b/fairmq/FairMQLogger.h index 6dc56f64..cb250f3e 100644 --- a/fairmq/FairMQLogger.h +++ b/fairmq/FairMQLogger.h @@ -58,5 +58,6 @@ timestamp_t get_timestamp(); #define LOG(type) FairMQLogger().Log(FairMQLogger::type) #define MQLOG(type) FairMQLogger().Log(FairMQLogger::type) #define SET_LOG_LEVEL(loglevel) FairMQLogger::SetLogLevel(FairMQLogger::loglevel) +#define SET_LOGGER_LEVEL(loglevel) FairMQLogger::SetLogLevel(loglevel) #endif /* FAIRMQLOGGER_H_ */ diff --git a/fairmq/options/FairMQChannel.cxx b/fairmq/options/FairMQChannel.cxx new file mode 100644 index 00000000..27faa60b --- /dev/null +++ b/fairmq/options/FairMQChannel.cxx @@ -0,0 +1,143 @@ +/******************************************************************************** + * Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH * + * * + * This software is distributed under the terms of the * + * GNU Lesser General Public Licence version 3 (LGPL) version 3, * + * copied verbatim in the file "LICENSE" * + ********************************************************************************/ +/** + * FairMQChannel.cxx + * + * @since 2015-06-02 + * @author A. Rybalchenko + */ + +#include + +#include "FairMQChannel.h" +#include "FairMQLogger.h" + +using namespace std; + +FairMQChannel::FairMQChannel() + : fType("unspecified") + , fMethod("unspecified") + , fProtocol("unspecified") + , fAddress("unspecified") + , fPort("unspecified") + , fSndBufSize(1000) + , fRcvBufSize(1000) + , fRateLogging(1) + , fSocket() + , fIsValid(false) + , fChannelName("") +{ +} + +FairMQChannel::FairMQChannel(string type, string method, string protocol, string address, string port) + : fType(type) + , fMethod(method) + , fProtocol(protocol) + , fAddress(address) + , fPort(port) + , fSndBufSize(1000) + , fRcvBufSize(1000) + , fRateLogging(1) + , fSocket() + , fIsValid(false) + , fChannelName("") +{ +} + +bool FairMQChannel::ValidateChannel() +{ + LOG(DEBUG) << "Validating channel " << fChannelName << "... "; + if (fIsValid) + { + LOG(DEBUG) << "Channel is already valid"; + return true; + } + + const string socketTypeNames[] = { "sub", "pub", "pull", "push", "req", "rep", "xsub", "xpub", "dealer", "router", "pair" }; + const set socketTypes(socketTypeNames, socketTypeNames + sizeof(socketTypeNames) / sizeof(string)); + if (socketTypes.find(fType) == socketTypes.end()) + { + LOG(DEBUG) << "Invalid channel type: " << fType; + fIsValid = false; + return false; + } + + const string socketMethodNames[] = { "bind", "connect" }; + const set socketMethods(socketMethodNames, socketMethodNames + sizeof(socketMethodNames) / sizeof(string)); + if (socketMethods.find(fMethod) == socketMethods.end()) + { + LOG(DEBUG) << "Invalid channel method: " << fMethod; + fIsValid = false; + return false; + } + + const string socketProtocolNames[] = { "tcp", "ipc", "inproc" }; + const set socketProtocols(socketProtocolNames, socketProtocolNames + sizeof(socketProtocolNames) / sizeof(string)); + if (socketProtocols.find(fProtocol) == socketProtocols.end()) + { + LOG(DEBUG) << "Invalid channel protocol: " << fProtocol; + fIsValid = false; + return false; + } + + if (fAddress == "unspecified" && fAddress == "") + { + LOG(DEBUG) << "invalid channel address: " << fAddress; + fIsValid = false; + return false; + } + + if (fPort == "unspecified" && fPort == "") + { + LOG(DEBUG) << "invalid channel port: " << fPort; + fIsValid = false; + return false; + } + + if (fSndBufSize < 0) + { + LOG(DEBUG) << "invalid channel send buffer size: " << fSndBufSize; + fIsValid = false; + return false; + } + + if (fRcvBufSize < 0) + { + LOG(DEBUG) << "invalid channel receive buffer size: " << fRcvBufSize; + fIsValid = false; + return false; + } + + LOG(DEBUG) << "Channel is valid"; + fIsValid = true; + return true; +} + +int FairMQChannel::Send(FairMQMessage* msg, const string& flag) +{ + return fSocket->Send(msg, flag); +} + +int FairMQChannel::Send(FairMQMessage* msg, const int flags) +{ + return fSocket->Send(msg, flags); +} + +int FairMQChannel::Receive(FairMQMessage* msg, const string& flag) +{ + return fSocket->Receive(msg, flag); +} + +int FairMQChannel::Receive(FairMQMessage* msg, const int flags) +{ + return fSocket->Receive(msg, flags); +} + +FairMQChannel::~FairMQChannel() +{ +} diff --git a/fairmq/options/FairMQChannel.h b/fairmq/options/FairMQChannel.h new file mode 100644 index 00000000..56f86fd3 --- /dev/null +++ b/fairmq/options/FairMQChannel.h @@ -0,0 +1,54 @@ +/******************************************************************************** + * Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH * + * * + * This software is distributed under the terms of the * + * GNU Lesser General Public Licence version 3 (LGPL) version 3, * + * copied verbatim in the file "LICENSE" * + ********************************************************************************/ +/** + * FairMQChannel.h + * + * @since 2015-06-02 + * @author A. Rybalchenko + */ + +#ifndef FAIRMQCHANNEL_H_ +#define FAIRMQCHANNEL_H_ + +#include + +#include "FairMQSocket.h" + +class FairMQChannel +{ + friend class FairMQDevice; + + public: + FairMQChannel(); + FairMQChannel(std::string type, std::string method, std::string protocol, std::string address, std::string port); + virtual ~FairMQChannel(); + + bool ValidateChannel(); + + // Wrappers for the socket methods to simplify the usage of channels + int Send(FairMQMessage* msg, const std::string& flag=""); + int Send(FairMQMessage* msg, const int flags); + int Receive(FairMQMessage* msg, const std::string& flag=""); + int Receive(FairMQMessage* msg, const int flags); + + std::string fType; + std::string fMethod; + std::string fProtocol; + std::string fAddress; + std::string fPort; + int fSndBufSize; + int fRcvBufSize; + int fRateLogging; + + private: + FairMQSocket* fSocket; + bool fIsValid; + std::string fChannelName; +}; + +#endif /* FAIRMQCHANNEL_H_ */ \ No newline at end of file diff --git a/fairmq/options/FairMQProgOptions.cxx b/fairmq/options/FairMQProgOptions.cxx new file mode 100644 index 00000000..30aa6ff1 --- /dev/null +++ b/fairmq/options/FairMQProgOptions.cxx @@ -0,0 +1,106 @@ +/* + * File: FairMQProgOptions.cxx + * Author: winckler + * + * Created on March 11, 2015, 10:20 PM + */ + +#include "FairMQProgOptions.h" +#include + +FairMQProgOptions::FairMQProgOptions() : + FairProgOptions(), + fMQParserOptions("MQ-Device parser options"), + fMQtree(), + fFairMQmap() +{ + InitOptionDescription(); +} + +FairMQProgOptions::~FairMQProgOptions() +{ +} + + + +int FairMQProgOptions::ParseAll(const int argc, char** argv, bool AllowUnregistered) +{ + // before parsing, define cmdline and optionally cfgfile description, + // and also what is visible for the user + AddToCmdLineOptions(fGenericDesc); + AddToCmdLineOptions(fMQParserOptions); + + // if config file option enabled then id non required in cmdline but required in configfile + // else required in cmdline + if(fUseConfigFile) + { + fCmdline_options.add_options() + ("device-id", po::value< std::string >(), "Device ID"); + fConfig_file_options.add_options() + ("device-id", po::value< std::string >()->required(), "Device ID"); + } + else + fCmdline_options.add_options() + ("device-id", po::value< std::string >()->required(), "Device ID"); + + fVisible_options.add_options() + ("device-id", po::value< std::string >()->required(), "Device ID (required value)"); + + + // parse command line + if(ParseCmdLine(argc,argv,fCmdline_options,fvarmap,AllowUnregistered)) + return 1; + + // if txt/INI configuration file enabled then parse it + if(fUseConfigFile && !fConfigFile.empty()) + { + AddToCfgFileOptions(fMQParserOptions,false); + + if(ParseCfgFile(fConfigFile,fConfig_file_options,fvarmap,AllowUnregistered)) + return 1; + } + + + // set log level before printing (default is 0 = DEBUG level) + int verbose=GetValue("verbose"); + SET_LOGGER_LEVEL(verbose); + + PrintOptions(); + + return 0; +} + + + + +int FairMQProgOptions::NotifySwitchOption() +{ + if ( fvarmap.count("help") ) + { + std::cout << "***** FAIRMQ Program Options ***** \n" << fVisible_options; + return 1; + } + + if (fvarmap.count("version")) + { + std::cout << "Beta version 0.1\n"; + return 1; + } + + return 0; +} + + +void FairMQProgOptions::InitOptionDescription() +{ + fMQParserOptions.add_options() + ("config-xml-string", po::value< std::vector >()->multitoken(), "XML input as command line string.") + ("config-xml-filename", po::value< std::string >(), "XML input as file.") + ("config-json-string", po::value< std::vector >()->multitoken(), "JSON input as command line string.") + ("config-json-filename", po::value< std::string >(), "JSON input as file.") + + //("ini.config.string", po::value< std::vector >()->multitoken(), "INI input as command line string.") + //("ini.config.filename", po::value< std::string >(), "INI input as file.") + ; + +} \ No newline at end of file diff --git a/fairmq/options/FairMQProgOptions.h b/fairmq/options/FairMQProgOptions.h new file mode 100644 index 00000000..c0f40ab6 --- /dev/null +++ b/fairmq/options/FairMQProgOptions.h @@ -0,0 +1,80 @@ +/* + * File: FairMQProgOptions.h + * Author: winckler + * + * Created on March 11, 2015, 10:20 PM + */ + +#ifndef FAIRMQPROGOPTIONS_H +#define FAIRMQPROGOPTIONS_H + +#include "FairProgOptions.h" + +#include "FairMQChannel.h" +#include + +namespace pt = boost::property_tree; +class FairMQProgOptions : public FairProgOptions +{ +protected: + typedef std::map > FairMQMap; + +public: + FairMQProgOptions(); + virtual ~FairMQProgOptions(); + virtual int ParseAll(const int argc, char** argv, bool AllowUnregistered=false); + + + // external parser, store function + template < typename T, typename ...Args> + int UserParser(Args &&... args) + { + try + { + Store( T().UserParser(std::forward(args)...) ); + } + catch (std::exception& e) + { + MQLOG(ERROR) << e.what(); + return 1; + } + return 0; + } + + int Store(const po::variables_map& vm) + { + fvarmap = vm; + return 0; + } + + int Store(const pt::ptree& tree) + { + fMQtree = tree; + return 0; + } + + int Store(const FairMQMap& channels) + { + fFairMQmap = channels; + return 0; + } + + + FairMQMap GetFairMQMap() + { + return fFairMQmap; + } + + +protected: + po::options_description fMQParserOptions; + pt::ptree fMQtree; + FairMQMap fFairMQmap; + + virtual int NotifySwitchOption();// for custom help & version printing + void InitOptionDescription(); +}; + + +#endif /* FAIRMQPROGOPTIONS_H */ + diff --git a/fairmq/options/FairProgOptions.cxx b/fairmq/options/FairProgOptions.cxx new file mode 100644 index 00000000..389c7fff --- /dev/null +++ b/fairmq/options/FairProgOptions.cxx @@ -0,0 +1,463 @@ +/* + * File: FairProgOptions.cxx + * Author: winckler + * + * Created on March 11, 2015, 5:38 PM + */ + +#include "FairProgOptions.h" + + + +/// ////////////////////////////////////////////////////////////////////////////////////////////////////// +/// Constructor / destructor +FairProgOptions::FairProgOptions() : + fGenericDesc("Generic options description"), + fConfigDesc("Configuration options description"), + fHiddenDesc("Hidden options description"), + fEnvironmentDesc("Environment Variables"), + fCmdline_options("Command line options"), + fConfig_file_options("Configuration file options"), + fVisible_options("Visible options"), + fVerboseLvl(0), fUseConfigFile(false), fConfigFile() +{ + // ////////////////////////////////// + // define generic options + fGenericDesc.add_options() + ("help,h", "produce help") + ("version,v", "print version") + ("verbose", po::value(&fVerboseLvl)->default_value(0), "Verbosity level : \n" + " 0=DEBUG \n" + " 1=INFO \n" + " 2=WARN \n" + " 3=ERROR \n" + " 4=STATE \n" + " 5=NOLOG" + ) + ; + +} + +FairProgOptions::~FairProgOptions() +{ +} + + +/// ////////////////////////////////////////////////////////////////////////////////////////////////////// +/// Add option descriptions + +int FairProgOptions::AddToCmdLineOptions(const po::options_description& optdesc, bool visible) +{ + fCmdline_options.add(optdesc); + if(visible) + fVisible_options.add(optdesc); + return 0; +} + +int FairProgOptions::AddToCfgFileOptions(const po::options_description& optdesc, bool visible) +{ + fConfig_file_options.add(optdesc); + if(visible) + fVisible_options.add(optdesc); + return 0; +} + +int FairProgOptions::AddToEnvironmentOptions(const po::options_description& optdesc) +{ + fEnvironmentDesc.add(optdesc); + return 0; +} + +/// ////////////////////////////////////////////////////////////////////////////////////////////////////// +/// Parser + +int FairProgOptions::ParseCmdLine(const int argc, char** argv, const po::options_description& desc, po::variables_map& varmap, bool AllowUnregistered) +{ + // ////////////////////////////////// + // get options from cmd line and store in variable map + // here we use command_line_parser instead of parse_command_line, to allow unregistered and positional options + if(AllowUnregistered) + { + po::command_line_parser parser{argc, argv}; + parser.options(desc).allow_unregistered(); + po::parsed_options parsedOptions = parser.run(); + po::store(parsedOptions,varmap); + } + else + po::store(po::parse_command_line(argc, argv, desc), varmap); + + // ////////////////////////////////// + // call the virtual NotifySwitchOption method to handle switch options like e.g. "--help" or "--version" + // return 1 if switch options found in varmap + if(NotifySwitchOption()) + return 1; + + po::notify(varmap); + return 0; +} + + +int FairProgOptions::ParseCmdLine(const int argc, char** argv, const po::options_description& desc, bool AllowUnregistered) +{ + return ParseCmdLine(argc,argv,desc,fvarmap,AllowUnregistered); +} + + + +int FairProgOptions::ParseCfgFile(std::ifstream& ifs, const po::options_description& desc, po::variables_map& varmap, bool AllowUnregistered) +{ + if (!ifs) + { + std::cout << "can not open configuration file \n"; + return -1; + } + else + { + po:store(parse_config_file(ifs, desc, AllowUnregistered), varmap); + po::notify(varmap); + } + return 0; +} + +int FairProgOptions::ParseCfgFile(const std::string& filename, const po::options_description& desc, po::variables_map& varmap, bool AllowUnregistered) +{ + std::ifstream ifs(filename.c_str()); + if (!ifs) + { + std::cout << "can not open configuration file: " << filename << "\n"; + return -1; + } + else + { + po:store(parse_config_file(ifs, desc, AllowUnregistered), varmap); + po::notify(varmap); + } + return 0; +} + + +int FairProgOptions::ParseCfgFile(const std::string& filename, const po::options_description& desc, bool AllowUnregistered) +{ + return ParseCfgFile(filename,desc,fvarmap,AllowUnregistered); +} + +int FairProgOptions::ParseCfgFile(std::ifstream& ifs, const po::options_description& desc, bool AllowUnregistered) +{ + return ParseCfgFile(ifs,desc,fvarmap,AllowUnregistered); +} + + +int FairProgOptions::ParseEnvironment(const std::function & environment_mapper) +{ + po::store(po::parse_environment(fEnvironmentDesc, environment_mapper), fvarmap); + po::notify(fvarmap); + + return 0; +} + +// Given a key, convert the variable value to string +std::string FairProgOptions::GetStringValue(const std::string& key) + { + std::string val_str; + try + { + if ( fvarmap.count(key) ) + { + auto& value = fvarmap[key].value(); + + + // string albeit useless here + if(auto q = boost::any_cast< std::string >(&value )) + { + val_str = variable_value_to_string< std::string >(fvarmap[key]); + return val_str; + } + + // vector + if(auto q = boost::any_cast< std::vector >(&value )) + { + val_str = variable_value_to_string< std::vector >(fvarmap[key]); + return val_str; + } + + // int + if(auto q = boost::any_cast< int >(&value )) + { + val_str = variable_value_to_string< int >(fvarmap[key]); + return val_str; + } + + // vector + if(auto q = boost::any_cast< std::vector >(&value )) + { + val_str = variable_value_to_string< std::vector >(fvarmap[key]); + return val_str; + } + + // float + if(auto q = boost::any_cast< float >(&value )) + { + val_str = variable_value_to_string< float >(fvarmap[key]); + return val_str; + } + + // vector float + if(auto q = boost::any_cast< std::vector >(&value )) + { + val_str = variable_value_to_string< std::vector >(fvarmap[key]); + return val_str; + } + + // double + if(auto q = boost::any_cast< double >(&value )) + { + val_str = variable_value_to_string< double >(fvarmap[key]); + return val_str; + } + + // vector double + if(auto q = boost::any_cast< std::vector >(&value )) + { + val_str = variable_value_to_string< std::vector >(fvarmap[key]); + return val_str; + } + + + } + } + catch(std::exception& e) + { + MQLOG(ERROR) << "Problem in boost variable map for the key '" << key << "'"; + MQLOG(ERROR) << e.what(); + } + + return val_str; + } + + +/* +int FairProgOptions::ParseAll(const int argc, char** argv, bool AllowUnregistered) +{ + // ////////////////////////////////// + // Method to overload. + ParseCmdLine(argc,argv,fGenericDesc,fvarmap,AllowUnregistered); + PrintOptions(); + + return 0; +} +*/ + +/// ////////////////////////////////////////////////////////////////////////////////////////////////////// +/// Print/notify options + +int FairProgOptions::PrintHelp() const +{ + std::cout << fVisible_options << "\n"; + return 0; +} + +int FairProgOptions::PrintOptions() +{ + // ////////////////////////////////// + // Method to overload. + // -> loop over variable map and print its content + // -> In this example the following types are supported: + // std::string, int, float, double, boost::filesystem::path + // std::vector, std::vector, std::vector, std::vector + + + MapVarValInfo_t mapinfo; + + // get string length for formatting and convert varmap values into string + int maxlen_1st = 0; + int maxlen_2nd = 0; + int maxlen_TypeInfo = 0; + int maxlen_default =0; + int maxlen_empty = 0; + int total_len=0; + for (const auto& m : fvarmap) + { + Max(maxlen_1st, m.first.length()); + + VarValInfo_t valinfo=Get_variable_value_info(m.second); + mapinfo[m.first]=valinfo; + std::string val_str; + std::string typeInfo_str; + std::string default_str; + std::string empty_str; + std::tie(val_str,typeInfo_str,default_str,empty_str)=valinfo; + + Max(maxlen_2nd, val_str.length()); + Max(maxlen_TypeInfo, typeInfo_str.length()); + Max(maxlen_default, default_str.length()); + Max(maxlen_empty, empty_str.length()); + + } + + // TODO : limit the value length field in a better way + if(maxlen_2nd>100) + maxlen_2nd=100; + total_len=maxlen_1st+maxlen_2nd+maxlen_TypeInfo+maxlen_default+maxlen_empty; + + + //maxlen_2nd=200; + + // formatting and printing + + MQLOG(INFO)< + auto& value = var_val.value(); + std::string defaulted_val; + std::string empty_val; + + if(var_val.empty()) + empty_val=" [empty]"; + else + if(var_val.defaulted()) + defaulted_val=" [default value]"; + else + defaulted_val=" [provided value]"; + + empty_val+=" *"; + // string + if(auto q = boost::any_cast< std::string >(&value)) + { + std::string val_str = *q; + return std::make_tuple(val_str,std::string(" [Type=string]"),defaulted_val,empty_val); + } + + // vector + if(auto q = boost::any_cast< std::vector >(&value)) + { + std::string val_str = variable_value_to_string< std::vector >(var_val); + return std::make_tuple(val_str,std::string(" [Type=vector]"),defaulted_val,empty_val); + } + + // int + if(auto q = boost::any_cast< int >(&value)) + { + std::string val_str = variable_value_to_string< int >(var_val); + return std::make_tuple(val_str,std::string(" [Type=int]"),defaulted_val,empty_val); + } + + // vector + if(auto q = boost::any_cast< std::vector >(&value)) + { + std::string val_str = variable_value_to_string< std::vector >(var_val); + return std::make_tuple(val_str,std::string(" [Type=vector]"),defaulted_val,empty_val); + } + + // float + if(auto q = boost::any_cast< float >(&value)) + { + std::string val_str = variable_value_to_string< float >(var_val); + return std::make_tuple(val_str,std::string(" [Type=float]"),defaulted_val,empty_val); + } + + // vector + if(auto q = boost::any_cast< std::vector >(&value)) + { + std::string val_str = variable_value_to_string< std::vector >(var_val); + return std::make_tuple(val_str,std::string(" [Type=vector]"),defaulted_val,empty_val); + } + + // double + if(auto q = boost::any_cast< double >(&value)) + { + std::string val_str = variable_value_to_string< double >(var_val); + return std::make_tuple(val_str,std::string(" [Type=double]"),defaulted_val,empty_val); + } + + // vector + if(auto q = boost::any_cast< std::vector >(&value)) + { + std::string val_str = variable_value_to_string< std::vector >(var_val); + return std::make_tuple(val_str,std::string(" [Type=vector]"),defaulted_val,empty_val); + } + + // boost::filesystem::path + if(auto q = boost::any_cast(&value)) + { + std::string val_str = (*q).string(); + return std::make_tuple(val_str,std::string(" [Type=boost::filesystem::path]"),defaulted_val,empty_val); + } + + // if we get here, the type is not supported return unknown info + return std::make_tuple(std::string("Unknown value"), std::string(" [Type=Unknown]"),defaulted_val,empty_val); + } + + diff --git a/fairmq/options/FairProgOptions.h b/fairmq/options/FairProgOptions.h new file mode 100644 index 00000000..811d8dcc --- /dev/null +++ b/fairmq/options/FairProgOptions.h @@ -0,0 +1,206 @@ +/* + * File: FairProgOptions.h + * Author: winckler + * + * Created on March 11, 2015, 5:38 PM + */ + +#ifndef FAIRPROGOPTIONS_H +#define FAIRPROGOPTIONS_H + +#include "FairMQLogger.h" +#include +#include + +#include +#include +#include +#include +#include +#include + +/* + * FairProgOptions abstract base class + * parse command line, configuration file options as well as environment variables. + * + * The user defines in the derived class the option descriptions and + * the pure virtual ParseAll() method + * + * class MyOptions : public FairProgOptions + * { + * public : + * MyOptions() : FairProgOptions() + * { + * fCmdline_options.add(fGenericDesc); + * fVisible_options.add(fCmdline_options); + * } + * virtual ~MyOptions(){} + * virtual int ParseAll(const int argc, char** argv, bool AllowUnregistered=false) + * { + * if(ParseCmdLine(argc,argv,fCmdline_options,fvarmap,AllowUnregistered)) + * return 1; + * + * PrintOptions(); + * return 0; + * } + * } + */ + +template + std::ostream& operator<<(std::ostream& os, const std::vector& v) + { + std::copy(v.begin(), v.end(), std::ostream_iterator(os, " ")); + return os; + } + + +namespace po = boost::program_options; + + +class FairProgOptions +{ +public: + FairProgOptions(); + virtual ~FairProgOptions(); + + // add options_description + int AddToCmdLineOptions(const po::options_description& optdesc, bool visible=true); + int AddToCfgFileOptions(const po::options_description& optdesc, bool visible=true); + int AddToEnvironmentOptions(const po::options_description& optdesc); + + void EnableCfgFile(const std::string& filename="") + { + fUseConfigFile=true; + if(filename.empty()) + fCmdline_options.add_options() + ("config,c", po::value(&fConfigFile)->required(), "Path to configuration file"); + else + fConfigFile=filename; + + } + + + void UseConfigFile(const std::string& filename="") + { + fUseConfigFile=true; + if(filename.empty()) + fCmdline_options.add_options() + ("config,c", po::value(&fConfigFile)->required(), "Path to configuration file"); + else + fConfigFile=filename; + + } + + // set value corresponding to the key + template + T GetValue(const std::string& key) const + { + T val; + try + { + if ( fvarmap.count(key) ) + val=fvarmap[key].as(); + else + { + LOG(ERROR) <<"Key '"<< key <<"' not found in boost variable map"; + LOG(INFO) << "Command line / txt config file options are the following : "; + this->PrintHelp(); + } + } + catch(std::exception& e) + { + LOG(ERROR) << "Exception thorwn for the key '" << key << "'"; + LOG(ERROR) << e.what(); + this->PrintHelp(); + } + + return val; + } + + // convert value to string that corresponds to the key + std::string GetStringValue(const std::string& key); + const po::variables_map& GetVarMap() const {return fvarmap;} + + // boost prog options parsers + int ParseCmdLine(const int argc, char** argv, const po::options_description& desc, po::variables_map& varmap, bool AllowUnregistered=false); + int ParseCmdLine(const int argc, char** argv, const po::options_description& desc, bool AllowUnregistered=false); + + int ParseCfgFile(const std::string& filename, const po::options_description& desc, po::variables_map& varmap, bool AllowUnregistered=false); + int ParseCfgFile(const std::string& filename, const po::options_description& desc, bool AllowUnregistered=false); + int ParseCfgFile(std::ifstream& ifs, const po::options_description& desc, po::variables_map& varmap, bool AllowUnregistered=false); + int ParseCfgFile(std::ifstream& ifs, const po::options_description& desc, bool AllowUnregistered=false); + + + int ParseEnvironment(const std::function&); + + virtual int ParseAll(const int argc, char** argv, bool AllowUnregistered=false)=0; + + virtual int PrintOptions(); + int PrintHelp() const; + +protected: + + // options container + po::variables_map fvarmap; + + // basic description categories + po::options_description fGenericDesc; + po::options_description fConfigDesc; + po::options_description fEnvironmentDesc; + po::options_description fHiddenDesc; + + // Description of cmd line and simple configuration file (configuration file like txt, but not like xml json ini) + po::options_description fCmdline_options; + po::options_description fConfig_file_options; + + // Description which is printed in help command line + po::options_description fVisible_options; + + int fVerboseLvl; + bool fUseConfigFile; + std::string fConfigFile; + virtual int NotifySwitchOption(); + + // UpadateVarMap() and replace() --> to modify the value of variable map after calling po::store + template + void UpadateVarMap(const std::string& key, const T& val) + { + replace(fvarmap,key,val); + } + + template + void replace( std::map& vm, const std::string& opt, const T& val) + { + vm[opt].value() = boost::any(val); + } + +private: + + // ///////////////////////////////////////////// + // Methods below are helper functions used in the PrintOptions method + typedef std::tuple VarValInfo_t; + typedef std::map MapVarValInfo_t; + + VarValInfo_t Get_variable_value_info(const po::variable_value& var_val); + + template + std::string variable_value_to_string(const po::variable_value& var_val) + { + auto& value = var_val.value(); + std::ostringstream ostr; + if(auto q = boost::any_cast< T >(&value)) + ostr<<*q; + std::string val_str=ostr.str(); + return val_str; + } + + static void Max(int &val, const int &comp) + { + if (comp>val) + val=comp; + } +}; + + +#endif /* FAIRPROGOPTIONS_H */ + diff --git a/fairmq/options/ProgOptionTest/CMakeLists.txt b/fairmq/options/ProgOptionTest/CMakeLists.txt new file mode 100644 index 00000000..f70f41fe --- /dev/null +++ b/fairmq/options/ProgOptionTest/CMakeLists.txt @@ -0,0 +1,96 @@ + ################################################################################ + # Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH # + # # + # This software is distributed under the terms of the # + # GNU Lesser General Public Licence version 3 (LGPL) version 3, # + # copied verbatim in the file "LICENSE" # + ################################################################################ +# Create a library called "ProgOptionTest" + +# Test fair-prog-opt + + # scripts + configure_file( ${CMAKE_SOURCE_DIR}/fairmq/options/ProgOptionTest/macro/testMQOptions1.sh.in ${CMAKE_BINARY_DIR}/bin/testMQOptions1.sh ) + configure_file( ${CMAKE_SOURCE_DIR}/fairmq/options/ProgOptionTest/macro/testMQOptions2.sh.in ${CMAKE_BINARY_DIR}/bin/testMQOptions2.sh ) + configure_file( ${CMAKE_SOURCE_DIR}/fairmq/options/ProgOptionTest/macro/testMQOptions3.sh.in ${CMAKE_BINARY_DIR}/bin/testMQOptions3.sh ) + configure_file( ${CMAKE_SOURCE_DIR}/fairmq/options/ProgOptionTest/macro/testMQOptions4.sh.in ${CMAKE_BINARY_DIR}/bin/testMQOptions4.sh ) + configure_file( ${CMAKE_SOURCE_DIR}/fairmq/options/ProgOptionTest/macro/testMQOptions5.sh.in ${CMAKE_BINARY_DIR}/bin/testMQOptions5.sh ) + configure_file( ${CMAKE_SOURCE_DIR}/fairmq/options/ProgOptionTest/macro/start-bsampler-sink.sh.in ${CMAKE_BINARY_DIR}/bin/start-bsampler-sink.sh ) + EXEC_PROGRAM(/bin/chmod ARGS "u+x ${CMAKE_BINARY_DIR}/bin/testMQOptions1.sh") + EXEC_PROGRAM(/bin/chmod ARGS "u+x ${CMAKE_BINARY_DIR}/bin/testMQOptions2.sh") + EXEC_PROGRAM(/bin/chmod ARGS "u+x ${CMAKE_BINARY_DIR}/bin/testMQOptions3.sh") + EXEC_PROGRAM(/bin/chmod ARGS "u+x ${CMAKE_BINARY_DIR}/bin/testMQOptions4.sh") + EXEC_PROGRAM(/bin/chmod ARGS "u+x ${CMAKE_BINARY_DIR}/bin/testMQOptions5.sh") + EXEC_PROGRAM(/bin/chmod ARGS "u+x ${CMAKE_BINARY_DIR}/bin/start-bsampler-sink.sh") + + # Config/xml/json example file + configure_file( ${CMAKE_SOURCE_DIR}/fairmq/options/ProgOptionTest/macro/ConfigFileTest.cfg.in ${CMAKE_BINARY_DIR}/bin/ConfigFileTest.cfg) + configure_file( ${CMAKE_SOURCE_DIR}/fairmq/options/ProgOptionTest/macro/testXML.xml ${CMAKE_BINARY_DIR}/bin/testXML.xml ) + configure_file( ${CMAKE_SOURCE_DIR}/fairmq/options/ProgOptionTest/macro/testJSON.json ${CMAKE_BINARY_DIR}/bin/testJSON.json ) + configure_file( ${CMAKE_SOURCE_DIR}/fairmq/options/ProgOptionTest/macro/bsampler-sink.json ${CMAKE_BINARY_DIR}/bin/bsampler-sink.json ) + + + +set(INCLUDE_DIRECTORIES +${CMAKE_SOURCE_DIR}/fairmq +${CMAKE_SOURCE_DIR}/fairmq/options +${CMAKE_SOURCE_DIR}/fairmq/options/ProgOptionTest/lib +${CMAKE_SOURCE_DIR}/fairmq/options/ProgOptionTest/run +) + +Set(SYSTEM_INCLUDE_DIRECTORIES + ${SYSTEM_INCLUDE_DIRECTORIES} +) + +include_directories(${INCLUDE_DIRECTORIES}) +include_directories(${SYSTEM_INCLUDE_DIRECTORIES}) + +set(LINK_DIRECTORIES +${Boost_LIBRARY_DIRS} +) + +link_directories(${LINK_DIRECTORIES}) + +Set(SRCS + lib/FairMQParser.cxx +) + +Set(LIBRARY_NAME ProgOptionTest) + +If (Boost_FOUND) + Set(DEPENDENCIES + boost_system boost_program_options FairMQ + ) +EndIf (Boost_FOUND) + +GENERATE_LIBRARY() + + +If (Boost_FOUND) + Set(Exe_Names + runtestMQOption1 + runtestMQOption2 + runOptTestSampler + runOptTestSink + ) + + + set(Exe_Source + run/testMQoptions1.cxx + run/testMQoptions2.cxx + run/runOptTestSampler.cxx + run/runOptTestSink.cxx + ) + + List(LENGTH Exe_Names _length) + Math(EXPR _length ${_length}-1) + + ForEach(_file RANGE 0 ${_length}) + List(GET Exe_Names ${_file} _name) + List(GET Exe_Source ${_file} _src) + Set(EXE_NAME ${_name}) + Set(SRCS ${_src}) + Set(DEPENDENCIES ProgOptionTest) + GENERATE_EXECUTABLE() + EndForEach(_file RANGE 0 ${_length}) +EndIf (Boost_FOUND) diff --git a/fairmq/options/ProgOptionTest/lib/FairMQParser.cxx b/fairmq/options/ProgOptionTest/lib/FairMQParser.cxx new file mode 100644 index 00000000..8e2e184f --- /dev/null +++ b/fairmq/options/ProgOptionTest/lib/FairMQParser.cxx @@ -0,0 +1,252 @@ +/* + * File: FairMQParser.cxx + * Author: winckler + * + * Created on May 14, 2015, 5:01 PM + */ + +#include "FairMQParser.h" +#include "FairMQLogger.h" +#include + +// WARNING : pragma commands to hide boost (1.54.0) warning +// TODO : remove these pragma commands when boost will fix this issue in future release +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wshadow" +#include +#pragma clang diagnostic pop + +namespace FairMQParser +{ + no_id_exception NoIdErr; + + // TODO : add key-value map parameter for replacing/updating values from keys + // function that convert property tree (given the xml or json structure) to FairMQMap + FairMQMap boost_ptree_to_MQMap(const boost::property_tree::ptree& pt, const std::string& device_id, const std::string& root_node, const std::string& format_flag) + { + // Create fair mq map + FairMQMap MQChannelMap; + + // variables to create key for the mq map. Note: maybe device name and id useless here + std::string kdevice_id; + std::string kchannel; + + if(device_id.empty()) + throw NoIdErr; + + + // do a first loop just to print the device-id in xml/json input + for(const auto& p : pt.get_child(root_node)) + { + if (p.first != "device") + continue; + + //get id attribute to choose the device + if(format_flag=="xml") + { + kdevice_id=p.second.get(".id"); + MQLOG(DEBUG)<<"Found device id '"<< kdevice_id <<"' in XML input"; + } + + if(format_flag=="json") + { + kdevice_id=p.second.get("id"); + MQLOG(DEBUG)<<"Found device id '"<< kdevice_id <<"' in JSON input"; + } + } + + // Extract value from boost::property_tree + // For each device in fairMQOptions + for(const auto& p : pt.get_child(root_node)) + { + if (p.first != "device") + continue; + + //get id attribute to choose the device + if(format_flag=="xml") + kdevice_id=p.second.get(".id"); + + if(format_flag=="json") + kdevice_id=p.second.get("id"); + // if not correct device id, do not fill MQMap + if(device_id != kdevice_id) + continue; + + // print if DEBUG log level set + std::stringstream ss_device; + ss_device << "[node = " << p.first + << "] id = " << kdevice_id; + MQLOG(DEBUG)<(".name"); + + if(format_flag=="json") + kchannel=q.second.get("name"); + + // print if DEBUG log level set + std::stringstream ss_chan; + ss_chan << "\t [node = " << q.first + << "] name = " << kchannel; + MQLOG(DEBUG)< channel_list; + + int count_socket=0; + // for each socket in channel + for(const auto& r : q.second.get_child("")) + { + if (r.first != "socket") + continue; + + count_socket++; + FairMQChannel channel; + + // print if DEBUG log level set + std::stringstream ss_sock; + ss_sock << "\t \t [node = " << r.first + << "] socket index = " << count_socket; + MQLOG(DEBUG)<("type",channel.fType); + channel.fMethod = r.second.get("method",channel.fMethod); + channel.fAddress = r.second.get("address",channel.fAddress); + channel.fSndBufSize = r.second.get("sndBufSize",channel.fSndBufSize);//int + channel.fRcvBufSize = r.second.get("rcvBufSize",channel.fRcvBufSize);//int + channel.fRateLogging = r.second.get("rateLogging",channel.fRateLogging);//int + + channel_list.push_back(channel); + }// end socket loop + + //fill mq map option + MQChannelMap.insert(std::make_pair(kchannel,std::move(channel_list))); + } + } + + if(MQChannelMap.size()>0) + { + MQLOG(DEBUG)<<"---- Channel-keys found are :"; + for(const auto& p : MQChannelMap) + MQLOG(DEBUG)<> match; + std::pair device_match; + + ProcessTree(xml.begin (), xml.end (), std::back_inserter(match), + [] (const std::string& key) { return key == "device"; }); + + + // for each device + for (const auto& pair: match) + { + if(pair.second.get(".name") == devicename) + { + device_match=pair; + + } + else + { + //match.erase(std::remove(match.begin(), match.end(), pair), match.end()); + continue; + } + + //std::cout << "pair.first " << pair.first << std::endl;//device + //std::cout << "\t node = " << pair.first + // << "\t name = " << pair.second.get(".name") + // << "\t id = " << pair.second.get(".id"); + //std::cout< + +// std +#include +#include +#include + + +namespace FairMQParser +{ + + typedef std::map > FairMQMap; + FairMQMap boost_ptree_to_MQMap(const boost::property_tree::ptree& pt, const std::string& device_id, const std::string& root_node, const std::string& format_flag="json"); + + //////////////////////////////////////////////////////////////////////////// + /////////////////////////////////// XML //////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + + // xml example 1 + //////////////////////////////////////////////////////////////////////////// + struct XML + { + FairMQMap UserParser(const std::string& filename, const std::string& device_id, const std::string& root_node="fairMQOptions"); + FairMQMap UserParser(std::stringstream& input_ss, const std::string& device_id, const std::string& root_node="fairMQOptions"); + }; + + // xml example 2 + //////////////////////////////////////////////////////////////////////////// + struct MQXML2 + { + boost::property_tree::ptree UserParser(const std::string& filename); + }; + + // xml example 3 + //////////////////////////////////////////////////////////////////////////// + struct MQXML3 + { + boost::property_tree::ptree UserParser(const std::string& filename, const std::string& root_node); + }; + + //////////////////////////////////////////////////////////////////////////// + /////////////////////////////////// JSON /////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + struct JSON + { + FairMQMap UserParser(const std::string& filename, const std::string& device_id, const std::string& root_node="fairMQOptions"); + FairMQMap UserParser(std::stringstream& input_ss, const std::string& device_id, const std::string& root_node="fairMQOptions"); + }; + + + //////////////////////////////////////////////////////////////////////////// + // template function iterating over the whole boost property tree + template + void ProcessTree(Input_tree_It first, Input_tree_It last, Output_tree_It dest, Compare_key compare) + { + //typedef typename std::iterator_traits::reference reference; + + if (first == last) + { + return; + } + + auto begin = first->second.begin (); + auto end = first->second.end (); + + if (begin != end) + { + ProcessTree (begin, end, dest, compare); + } + + if (compare (first->first)) + { + dest = *first; + } + + ProcessTree (++first, last, dest, compare); + } + + class no_id_exception: public std::exception + { + virtual const char* what() const throw() + { + return "Empty string for the device-id in FairMQParser::boost_ptree_to_MQMap(...) function"; + } + }; + +} // end FairMQParser namespace +#endif /* FAIRMQPARSER_H */ + diff --git a/fairmq/options/ProgOptionTest/macro/ConfigFileTest.cfg.in b/fairmq/options/ProgOptionTest/macro/ConfigFileTest.cfg.in new file mode 100644 index 00000000..160ce842 --- /dev/null +++ b/fairmq/options/ProgOptionTest/macro/ConfigFileTest.cfg.in @@ -0,0 +1,38 @@ +#---------------------------------------------------- +# comments : +# brackets [] are used to group options. For example : +# +# [xml.config] +# node.root = fairMQOptions +# +# is equivalent to +# xml.config.node.root = fairMQOptions +#---------------------------------------------------- + +config-json-filename = @CMAKE_BINARY_DIR@/bin/testJSON.json +config-xml-filename = @CMAKE_BINARY_DIR@/bin/testXML.xml + +# +device-id = merger + +#------------------- +[xml.config] + +#filename = @CMAKE_BINARY_DIR@/bin/testXML.xml +node.root = fairMQOptions + + +#------------------- +[input.file] + +name = sampler_file_name.root +tree = sampler_tree +branch = sampler_branch + + +#------------------- +[output.file] + +name = sink_filename.root +tree = sink_tree +branch = sink_branch \ No newline at end of file diff --git a/fairmq/options/ProgOptionTest/macro/bsampler-sink.json b/fairmq/options/ProgOptionTest/macro/bsampler-sink.json new file mode 100644 index 00000000..8b265bc1 --- /dev/null +++ b/fairmq/options/ProgOptionTest/macro/bsampler-sink.json @@ -0,0 +1,40 @@ +{ + "fairMQOptions": + { + "device": + { + "id": "bsampler1", + "channel": + { + "name": "data-out", + "socket": + { + "type": "pub", + "method": "bind", + "address": "tcp://*:5555", + "sndBufSize": "1000", + "rcvBufSize": "1000", + "rateLogging": "1" + } + } + }, + "device": + { + "id": "sink1", + "channel": + { + "name": "data-in", + "socket": + { + "type": "sub", + "method": "connect", + "address": "tcp://localhost:5555", + "sndBufSize": "1000", + "rcvBufSize": "1000", + "rateLogging": "1" + } + } + } + } +} + diff --git a/fairmq/options/ProgOptionTest/macro/start-bsampler-sink.sh.in b/fairmq/options/ProgOptionTest/macro/start-bsampler-sink.sh.in new file mode 100644 index 00000000..fcbae77b --- /dev/null +++ b/fairmq/options/ProgOptionTest/macro/start-bsampler-sink.sh.in @@ -0,0 +1,18 @@ +#!/bin/bash + +JSONFILE="@CMAKE_BINARY_DIR@/bin/bsampler-sink.json" + +# Note: device-id value must correspond to the device id given in the json file + +BSAMPLER="runOptTestSampler" +BSAMPLER+=" --config-sjson-filename $JSONFILE" +BSAMPLER+=" --device-id bsampler1" + +xterm -geometry 150x23+0+0 -hold -e @CMAKE_BINARY_DIR@/bin/$BSAMPLER & + + +SINK="runOptTestSink" +SINK+=" --config-json-filename $JSONFILE" +SINK+=" --device-id sink1" + +xterm -geometry 150x23+0+350 -hold -e @CMAKE_BINARY_DIR@/bin/$SINK & diff --git a/fairmq/options/ProgOptionTest/macro/testJSON.json b/fairmq/options/ProgOptionTest/macro/testJSON.json new file mode 100644 index 00000000..060eb389 --- /dev/null +++ b/fairmq/options/ProgOptionTest/macro/testJSON.json @@ -0,0 +1,60 @@ +{ + "fairMQOptions": { + "device": + { + "id": "merger1", + "channel": + { + "name": "two_inputs_channel", + "socket": + { + "type": "pull", + "address": "tcp://*:5569", + "sndBufSize": "1000", + "rcvBufSize": "1000", + "rateLogging": "1" + }, + "socket": + { + "type": "pull", + "method": "bind", + "address": "tcp://*:5570", + "sndBufSize": "1000", + "rcvBufSize": "1000", + "rateLogging": "1" + } + + }, + "channel": + { + "name": "one_output_channel", + "socket": { + "type": "push", + "method": "connect", + "address": "tcp://*:5571", + "sndBufSize": "1000", + "rcvBufSize": "1000", + "rateLogging": "1" + } + } + + }, + "device": + { + "id": "sink1", + "channel": { + "name": "one_input", + "socket": { + "name": "input1", + "type": "pull", + "method": "bind", + "address": "tcp://localhost:5571", + "sndBufSize": "1000", + "rcvBufSize": "1000", + "rateLogging": "1" + } + } + } + + } +} \ No newline at end of file diff --git a/fairmq/options/ProgOptionTest/macro/testMQOptions1.sh.in b/fairmq/options/ProgOptionTest/macro/testMQOptions1.sh.in new file mode 100644 index 00000000..1e3fff99 --- /dev/null +++ b/fairmq/options/ProgOptionTest/macro/testMQOptions1.sh.in @@ -0,0 +1,11 @@ +#!/bin/bash + +RUN_TEST="runtestMQOption1" + +if [ "$#" -gt 0 ]; then + RUN_TEST+=" $*" +fi + +RUN_TEST+=" --config-xml-filename @CMAKE_BINARY_DIR@/bin/testXML.xml" + +@CMAKE_BINARY_DIR@/bin/$RUN_TEST \ No newline at end of file diff --git a/fairmq/options/ProgOptionTest/macro/testMQOptions2.sh.in b/fairmq/options/ProgOptionTest/macro/testMQOptions2.sh.in new file mode 100644 index 00000000..58cb0500 --- /dev/null +++ b/fairmq/options/ProgOptionTest/macro/testMQOptions2.sh.in @@ -0,0 +1,59 @@ +#!/bin/bash + +RUN_TEST="runtestMQOption1" + +if [ "$#" -gt 0 ]; then + RUN_TEST+=" $*" +fi + +XML_CMD_LINE="" +XML_CMD_LINE+="" +XML_CMD_LINE+=" " +XML_CMD_LINE+=" " +XML_CMD_LINE+=" pull" +XML_CMD_LINE+=" bind" +XML_CMD_LINE+="
tcp://*:5569
" +XML_CMD_LINE+=" 1000" +XML_CMD_LINE+=" 1000" +XML_CMD_LINE+=" 1" +XML_CMD_LINE+="
" +XML_CMD_LINE+=" " +XML_CMD_LINE+=" pull" +XML_CMD_LINE+=" bind" +XML_CMD_LINE+="
tcp://*:5570
" +XML_CMD_LINE+=" 1000" +XML_CMD_LINE+=" 1000" +XML_CMD_LINE+=" 1" +XML_CMD_LINE+="
" +XML_CMD_LINE+="
" +XML_CMD_LINE+=" " +XML_CMD_LINE+=" " +XML_CMD_LINE+=" push" +XML_CMD_LINE+=" connect" +XML_CMD_LINE+="
tcp://*:5571
" +XML_CMD_LINE+=" 1000" +XML_CMD_LINE+=" 1000" +XML_CMD_LINE+=" 1" +XML_CMD_LINE+="
" +XML_CMD_LINE+="
" +XML_CMD_LINE+="
" +XML_CMD_LINE+=" " +XML_CMD_LINE+=" " +XML_CMD_LINE+=" " +XML_CMD_LINE+=" pull" +XML_CMD_LINE+=" bind" +XML_CMD_LINE+="
tcp://localhost:5571
" +XML_CMD_LINE+=" 1000" +XML_CMD_LINE+=" 1000" +XML_CMD_LINE+=" 1" +XML_CMD_LINE+="
" +XML_CMD_LINE+="
" +XML_CMD_LINE+="
" +XML_CMD_LINE+="" + + + +RUN_TEST+=" --config-xml-string $XML_CMD_LINE" + + +@CMAKE_BINARY_DIR@/bin/$RUN_TEST diff --git a/fairmq/options/ProgOptionTest/macro/testMQOptions3.sh.in b/fairmq/options/ProgOptionTest/macro/testMQOptions3.sh.in new file mode 100644 index 00000000..076f9520 --- /dev/null +++ b/fairmq/options/ProgOptionTest/macro/testMQOptions3.sh.in @@ -0,0 +1,10 @@ +#!/bin/bash + +RUN_TEST="runtestMQOption2" + +if [ "$#" -gt 0 ]; then + RUN_TEST+=" $*" +fi +RUN_TEST+=" --config @CMAKE_BINARY_DIR@/bin/ConfigFileTest.cfg" + +@CMAKE_BINARY_DIR@/bin/$RUN_TEST \ No newline at end of file diff --git a/fairmq/options/ProgOptionTest/macro/testMQOptions4.sh.in b/fairmq/options/ProgOptionTest/macro/testMQOptions4.sh.in new file mode 100644 index 00000000..c3cf03ee --- /dev/null +++ b/fairmq/options/ProgOptionTest/macro/testMQOptions4.sh.in @@ -0,0 +1,11 @@ +#!/bin/bash + +RUN_TEST="runtestMQOption1" + +if [ "$#" -gt 0 ]; then + RUN_TEST+=" $*" +fi + +RUN_TEST+=" --config-json-filename @CMAKE_BINARY_DIR@/bin/testJSON.json" + +@CMAKE_BINARY_DIR@/bin/$RUN_TEST \ No newline at end of file diff --git a/fairmq/options/ProgOptionTest/macro/testMQOptions5.sh.in b/fairmq/options/ProgOptionTest/macro/testMQOptions5.sh.in new file mode 100644 index 00000000..13064de6 --- /dev/null +++ b/fairmq/options/ProgOptionTest/macro/testMQOptions5.sh.in @@ -0,0 +1,77 @@ +#!/bin/bash + +RUN_TEST="runtestMQOption1" + +if [ "$#" -gt 0 ]; then + RUN_TEST+=" $*" +fi + +JSON_CMD_LINE="{" +JSON_CMD_LINE+=" \"fairMQOptions\": {" +JSON_CMD_LINE+=" \"device\": " +JSON_CMD_LINE+=" {" +JSON_CMD_LINE+=" \"name\": \"merger\"," +JSON_CMD_LINE+=" \"id\": \"1234\"," +JSON_CMD_LINE+=" \"channel\": " +JSON_CMD_LINE+=" {" +JSON_CMD_LINE+=" \"name\": \"two_inputs_channel\"," +JSON_CMD_LINE+=" \"socket\": " +JSON_CMD_LINE+=" {" +JSON_CMD_LINE+=" \"name\": \"input1\"," +JSON_CMD_LINE+=" \"type\": \"pull\"," +JSON_CMD_LINE+=" \"method\": \"bind\"," +JSON_CMD_LINE+=" \"address\": \"tcp://*:5569\"," +JSON_CMD_LINE+=" \"sndBufSize\": \"1000\"," +JSON_CMD_LINE+=" \"rcvBufSize\": \"1000\"," +JSON_CMD_LINE+=" \"rateLogging\": \"1\" " +JSON_CMD_LINE+=" }," +JSON_CMD_LINE+=" \"socket\": " +JSON_CMD_LINE+=" {" +JSON_CMD_LINE+=" \"name\": \"input2\"," +JSON_CMD_LINE+=" \"type\": \"pull\"," +JSON_CMD_LINE+=" \"method\": \"bind\"," +JSON_CMD_LINE+=" \"address\": \"tcp://*:5570\"," +JSON_CMD_LINE+=" \"sndBufSize\": \"1000\"," +JSON_CMD_LINE+=" \"rcvBufSize\": \"1000\"," +JSON_CMD_LINE+=" \"rateLogging\": \"1\" " +JSON_CMD_LINE+=" }" +JSON_CMD_LINE+=" }," +JSON_CMD_LINE+=" \"channel\":" +JSON_CMD_LINE+=" {" +JSON_CMD_LINE+=" \"name\": \"one_output_channel\"," +JSON_CMD_LINE+=" \"socket\": {" +JSON_CMD_LINE+=" \"name\": \"output1\"," +JSON_CMD_LINE+=" \"type\": \"push\"," +JSON_CMD_LINE+=" \"method\": \"connect\"," +JSON_CMD_LINE+=" \"address\": \"tcp://*:5571\"," +JSON_CMD_LINE+=" \"sndBufSize\": \"1000\"," +JSON_CMD_LINE+=" \"rcvBufSize\": \"1000\"," +JSON_CMD_LINE+=" \"rateLogging\": \"1\" " +JSON_CMD_LINE+=" }" +JSON_CMD_LINE+=" }" +JSON_CMD_LINE+=" }," +JSON_CMD_LINE+=" \"device\":" +JSON_CMD_LINE+=" {" +JSON_CMD_LINE+=" \"name\": \"sink\"," +JSON_CMD_LINE+=" \"id\": \"4567\"," +JSON_CMD_LINE+=" \"channel\": {" +JSON_CMD_LINE+=" \"name\": \"one_input\"," +JSON_CMD_LINE+=" \"socket\": {" +JSON_CMD_LINE+=" \"name\": \"input1\"," +JSON_CMD_LINE+=" \"type\": \"pull\"," +JSON_CMD_LINE+=" \"method\": \"bind\"," +JSON_CMD_LINE+=" \"address\": \"tcp://localhost:5571\"," +JSON_CMD_LINE+=" \"sndBufSize\": \"1000\"," +JSON_CMD_LINE+=" \"rcvBufSize\": \"1000\"," +JSON_CMD_LINE+=" \"rateLogging\": \"1\" " +JSON_CMD_LINE+=" }" +JSON_CMD_LINE+=" }" +JSON_CMD_LINE+=" }" +JSON_CMD_LINE+=" }" +JSON_CMD_LINE+="}" + + +RUN_TEST+=" --config-json-string $JSON_CMD_LINE" + + +@CMAKE_BINARY_DIR@/bin/$RUN_TEST diff --git a/fairmq/options/ProgOptionTest/macro/testXML.xml b/fairmq/options/ProgOptionTest/macro/testXML.xml new file mode 100644 index 00000000..ae7360d2 --- /dev/null +++ b/fairmq/options/ProgOptionTest/macro/testXML.xml @@ -0,0 +1,48 @@ + + + + + + pull + bind +
tcp://*:5569
+ 1000 + 1000 + 1 + +
+ + pull + bind +
tcp://*:5570
+ 1000 + 1000 + 1 + +
+
+ + + push + connect +
tcp://*:5571
+ 1000 + 1000 + 1 +
+
+
+ + + + pull + bind +
tcp://localhost:5571
+ 1000 + 1000 + 1 +
+
+
+
+ diff --git a/fairmq/options/ProgOptionTest/run/runOptTestSampler.cxx b/fairmq/options/ProgOptionTest/run/runOptTestSampler.cxx new file mode 100644 index 00000000..be46b4e0 --- /dev/null +++ b/fairmq/options/ProgOptionTest/run/runOptTestSampler.cxx @@ -0,0 +1,83 @@ +/* + * File: runOptTestSampler.cxx + * Author: winckler + * + * Created on June 10, 2015, 3:34 PM + */ + +#include +/// std +#include +#include + +/// boost +#include "boost/program_options.hpp" + +/// FairRoot/FairMQ +#include "FairMQLogger.h" +#include "FairMQParser.h" +#include "FairMQProgOptions.h" + + +////////////////////////////////////////////////////////////// +/// main +////////////////////////////////////////////////////////////// +using namespace std; +using namespace FairMQParser; +using namespace boost::program_options; +int main(int argc, char** argv) +{ + FairMQProgOptions config; + try + { + // ////////////////////////////////////////////////////////////// + // define key specific to the BenchmarkSampler in options_description + + int eventSize; + int eventRate; + int ioThreads; + options_description sampler_options("Sampler options"); + sampler_options.add_options() + ("event-size", value(&eventSize)->default_value(1000), "Event size in bytes") + ("event-rate", value(&eventRate)->default_value(0), "Event rate limit in maximum number of events per second") + ("io-threads", value(&ioThreads)->default_value(1), "Number of I/O threads"); + + // and add it to cmdline option of FairMQProgOptions + config.AddToCmdLineOptions(sampler_options); + + // ////////////////////////////////////////////////////////////// + // enable simple config txt/INI file + //config.EnableCfgFile(); + //config.AddToCfgFileOptions(sampler_options,false); + // ////////////////////////////////////////////////////////////// + // Parse command line options and store in variable map + if(config.ParseAll(argc,argv,true)) + return 0; + + // keys defined in FairMQProgOptions + string filename=config.GetValue("config-json-filename"); + string deviceID=config.GetValue("device-id"); + + // ////////////////////////////////////////////////////////////// + // User defined parsing method. + + config.UserParser(filename,deviceID); + FairMQMap channels=config.GetFairMQMap(); + //set device here + + } + catch (exception& e) + { + LOG(ERROR) << e.what(); + LOG(INFO) << "Command line options are the following : "; + config.PrintHelp(); + return 1; + } + return 0; +} + + + + + + diff --git a/fairmq/options/ProgOptionTest/run/runOptTestSink.cxx b/fairmq/options/ProgOptionTest/run/runOptTestSink.cxx new file mode 100644 index 00000000..6b687b92 --- /dev/null +++ b/fairmq/options/ProgOptionTest/run/runOptTestSink.cxx @@ -0,0 +1,77 @@ +/* + * File: runOptTestSink.cxx + * Author: winckler + * + * Created on June 10, 2015, 3:34 PM + */ + +#include +/// std +#include +#include + +/// boost +#include "boost/program_options.hpp" + +/// FairRoot/FairMQ +#include "FairMQLogger.h" +#include "FairMQParser.h" +#include "FairMQProgOptions.h" + + +////////////////////////////////////////////////////////////// +/// main +////////////////////////////////////////////////////////////// +using namespace std; +using namespace FairMQParser; +using namespace boost::program_options; +int main(int argc, char** argv) +{ + FairMQProgOptions config; + try + { + // ////////////////////////////////////////////////////////////// + // define key specific to the BenchmarkSampler in options_description + + int eventSize; + int eventRate; + int ioThreads; + options_description Sink_options("Sink options"); + Sink_options.add_options() + ("io-threads", value(&ioThreads)->default_value(1), "Number of I/O threads"); + + // and add it to cmdline option of FairMQProgOptions + config.AddToCmdLineOptions(Sink_options); + + // ////////////////////////////////////////////////////////////// + // Parse command line options and store in variable map + if(config.ParseAll(argc,argv,true)) + return 0; + + // keys defined in FairMQProgOptions + string filename=config.GetValue("config-json-filename"); + string deviceID=config.GetValue("device-id"); + + // ////////////////////////////////////////////////////////////// + // User defined parsing method. + + config.UserParser(filename,deviceID); + FairMQMap channels=config.GetFairMQMap(); + //set device here + + } + catch (exception& e) + { + LOG(ERROR) << e.what(); + LOG(INFO) << "Command line options are the following : "; + config.PrintHelp(); + return 1; + } + return 0; +} + + + + + + diff --git a/fairmq/options/ProgOptionTest/run/testMQoptions1.cxx b/fairmq/options/ProgOptionTest/run/testMQoptions1.cxx new file mode 100644 index 00000000..2423de01 --- /dev/null +++ b/fairmq/options/ProgOptionTest/run/testMQoptions1.cxx @@ -0,0 +1,150 @@ +/// std +#include +#include + +/// boost +#include "boost/program_options.hpp" + +/// FairRoot/FairMQ +#include "FairMQLogger.h" +#include "FairMQParser.h" +#include "FairMQProgOptions.h" + +////////////////////////////////////////////////////////////// +// tests +////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////// + +// Parse xml from file +int testXML1(FairMQProgOptions* config) +{ + LOG(INFO)<<"--------- test XML1 ---------\n"; + std::string filename; + std::string XMLrootNode; + + filename=config->GetValue("config-xml-filename"); + XMLrootNode=config->GetValue("xml.config.node.root"); + std::string id=config->GetValue("device-id"); + config->UserParser(filename,id,XMLrootNode); + // other xml parser test + config->UserParser(filename); + config->UserParser(filename,"merger"); + + LOG(INFO)<<"--------- test XML1 end ---------\n"; + return 0; +} + + +// Parse xml from command line +int testXML2(FairMQProgOptions* config) +{ + LOG(INFO)<<"--------- test XML2 ---------\n"; + std::string XML; + std::string XMLrootNode; + std::string id=config->GetValue("device-id"); + XMLrootNode=config->GetValue("xml.config.node.root"); + + // Note: convert the vector into one string with GetStringValue(key) + XML=config->GetStringValue("config-xml-string"); + + std::stringstream iss; + iss << XML; + config->UserParser(iss,id,XMLrootNode); + + LOG(INFO)<<"--------- test XML2 end ---------\n"; + return 0; +} + +// Parse json from file +int testJSON1(FairMQProgOptions* config) +{ + LOG(INFO)<<"--------- test JSON1 ---------\n"; + std::string filename; + std::string JSONrootNode; + std::string id=config->GetValue("device-id"); + + filename=config->GetValue("config-json-filename"); + JSONrootNode=config->GetValue("json.config.node.root"); + + config->UserParser(filename,id,JSONrootNode); + + LOG(INFO)<<"--------- test JSON1 end ---------\n"; + return 0; +} + +// Parse json from command line +int testJSON2(FairMQProgOptions* config) +{ + LOG(INFO)<<"--------- test JSON2 ---------\n"; + std::string JSON; + std::string JSONrootNode; + std::string id=config->GetValue("device-id"); + JSONrootNode=config->GetValue("json.config.node.root"); + + // Note: convert the vector into one string with GetStringValue(key) + JSON=config->GetStringValue("config-json-string"); + + std::stringstream iss; + iss << JSON; + config->UserParser(iss,id,JSONrootNode); + + LOG(INFO)<<"--------- test JSON2 end ---------\n"; + return 0; +} + +////////////////////////////////////////////////////////////// +/// main +////////////////////////////////////////////////////////////// + +int main(int argc, char** argv) +{ + FairMQProgOptions* config= new FairMQProgOptions(); + try + { + po::options_description format_desc("XML or JSON input"); + format_desc.add_options() + ("xml.config.node.root", po::value()->default_value("fairMQOptions"), "xml root node ") + ("json.config.node.root", po::value()->default_value("fairMQOptions"), "json root node ") + ; + + config->AddToCmdLineOptions(format_desc); + + // Parse command line + if(config->ParseAll(argc,argv)) + return 0; + + // Set severity level (Default is 0=DEBUG) + int verbose=config->GetValue("verbose"); + FairMQLogger::Level lvl=static_cast(verbose); + SET_LOGGER_LEVEL(lvl); + + + // Parse xml or json from cmd line or file + + if(config->GetVarMap().count("config-xml-filename")) + testXML1(config); + + if(config->GetVarMap().count("config-xml-string")) + testXML2(config); + + if(config->GetVarMap().count("config-json-filename")) + testJSON1(config); + + if(config->GetVarMap().count("config-json-string")) + testJSON2(config); + + } + catch (std::exception& e) + { + LOG(ERROR) << e.what(); + return 1; + } + return 0; +} + + + + + + diff --git a/fairmq/options/ProgOptionTest/run/testMQoptions2.cxx b/fairmq/options/ProgOptionTest/run/testMQoptions2.cxx new file mode 100644 index 00000000..c29a7110 --- /dev/null +++ b/fairmq/options/ProgOptionTest/run/testMQoptions2.cxx @@ -0,0 +1,79 @@ +/// std +#include +#include + +/// boost +#include "boost/program_options.hpp" + +/// FairRoot/FairMQ +#include "FairMQLogger.h" +#include "FairMQParser.h" +#include "FairMQProgOptions.h" + +////////////////////////////////////////////////////////////// +/// main +////////////////////////////////////////////////////////////// + +int main(int argc, char** argv) +{ + + try + { + FairMQProgOptions config; + + po::options_description format_desc("XML input"); + format_desc.add_options() + ("xml.config.node.root", po::value()->default_value("fairMQOptions"), "xml root node ") + ; + + po::options_description io_file_opt_desc("I/O file Options"); + io_file_opt_desc.add_options() + ("input.file.name", po::value(), "input file name") + ("input.file.tree", po::value(), "input tree name") + ("input.file.branch", po::value(), "input branch name") + ("output.file.name", po::value(), "output file name") + ("output.file.tree", po::value(), "output tree name") + ("output.file.branch", po::value(), "output branch name") + ; + + config.AddToCmdLineOptions(format_desc,true); + config.AddToCmdLineOptions(io_file_opt_desc,true); + + + config.EnableCfgFile();// UseConfigFile (by default config file is not defined) + config.AddToCfgFileOptions(format_desc,false);//false because already added to visible + config.AddToCfgFileOptions(io_file_opt_desc,false); + + // Parse command line and config file + if(config.ParseAll(argc,argv)) + return 0; + + // Set severity level (Default is 0=DEBUG) + int verbose=config.GetValue("verbose"); + FairMQLogger::Level lvl=static_cast(verbose); + SET_LOGGER_LEVEL(lvl); + + // parse XML file + std::string filename; + std::string XMLrootNode; + + filename=config.GetValue("config-xml-filename"); + XMLrootNode=config.GetValue("xml.config.node.root"); + std::string id=config.GetValue("device-id"); + config.UserParser(filename,id,XMLrootNode); + + + } + catch (std::exception& e) + { + MQLOG(ERROR) << e.what(); + return 1; + } + return 0; +} + + + + + +