$treeview $search $mathjax
AirInv Logo  1.00.0
$projectbrief
$projectbrief
$searchbox

AirInvServer.cpp

Go to the documentation of this file.
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