AirInv Logo  1.00.9
C++ Simulated Airline Inventory Management System Library
AirInvServer.cpp
Go to the documentation of this file.
1 
5 // //////////////////////////////////////////////////////////////////////
6 // Import section
7 // //////////////////////////////////////////////////////////////////////
8 // STL
9 #include <cassert>
10 #include <sstream>
11 #include <fstream>
12 #include <string>
13 #include <unistd.h>
14 // Boost (Extended STL)
15 #include <boost/program_options.hpp>
16 #include <boost/tokenizer.hpp>
17 // ZeroMQ
18 #include <zmq.hpp>
19 // StdAir
20 #include <stdair/basic/BasLogParams.hpp>
21 #include <stdair/basic/BasDBParams.hpp>
22 #include <stdair/service/Logger.hpp>
23 #include <stdair/stdair_json.hpp>
24 // AirInvServer
25 #include <airinv/config/airinv-paths.hpp>
27 
28 // ///////// Type definitions //////////
29 typedef unsigned int ServerPort_T;
30 
31 // //////// Constants //////
33 const std::string K_AIRINV_DEFAULT_LOG_FILENAME ("airinvServer.log");
34 
36 const std::string K_AIRINV_DEFAULT_SERVER_PROTOCOL ("tcp://");
37 
39 const std::string K_AIRINV_DEFAULT_SERVER_ADDRESS ("*");
40 
42 const ServerPort_T K_AIRINV_DEFAULT_SERVER_PORT (5555);
43 
45 const std::string K_AIRINV_DEFAULT_INVENTORY_FILENAME (STDAIR_SAMPLE_DIR
46  "/invdump01.csv");
48 const std::string K_AIRINV_DEFAULT_SCHEDULE_FILENAME (STDAIR_SAMPLE_DIR
49  "/schedule01.csv");
51 const std::string K_AIRINV_DEFAULT_OND_FILENAME (STDAIR_SAMPLE_DIR
52  "/ond01.csv");
54 const std::string K_AIRINV_DEFAULT_FRAT5_INPUT_FILENAME (STDAIR_SAMPLE_DIR
55  "/frat5.csv");
57 const std::string K_AIRINV_DEFAULT_FF_DISUTILITY_INPUT_FILENAME (STDAIR_SAMPLE_DIR
58  "/ffDisutility.csv");
59 
61 const std::string K_AIRINV_DEFAULT_YIELD_FILENAME (STDAIR_SAMPLE_DIR
62  "/yield01.csv");
63 
68 const bool K_AIRINV_DEFAULT_BUILT_IN_INPUT = false;
69 
74 const bool K_AIRINV_DEFAULT_FOR_SCHEDULE = false;
75 
79 const int K_AIRINV_EARLY_RETURN_STATUS = 99;
80 
84 struct Command_T {
85  typedef enum {
86  NOP = 0,
87  QUIT,
88  DISPLAY,
89  SELL,
90  LAST_VALUE
91  } Type_T;
92 };
93 
94 // ///////// Parsing of Options & Configuration /////////
95 // A helper function to simplify the main part.
96 template<class T> std::ostream& operator<< (std::ostream& os,
97  const std::vector<T>& v) {
98  std::copy (v.begin(), v.end(), std::ostream_iterator<T> (std::cout, " "));
99  return os;
100 }
101 
103 int readConfiguration (int argc, char* argv[], std::string& ioServerProtocol,
104  std::string& ioServerAddress, ServerPort_T& ioServerPort,
105  bool& ioIsBuiltin, bool& ioIsForSchedule,
106  stdair::Filename_T& ioInventoryFilename,
107  stdair::Filename_T& ioScheduleInputFilename,
108  stdair::Filename_T& ioODInputFilename,
109  stdair::Filename_T& ioFRAT5Filename,
110  stdair::Filename_T& ioFFDisutilityFilename,
111  stdair::Filename_T& ioYieldInputFilename,
112  std::string& ioLogFilename) {
113  // Default for the built-in input
114  ioIsBuiltin = K_AIRINV_DEFAULT_BUILT_IN_INPUT;
115 
116  // Default for the inventory or schedule option
117  ioIsForSchedule = K_AIRINV_DEFAULT_FOR_SCHEDULE;
118 
119  // Declare a group of options that will be allowed only on command line
120  boost::program_options::options_description generic ("Generic options");
121  generic.add_options()
122  ("prefix", "print installation prefix")
123  ("version,v", "print version string")
124  ("help,h", "produce help message");
125 
126  // Declare a group of options that will be allowed both on command
127  // line and in config file
128 
129  boost::program_options::options_description config ("Configuration");
130  config.add_options()
131  ("builtin,b",
132  "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")
133  ("for_schedule,f",
134  "The BOM tree should be built from a schedule file (instead of from an inventory dump)")
135  ("inventory,i",
136  boost::program_options::value< std::string >(&ioInventoryFilename)->default_value(K_AIRINV_DEFAULT_INVENTORY_FILENAME),
137  "(CVS) input file for the inventory")
138  ("schedule,s",
139  boost::program_options::value< std::string >(&ioScheduleInputFilename)->default_value(K_AIRINV_DEFAULT_SCHEDULE_FILENAME),
140  "(CVS) input file for the schedule")
141  ("ond,o",
142  boost::program_options::value< std::string >(&ioODInputFilename)->default_value(K_AIRINV_DEFAULT_OND_FILENAME),
143  "(CVS) input file for the O&D")
144  ("frat5,r",
145  boost::program_options::value< std::string >(&ioFRAT5Filename)->default_value(K_AIRINV_DEFAULT_FRAT5_INPUT_FILENAME),
146  "(CSV) input file for the FRAT5 Curve")
147  ("ff_disutility,d",
148  boost::program_options::value< std::string >(&ioFFDisutilityFilename)->default_value(K_AIRINV_DEFAULT_FF_DISUTILITY_INPUT_FILENAME),
149  "(CSV) input file for the FF disutility Curve")
150  ("yield,y",
151  boost::program_options::value< std::string >(&ioYieldInputFilename)->default_value(K_AIRINV_DEFAULT_YIELD_FILENAME),
152  "(CVS) input file for the yield")
153  ("protocol,t",
154  boost::program_options::value< std::string >(&ioServerProtocol)->default_value(K_AIRINV_DEFAULT_SERVER_PROTOCOL),
155  "Server protocol")
156  ("address,a",
157  boost::program_options::value< std::string >(&ioServerAddress)->default_value(K_AIRINV_DEFAULT_SERVER_ADDRESS),
158  "Server address")
159  ("port,p",
160  boost::program_options::value< ServerPort_T >(&ioServerPort)->default_value(K_AIRINV_DEFAULT_SERVER_PORT),
161  "Server port")
162  ("log,l",
163  boost::program_options::value< std::string >(&ioLogFilename)->default_value(K_AIRINV_DEFAULT_LOG_FILENAME),
164  "Filename for the output logs")
165  ;
166 
167  // Hidden options, will be allowed both on command line and
168  // in config file, but will not be shown to the user.
169  boost::program_options::options_description hidden ("Hidden options");
170  hidden.add_options()
171  ("copyright",
172  boost::program_options::value< std::vector<std::string> >(),
173  "Show the copyright (license)");
174 
175  boost::program_options::options_description cmdline_options;
176  cmdline_options.add(generic).add(config).add(hidden);
177 
178  boost::program_options::options_description config_file_options;
179  config_file_options.add(config).add(hidden);
180  boost::program_options::options_description visible ("Allowed options");
181  visible.add(generic).add(config);
182 
183  boost::program_options::positional_options_description p;
184  p.add ("copyright", -1);
185 
186  boost::program_options::variables_map vm;
187  boost::program_options::
188  store (boost::program_options::command_line_parser (argc, argv).
189  options (cmdline_options).positional(p).run(), vm);
190 
191  std::ifstream ifs ("airinvServer.cfg");
192  boost::program_options::store (parse_config_file (ifs, config_file_options),
193  vm);
194  boost::program_options::notify (vm);
195 
196  if (vm.count ("help")) {
197  std::cout << visible << std::endl;
198  return K_AIRINV_EARLY_RETURN_STATUS;
199  }
200 
201  if (vm.count ("version")) {
202  std::cout << PACKAGE_NAME << ", version " << PACKAGE_VERSION << std::endl;
203  return K_AIRINV_EARLY_RETURN_STATUS;
204  }
205 
206  if (vm.count ("prefix")) {
207  std::cout << "Installation prefix: " << PREFIXDIR << std::endl;
208  return K_AIRINV_EARLY_RETURN_STATUS;
209  }
210 
211  if (vm.count ("protocol")) {
212  ioServerProtocol = vm["protocol"].as< std::string >();
213  std::cout << "Server protocol is: " << ioServerProtocol << std::endl;
214  }
215 
216  if (vm.count ("address")) {
217  ioServerAddress = vm["address"].as< std::string >();
218  std::cout << "Server address is: " << ioServerAddress << std::endl;
219  }
220 
221  if (vm.count ("port")) {
222  ioServerPort = vm["port"].as< ServerPort_T >();
223  std::cout << "Server port is: " << ioServerPort << std::endl;
224  }
225 
226  if (vm.count ("builtin")) {
227  ioIsBuiltin = true;
228  }
229  const std::string isBuiltinStr = (ioIsBuiltin == true)?"yes":"no";
230  std::cout << "The BOM should be built-in? " << isBuiltinStr << std::endl;
231 
232  if (vm.count ("for_schedule")) {
233  ioIsForSchedule = true;
234  }
235  const std::string isForScheduleStr = (ioIsForSchedule == true)?"yes":"no";
236  std::cout << "The BOM should be built from schedule? " << isForScheduleStr
237  << std::endl;
238 
239  if (ioIsBuiltin == false) {
240 
241  if (ioIsForSchedule == false) {
242  // The BOM tree should be built from parsing an inventory dump
243  if (vm.count ("inventory")) {
244  ioInventoryFilename = vm["inventory"].as< std::string >();
245  std::cout << "Input inventory filename is: " << ioInventoryFilename
246  << std::endl;
247 
248  } else {
249  // The built-in option is not selected. However, no inventory dump
250  // file is specified
251  std::cerr << "Either one among the -b/--builtin, -i/--inventory or "
252  << " -f/--for_schedule and -s/--schedule options "
253  << "must be specified" << std::endl;
254  }
255 
256  } else {
257  // The BOM tree should be built from parsing a schedule (and O&D) file
258  if (vm.count ("schedule")) {
259  ioScheduleInputFilename = vm["schedule"].as< std::string >();
260  std::cout << "Input schedule filename is: " << ioScheduleInputFilename
261  << std::endl;
262 
263  } else {
264  // The built-in option is not selected. However, no schedule file
265  // is specified
266  std::cerr << "Either one among the -b/--builtin, -i/--inventory or "
267  << " -f/--for_schedule and -s/--schedule options "
268  << "must be specified" << std::endl;
269  }
270 
271  if (vm.count ("ond")) {
272  ioODInputFilename = vm["ond"].as< std::string >();
273  std::cout << "Input O&D filename is: " << ioODInputFilename << std::endl;
274  }
275 
276  if (vm.count ("frat5")) {
277  ioFRAT5Filename = vm["frat5"].as< std::string >();
278  std::cout << "FRAT5 input filename is: " << ioFRAT5Filename << std::endl;
279 
280  }
281 
282  if (vm.count ("ff_disutility")) {
283  ioFFDisutilityFilename = vm["ff_disutility"].as< std::string >();
284  std::cout << "FF disutility input filename is: "
285  << ioFFDisutilityFilename << std::endl;
286 
287  }
288 
289  if (vm.count ("yield")) {
290  ioYieldInputFilename = vm["yield"].as< std::string >();
291  std::cout << "Input yield filename is: " << ioYieldInputFilename << std::endl;
292  }
293  }
294  }
295 
296  if (vm.count ("log")) {
297  ioLogFilename = vm["log"].as< std::string >();
298  std::cout << "Log filename is: " << ioLogFilename << std::endl;
299  }
300 
301  return 0;
302 }
303 
304 
305 // ///////// Utility functions on top of the ZeroMQ library /////////
309 static std::string s_recv (zmq::socket_t& socket) {
310  zmq::message_t message;
311  socket.recv (message);
312 
313  return std::string (static_cast<char*> (message.data()), message.size());
314 }
315 
319 static zmq::send_result_t s_send (zmq::socket_t& socket, const std::string& string) {
320  zmq::message_t message (string.size());
321  memcpy (message.data(), string.data(), string.size());
322 
323  zmq::send_flags flags = zmq::send_flags::none;
324 
325  zmq::send_result_t rc = socket.send (message, flags);
326  return rc;
327 }
328 
329 
330 // /////////////////////// M A I N ////////////////////////
331 int main (int argc, char* argv[]) {
332 
333  // Server parameters (for ZeroMQ)
334  std::string ioServerProtocol;
335  std::string ioServerAddress;
336  ServerPort_T ioServerPort;
337 
338  // State whether the BOM tree should be built-in or parsed from an
339  // input file
340  bool isBuiltin;
341  bool isForSchedule;
342 
343  // Input file names
344  stdair::Filename_T lInventoryFilename;
345  stdair::Filename_T lScheduleInputFilename;
346  stdair::Filename_T lODInputFilename;
347  stdair::Filename_T lFRAT5InputFilename;
348  stdair::Filename_T lFFDisutilityInputFilename;
349  stdair::Filename_T lYieldInputFilename;
350 
351  // Output log File
352  stdair::Filename_T lLogFilename;
353 
354  // Call the command-line option parser
355  const int lOptionParserStatus =
356  readConfiguration (argc, argv, ioServerProtocol, ioServerAddress,
357  ioServerPort, isBuiltin, isForSchedule,
358  lInventoryFilename, lScheduleInputFilename,
359  lODInputFilename, lFRAT5InputFilename,
360  lFFDisutilityInputFilename, lYieldInputFilename,
361  lLogFilename);
362 
363  if (lOptionParserStatus == K_AIRINV_EARLY_RETURN_STATUS) {
364  return 0;
365  }
366 
367  // Set the log parameters
368  std::ofstream logOutputFile;
369  // Open and clean the log outputfile
370  logOutputFile.open (lLogFilename.c_str());
371  logOutputFile.clear();
372 
373  // Initialise the inventory service
374  const stdair::BasLogParams lLogParams (stdair::LOG::DEBUG, logOutputFile);
375  AIRINV::AIRINV_Master_Service airinvService (lLogParams);
376 
377  // DEBUG
378  STDAIR_LOG_DEBUG ("Initialisation of the AirInv server");
379 
380  // Check wether or not a (CSV) input file should be read
381  if (isBuiltin == true) {
382 
383  // Build the sample BOM tree for RMOL
384  airinvService.buildSampleBom();
385 
386  } else {
387  if (isForSchedule == true) {
388  // Build the BOM tree from parsing a schedule file (and O&D list)
389  stdair::ScheduleFilePath lScheduleFilePath (lScheduleInputFilename);
390  stdair::ODFilePath lODFilePath (lODInputFilename);
391  stdair::FRAT5FilePath lFRAT5FilePath (lFRAT5InputFilename);
392  stdair::FFDisutilityFilePath lFFDisutilityFilePath (lFFDisutilityInputFilename);
393  AIRRAC::YieldFilePath lYieldFilePath (lYieldInputFilename);
394  airinvService.parseAndLoad (lScheduleFilePath, lODFilePath,
395  lFRAT5FilePath, lFFDisutilityFilePath,
396  lYieldFilePath);
397 
398  } else {
399  // Build the BOM tree from parsing an inventory dump file
400  AIRINV::InventoryFilePath lInventoryFilePath (lInventoryFilename);
401  airinvService.parseAndLoad (lInventoryFilePath);
402  }
403  }
404 
405  // Build the connection string (e.g., "tcp://*:5555", which is the default)
406  std::ostringstream oZeroMQBindStream;
407  oZeroMQBindStream << ioServerProtocol << ioServerAddress
408  << ":" << ioServerPort;
409  const std::string lZeroMQBindString (oZeroMQBindStream.str());
410 
411  // Prepare the context and socket of the server
412  zmq::context_t context (1);
413  zmq::socket_t socket (context, ZMQ_REP);
414  socket.bind (lZeroMQBindString.c_str());
415 
416  // DEBUG
417  STDAIR_LOG_DEBUG ("The AirInv server is ready to receive requests...");
418 
419  while (true) {
420 
421  // Wait for next request from client, which is expected to give
422  // a JSON-ified command.
423  const std::string& lReceivedString = s_recv (socket);
424 
425  // DEBUG
426  STDAIR_LOG_DEBUG ("Received: '" << lReceivedString << "'");
427 
428  const stdair::JSONString lJSONCommandString (lReceivedString);
429  const std::string& lJSONDump =
430  airinvService.jsonHandler (lJSONCommandString);
431 
432  // DEBUG
433  STDAIR_LOG_DEBUG ("Send: '" << lJSONDump << "'");
434 
435  // Send back the answer details to the client
436  s_send (socket, lJSONDump);
437  }
438 
439  return 0;
440 }
441 
int main(int argc, char *argv[])
std::basic_ostream< charT, traits > & operator<<(std::basic_ostream< charT, traits > &ioOut, const AIRINV::BomAbstract &iBom)
Definition: BomAbstract.hpp:56
Interface for the AIRINV Services.