$treeview $search $mathjax
00001 00005 // ////////////////////////////////////////////////////////////////////// 00006 // Import section 00007 // ////////////////////////////////////////////////////////////////////// 00008 // STL 00009 #include <cassert> 00010 #include <sstream> 00011 #include <fstream> 00012 #include <string> 00013 #include <unistd.h> 00014 // Boost (Extended STL) 00015 #include <boost/program_options.hpp> 00016 #include <boost/tokenizer.hpp> 00017 // ZeroMQ 00018 #include <zmq.hpp> 00019 // StdAir 00020 #include <stdair/basic/BasLogParams.hpp> 00021 #include <stdair/basic/BasDBParams.hpp> 00022 #include <stdair/service/Logger.hpp> 00023 #include <stdair/stdair_json.hpp> 00024 // AirInvServer 00025 #include <airinv/config/airinv-paths.hpp> 00026 #include <airinv/AIRINV_Master_Service.hpp> 00027 00028 // ///////// Type definitions ////////// 00029 typedef unsigned int ServerPort_T; 00030 00031 // //////// Constants ////// 00033 const std::string K_AIRINV_DEFAULT_LOG_FILENAME ("airinvServer.log"); 00034 00036 const std::string K_AIRINV_DEFAULT_SERVER_PROTOCOL ("tcp://"); 00037 00039 const std::string K_AIRINV_DEFAULT_SERVER_ADDRESS ("*"); 00040 00042 const ServerPort_T K_AIRINV_DEFAULT_SERVER_PORT (5555); 00043 00045 const std::string K_AIRINV_DEFAULT_INVENTORY_FILENAME (STDAIR_SAMPLE_DIR 00046 "/invdump01.csv"); 00048 const std::string K_AIRINV_DEFAULT_SCHEDULE_FILENAME (STDAIR_SAMPLE_DIR 00049 "/schedule01.csv"); 00051 const std::string K_AIRINV_DEFAULT_OND_FILENAME (STDAIR_SAMPLE_DIR 00052 "/ond01.csv"); 00054 const std::string K_AIRINV_DEFAULT_FRAT5_INPUT_FILENAME (STDAIR_SAMPLE_DIR 00055 "/frat5.csv"); 00057 const std::string K_AIRINV_DEFAULT_FF_DISUTILITY_INPUT_FILENAME (STDAIR_SAMPLE_DIR 00058 "/ffDisutility.csv"); 00059 00061 const std::string K_AIRINV_DEFAULT_YIELD_FILENAME (STDAIR_SAMPLE_DIR 00062 "/yield01.csv"); 00063 00068 const bool K_AIRINV_DEFAULT_BUILT_IN_INPUT = false; 00069 00074 const bool K_AIRINV_DEFAULT_FOR_SCHEDULE = false; 00075 00079 const int K_AIRINV_EARLY_RETURN_STATUS = 99; 00080 00084 struct Command_T { 00085 typedef enum { 00086 NOP = 0, 00087 QUIT, 00088 DISPLAY, 00089 SELL, 00090 LAST_VALUE 00091 } Type_T; 00092 }; 00093 00094 // ///////// Parsing of Options & Configuration ///////// 00095 // A helper function to simplify the main part. 00096 template<class T> std::ostream& operator<< (std::ostream& os, 00097 const std::vector<T>& v) { 00098 std::copy (v.begin(), v.end(), std::ostream_iterator<T> (std::cout, " ")); 00099 return os; 00100 } 00101 00103 int readConfiguration (int argc, char* argv[], std::string& ioServerProtocol, 00104 std::string& ioServerAddress, ServerPort_T& ioServerPort, 00105 bool& ioIsBuiltin, bool& ioIsForSchedule, 00106 stdair::Filename_T& ioInventoryFilename, 00107 stdair::Filename_T& ioScheduleInputFilename, 00108 stdair::Filename_T& ioODInputFilename, 00109 stdair::Filename_T& ioFRAT5Filename, 00110 stdair::Filename_T& ioFFDisutilityFilename, 00111 stdair::Filename_T& ioYieldInputFilename, 00112 std::string& ioLogFilename) { 00113 // Default for the built-in input 00114 ioIsBuiltin = K_AIRINV_DEFAULT_BUILT_IN_INPUT; 00115 00116 // Default for the inventory or schedule option 00117 ioIsForSchedule = K_AIRINV_DEFAULT_FOR_SCHEDULE; 00118 00119 // Declare a group of options that will be allowed only on command line 00120 boost::program_options::options_description generic ("Generic options"); 00121 generic.add_options() 00122 ("prefix", "print installation prefix") 00123 ("version,v", "print version string") 00124 ("help,h", "produce help message"); 00125 00126 // Declare a group of options that will be allowed both on command 00127 // line and in config file 00128 00129 boost::program_options::options_description config ("Configuration"); 00130 config.add_options() 00131 ("builtin,b", 00132 "The sample BOM tree can be either built-in or parsed from an input file. That latter must then be given with the -i/--inventory or -s/--schedule option") 00133 ("for_schedule,f", 00134 "The BOM tree should be built from a schedule file (instead of from an inventory dump)") 00135 ("inventory,i", 00136 boost::program_options::value< std::string >(&ioInventoryFilename)->default_value(K_AIRINV_DEFAULT_INVENTORY_FILENAME), 00137 "(CVS) input file for the inventory") 00138 ("schedule,s", 00139 boost::program_options::value< std::string >(&ioScheduleInputFilename)->default_value(K_AIRINV_DEFAULT_SCHEDULE_FILENAME), 00140 "(CVS) input file for the schedule") 00141 ("ond,o", 00142 boost::program_options::value< std::string >(&ioODInputFilename)->default_value(K_AIRINV_DEFAULT_OND_FILENAME), 00143 "(CVS) input file for the O&D") 00144 ("frat5,r", 00145 boost::program_options::value< std::string >(&ioFRAT5Filename)->default_value(K_AIRINV_DEFAULT_FRAT5_INPUT_FILENAME), 00146 "(CSV) input file for the FRAT5 Curve") 00147 ("ff_disutility,d", 00148 boost::program_options::value< std::string >(&ioFFDisutilityFilename)->default_value(K_AIRINV_DEFAULT_FF_DISUTILITY_INPUT_FILENAME), 00149 "(CSV) input file for the FF disutility Curve") 00150 ("yield,y", 00151 boost::program_options::value< std::string >(&ioYieldInputFilename)->default_value(K_AIRINV_DEFAULT_YIELD_FILENAME), 00152 "(CVS) input file for the yield") 00153 ("protocol,t", 00154 boost::program_options::value< std::string >(&ioServerProtocol)->default_value(K_AIRINV_DEFAULT_SERVER_PROTOCOL), 00155 "Server protocol") 00156 ("address,a", 00157 boost::program_options::value< std::string >(&ioServerAddress)->default_value(K_AIRINV_DEFAULT_SERVER_ADDRESS), 00158 "Server address") 00159 ("port,p", 00160 boost::program_options::value< ServerPort_T >(&ioServerPort)->default_value(K_AIRINV_DEFAULT_SERVER_PORT), 00161 "Server port") 00162 ("log,l", 00163 boost::program_options::value< std::string >(&ioLogFilename)->default_value(K_AIRINV_DEFAULT_LOG_FILENAME), 00164 "Filename for the output logs") 00165 ; 00166 00167 // Hidden options, will be allowed both on command line and 00168 // in config file, but will not be shown to the user. 00169 boost::program_options::options_description hidden ("Hidden options"); 00170 hidden.add_options() 00171 ("copyright", 00172 boost::program_options::value< std::vector<std::string> >(), 00173 "Show the copyright (license)"); 00174 00175 boost::program_options::options_description cmdline_options; 00176 cmdline_options.add(generic).add(config).add(hidden); 00177 00178 boost::program_options::options_description config_file_options; 00179 config_file_options.add(config).add(hidden); 00180 boost::program_options::options_description visible ("Allowed options"); 00181 visible.add(generic).add(config); 00182 00183 boost::program_options::positional_options_description p; 00184 p.add ("copyright", -1); 00185 00186 boost::program_options::variables_map vm; 00187 boost::program_options:: 00188 store (boost::program_options::command_line_parser (argc, argv). 00189 options (cmdline_options).positional(p).run(), vm); 00190 00191 std::ifstream ifs ("airinvServer.cfg"); 00192 boost::program_options::store (parse_config_file (ifs, config_file_options), 00193 vm); 00194 boost::program_options::notify (vm); 00195 00196 if (vm.count ("help")) { 00197 std::cout << visible << std::endl; 00198 return K_AIRINV_EARLY_RETURN_STATUS; 00199 } 00200 00201 if (vm.count ("version")) { 00202 std::cout << PACKAGE_NAME << ", version " << PACKAGE_VERSION << std::endl; 00203 return K_AIRINV_EARLY_RETURN_STATUS; 00204 } 00205 00206 if (vm.count ("prefix")) { 00207 std::cout << "Installation prefix: " << PREFIXDIR << std::endl; 00208 return K_AIRINV_EARLY_RETURN_STATUS; 00209 } 00210 00211 if (vm.count ("protocol")) { 00212 ioServerProtocol = vm["protocol"].as< std::string >(); 00213 std::cout << "Server protocol is: " << ioServerProtocol << std::endl; 00214 } 00215 00216 if (vm.count ("address")) { 00217 ioServerAddress = vm["address"].as< std::string >(); 00218 std::cout << "Server address is: " << ioServerAddress << std::endl; 00219 } 00220 00221 if (vm.count ("port")) { 00222 ioServerPort = vm["port"].as< ServerPort_T >(); 00223 std::cout << "Server port is: " << ioServerPort << std::endl; 00224 } 00225 00226 if (vm.count ("builtin")) { 00227 ioIsBuiltin = true; 00228 } 00229 const std::string isBuiltinStr = (ioIsBuiltin == true)?"yes":"no"; 00230 std::cout << "The BOM should be built-in? " << isBuiltinStr << std::endl; 00231 00232 if (vm.count ("for_schedule")) { 00233 ioIsForSchedule = true; 00234 } 00235 const std::string isForScheduleStr = (ioIsForSchedule == true)?"yes":"no"; 00236 std::cout << "The BOM should be built from schedule? " << isForScheduleStr 00237 << std::endl; 00238 00239 if (ioIsBuiltin == false) { 00240 00241 if (ioIsForSchedule == false) { 00242 // The BOM tree should be built from parsing an inventory dump 00243 if (vm.count ("inventory")) { 00244 ioInventoryFilename = vm["inventory"].as< std::string >(); 00245 std::cout << "Input inventory filename is: " << ioInventoryFilename 00246 << std::endl; 00247 00248 } else { 00249 // The built-in option is not selected. However, no inventory dump 00250 // file is specified 00251 std::cerr << "Either one among the -b/--builtin, -i/--inventory or " 00252 << " -f/--for_schedule and -s/--schedule options " 00253 << "must be specified" << std::endl; 00254 } 00255 00256 } else { 00257 // The BOM tree should be built from parsing a schedule (and O&D) file 00258 if (vm.count ("schedule")) { 00259 ioScheduleInputFilename = vm["schedule"].as< std::string >(); 00260 std::cout << "Input schedule filename is: " << ioScheduleInputFilename 00261 << std::endl; 00262 00263 } else { 00264 // The built-in option is not selected. However, no schedule file 00265 // is specified 00266 std::cerr << "Either one among the -b/--builtin, -i/--inventory or " 00267 << " -f/--for_schedule and -s/--schedule options " 00268 << "must be specified" << std::endl; 00269 } 00270 00271 if (vm.count ("ond")) { 00272 ioODInputFilename = vm["ond"].as< std::string >(); 00273 std::cout << "Input O&D filename is: " << ioODInputFilename << std::endl; 00274 } 00275 00276 if (vm.count ("frat5")) { 00277 ioFRAT5Filename = vm["frat5"].as< std::string >(); 00278 std::cout << "FRAT5 input filename is: " << ioFRAT5Filename << std::endl; 00279 00280 } 00281 00282 if (vm.count ("ff_disutility")) { 00283 ioFFDisutilityFilename = vm["ff_disutility"].as< std::string >(); 00284 std::cout << "FF disutility input filename is: " 00285 << ioFFDisutilityFilename << std::endl; 00286 00287 } 00288 00289 if (vm.count ("yield")) { 00290 ioYieldInputFilename = vm["yield"].as< std::string >(); 00291 std::cout << "Input yield filename is: " << ioYieldInputFilename << std::endl; 00292 } 00293 } 00294 } 00295 00296 if (vm.count ("log")) { 00297 ioLogFilename = vm["log"].as< std::string >(); 00298 std::cout << "Log filename is: " << ioLogFilename << std::endl; 00299 } 00300 00301 return 0; 00302 } 00303 00304 00305 // ///////// Utility functions on top of the ZeroMQ library ///////// 00309 static std::string s_recv (zmq::socket_t& socket) { 00310 zmq::message_t message; 00311 socket.recv (&message); 00312 00313 return std::string (static_cast<char*> (message.data()), message.size()); 00314 } 00315 00319 static bool s_send (zmq::socket_t& socket, const std::string& string) { 00320 zmq::message_t message (string.size()); 00321 memcpy (message.data(), string.data(), string.size()); 00322 00323 bool rc = socket.send (message); 00324 return rc; 00325 } 00326 00327 00328 // /////////////////////// M A I N //////////////////////// 00329 int main (int argc, char* argv[]) { 00330 00331 // Server parameters (for ZeroMQ) 00332 std::string ioServerProtocol; 00333 std::string ioServerAddress; 00334 ServerPort_T ioServerPort; 00335 00336 // State whether the BOM tree should be built-in or parsed from an 00337 // input file 00338 bool isBuiltin; 00339 bool isForSchedule; 00340 00341 // Input file names 00342 stdair::Filename_T lInventoryFilename; 00343 stdair::Filename_T lScheduleInputFilename; 00344 stdair::Filename_T lODInputFilename; 00345 stdair::Filename_T lFRAT5InputFilename; 00346 stdair::Filename_T lFFDisutilityInputFilename; 00347 stdair::Filename_T lYieldInputFilename; 00348 00349 // Output log File 00350 stdair::Filename_T lLogFilename; 00351 00352 // Call the command-line option parser 00353 const int lOptionParserStatus = 00354 readConfiguration (argc, argv, ioServerProtocol, ioServerAddress, 00355 ioServerPort, isBuiltin, isForSchedule, 00356 lInventoryFilename, lScheduleInputFilename, 00357 lODInputFilename, lFRAT5InputFilename, 00358 lFFDisutilityInputFilename, lYieldInputFilename, 00359 lLogFilename); 00360 00361 if (lOptionParserStatus == K_AIRINV_EARLY_RETURN_STATUS) { 00362 return 0; 00363 } 00364 00365 // Set the log parameters 00366 std::ofstream logOutputFile; 00367 // Open and clean the log outputfile 00368 logOutputFile.open (lLogFilename.c_str()); 00369 logOutputFile.clear(); 00370 00371 // Initialise the inventory service 00372 const stdair::BasLogParams lLogParams (stdair::LOG::DEBUG, logOutputFile); 00373 AIRINV::AIRINV_Master_Service airinvService (lLogParams); 00374 00375 // DEBUG 00376 STDAIR_LOG_DEBUG ("Initialisation of the AirInv server"); 00377 00378 // Check wether or not a (CSV) input file should be read 00379 if (isBuiltin == true) { 00380 00381 // Build the sample BOM tree for RMOL 00382 airinvService.buildSampleBom(); 00383 00384 } else { 00385 if (isForSchedule == true) { 00386 // Build the BOM tree from parsing a schedule file (and O&D list) 00387 stdair::ScheduleFilePath lScheduleFilePath (lScheduleInputFilename); 00388 stdair::ODFilePath lODFilePath (lODInputFilename); 00389 stdair::FRAT5FilePath lFRAT5FilePath (lFRAT5InputFilename); 00390 stdair::FFDisutilityFilePath lFFDisutilityFilePath (lFFDisutilityInputFilename); 00391 AIRRAC::YieldFilePath lYieldFilePath (lYieldInputFilename); 00392 airinvService.parseAndLoad (lScheduleFilePath, lODFilePath, 00393 lFRAT5FilePath, lFFDisutilityFilePath, 00394 lYieldFilePath); 00395 00396 } else { 00397 // Build the BOM tree from parsing an inventory dump file 00398 AIRINV::InventoryFilePath lInventoryFilePath (lInventoryFilename); 00399 airinvService.parseAndLoad (lInventoryFilePath); 00400 } 00401 } 00402 00403 // Build the connection string (e.g., "tcp://*:5555", which is the default) 00404 std::ostringstream oZeroMQBindStream; 00405 oZeroMQBindStream << ioServerProtocol << ioServerAddress 00406 << ":" << ioServerPort; 00407 const std::string lZeroMQBindString (oZeroMQBindStream.str()); 00408 00409 // Prepare the context and socket of the server 00410 zmq::context_t context (1); 00411 zmq::socket_t socket (context, ZMQ_REP); 00412 socket.bind (lZeroMQBindString.c_str()); 00413 00414 // DEBUG 00415 STDAIR_LOG_DEBUG ("The AirInv server is ready to receive requests..."); 00416 00417 while (true) { 00418 00419 // Wait for next request from client, which is expected to give 00420 // a JSON-ified command. 00421 const std::string& lReceivedString = s_recv (socket); 00422 00423 // DEBUG 00424 STDAIR_LOG_DEBUG ("Received: '" << lReceivedString << "'"); 00425 00426 const stdair::JSONString lJSONCommandString (lReceivedString); 00427 const std::string& lJSONDump = 00428 airinvService.jsonHandler (lJSONCommandString); 00429 00430 // DEBUG 00431 STDAIR_LOG_DEBUG ("Send: '" << lJSONDump << "'"); 00432 00433 // Send back the answer details to the client 00434 s_send (socket, lJSONDump); 00435 } 00436 00437 return 0; 00438 } 00439