AirInv Logo  0.1.2
C++ Simulated Airline Inventory Management System library
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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/bom/BomJSONImport.hpp>
23 #include <stdair/bom/BomJSONExport.hpp>
24 #include <stdair/service/Logger.hpp>
25 // AirInvServer
28 
29 // ///////// Type definitions //////////
30 typedef unsigned int ServerPort_T;
31 
32 // //////// Constants //////
34 const std::string K_AIRINV_DEFAULT_LOG_FILENAME ("airinvServer.log");
35 
37 const std::string K_AIRINV_DEFAULT_SERVER_PROTOCOL ("tcp://");
38 
40 const std::string K_AIRINV_DEFAULT_SERVER_ADDRESS ("*");
41 
43 const ServerPort_T K_AIRINV_DEFAULT_SERVER_PORT (5555);
44 
46 const std::string K_AIRINV_DEFAULT_INVENTORY_FILENAME (STDAIR_SAMPLE_DIR
47  "/invdump01.csv");
49 const std::string K_AIRINV_DEFAULT_SCHEDULE_FILENAME (STDAIR_SAMPLE_DIR
50  "/schedule01.csv");
52 const std::string K_AIRINV_DEFAULT_OND_FILENAME (STDAIR_SAMPLE_DIR
53  "/ond01.csv");
54 
56 const std::string K_AIRINV_DEFAULT_YIELD_FILENAME (STDAIR_SAMPLE_DIR
57  "/yield01.csv");
58 
63 const bool K_AIRINV_DEFAULT_BUILT_IN_INPUT = false;
64 
69 const bool K_AIRINV_DEFAULT_FOR_SCHEDULE = false;
70 
74 const int K_AIRINV_EARLY_RETURN_STATUS = 99;
75 
79 struct Command_T {
80  typedef enum {
81  NOP = 0,
82  QUIT,
83  DISPLAY,
84  SELL,
85  LAST_VALUE
86  } Type_T;
87 };
88 
89 // ///////// Parsing of Options & Configuration /////////
90 // A helper function to simplify the main part.
91 template<class T> std::ostream& operator<< (std::ostream& os,
92  const std::vector<T>& v) {
93  std::copy (v.begin(), v.end(), std::ostream_iterator<T> (std::cout, " "));
94  return os;
95 }
96 
98 int readConfiguration (int argc, char* argv[], std::string& ioServerProtocol,
99  std::string& ioServerAddress, ServerPort_T& ioServerPort,
100  bool& ioIsBuiltin, bool& ioIsForSchedule,
101  stdair::Filename_T& ioInventoryFilename,
102  stdair::Filename_T& ioScheduleInputFilename,
103  stdair::Filename_T& ioODInputFilename,
104  stdair::Filename_T& ioYieldInputFilename,
105  std::string& ioLogFilename) {
106  // Default for the built-in input
107  ioIsBuiltin = K_AIRINV_DEFAULT_BUILT_IN_INPUT;
108 
109  // Default for the inventory or schedule option
110  ioIsForSchedule = K_AIRINV_DEFAULT_FOR_SCHEDULE;
111 
112  // Declare a group of options that will be allowed only on command line
113  boost::program_options::options_description generic ("Generic options");
114  generic.add_options()
115  ("prefix", "print installation prefix")
116  ("version,v", "print version string")
117  ("help,h", "produce help message");
118 
119  // Declare a group of options that will be allowed both on command
120  // line and in config file
121 
122  boost::program_options::options_description config ("Configuration");
123  config.add_options()
124  ("builtin,b",
125  "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")
126  ("for_schedule,f",
127  "The BOM tree should be built from a schedule file (instead of from an inventory dump)")
128  ("inventory,i",
129  boost::program_options::value< std::string >(&ioInventoryFilename)->default_value(K_AIRINV_DEFAULT_INVENTORY_FILENAME),
130  "(CVS) input file for the inventory")
131  ("schedule,s",
132  boost::program_options::value< std::string >(&ioScheduleInputFilename)->default_value(K_AIRINV_DEFAULT_SCHEDULE_FILENAME),
133  "(CVS) input file for the schedule")
134  ("ond,o",
135  boost::program_options::value< std::string >(&ioODInputFilename)->default_value(K_AIRINV_DEFAULT_OND_FILENAME),
136  "(CVS) input file for the O&D")
137  ("yield,y",
138  boost::program_options::value< std::string >(&ioYieldInputFilename)->default_value(K_AIRINV_DEFAULT_YIELD_FILENAME),
139  "(CVS) input file for the yield")
140  ("protocol,t",
141  boost::program_options::value< std::string >(&ioServerProtocol)->default_value(K_AIRINV_DEFAULT_SERVER_PROTOCOL),
142  "Server protocol")
143  ("address,a",
144  boost::program_options::value< std::string >(&ioServerAddress)->default_value(K_AIRINV_DEFAULT_SERVER_ADDRESS),
145  "Server address")
146  ("port,p",
147  boost::program_options::value< ServerPort_T >(&ioServerPort)->default_value(K_AIRINV_DEFAULT_SERVER_PORT),
148  "Server port")
149  ("log,l",
150  boost::program_options::value< std::string >(&ioLogFilename)->default_value(K_AIRINV_DEFAULT_LOG_FILENAME),
151  "Filename for the output logs")
152  ;
153 
154  // Hidden options, will be allowed both on command line and
155  // in config file, but will not be shown to the user.
156  boost::program_options::options_description hidden ("Hidden options");
157  hidden.add_options()
158  ("copyright",
159  boost::program_options::value< std::vector<std::string> >(),
160  "Show the copyright (license)");
161 
162  boost::program_options::options_description cmdline_options;
163  cmdline_options.add(generic).add(config).add(hidden);
164 
165  boost::program_options::options_description config_file_options;
166  config_file_options.add(config).add(hidden);
167  boost::program_options::options_description visible ("Allowed options");
168  visible.add(generic).add(config);
169 
170  boost::program_options::positional_options_description p;
171  p.add ("copyright", -1);
172 
173  boost::program_options::variables_map vm;
174  boost::program_options::
175  store (boost::program_options::command_line_parser (argc, argv).
176  options (cmdline_options).positional(p).run(), vm);
177 
178  std::ifstream ifs ("airinvServer.cfg");
179  boost::program_options::store (parse_config_file (ifs, config_file_options),
180  vm);
181  boost::program_options::notify (vm);
182 
183  if (vm.count ("help")) {
184  std::cout << visible << std::endl;
185  return K_AIRINV_EARLY_RETURN_STATUS;
186  }
187 
188  if (vm.count ("version")) {
189  std::cout << PACKAGE_NAME << ", version " << PACKAGE_VERSION << std::endl;
190  return K_AIRINV_EARLY_RETURN_STATUS;
191  }
192 
193  if (vm.count ("prefix")) {
194  std::cout << "Installation prefix: " << PREFIXDIR << std::endl;
195  return K_AIRINV_EARLY_RETURN_STATUS;
196  }
197 
198  if (vm.count ("protocol")) {
199  ioServerProtocol = vm["protocol"].as< std::string >();
200  std::cout << "Server protocol is: " << ioServerProtocol << std::endl;
201  }
202 
203  if (vm.count ("address")) {
204  ioServerAddress = vm["address"].as< std::string >();
205  std::cout << "Server address is: " << ioServerAddress << std::endl;
206  }
207 
208  if (vm.count ("port")) {
209  ioServerPort = vm["port"].as< ServerPort_T >();
210  std::cout << "Server port is: " << ioServerPort << std::endl;
211  }
212 
213  if (vm.count ("builtin")) {
214  ioIsBuiltin = true;
215  }
216  const std::string isBuiltinStr = (ioIsBuiltin == true)?"yes":"no";
217  std::cout << "The BOM should be built-in? " << isBuiltinStr << std::endl;
218 
219  if (vm.count ("for_schedule")) {
220  ioIsForSchedule = true;
221  }
222  const std::string isForScheduleStr = (ioIsForSchedule == true)?"yes":"no";
223  std::cout << "The BOM should be built from schedule? " << isForScheduleStr
224  << std::endl;
225 
226  if (ioIsBuiltin == false) {
227 
228  if (ioIsForSchedule == false) {
229  // The BOM tree should be built from parsing an inventory dump
230  if (vm.count ("inventory")) {
231  ioInventoryFilename = vm["inventory"].as< std::string >();
232  std::cout << "Input inventory filename is: " << ioInventoryFilename
233  << std::endl;
234 
235  } else {
236  // The built-in option is not selected. However, no inventory dump
237  // file is specified
238  std::cerr << "Either one among the -b/--builtin, -i/--inventory or "
239  << " -f/--for_schedule and -s/--schedule options "
240  << "must be specified" << std::endl;
241  }
242 
243  } else {
244  // The BOM tree should be built from parsing a schedule (and O&D) file
245  if (vm.count ("schedule")) {
246  ioScheduleInputFilename = vm["schedule"].as< std::string >();
247  std::cout << "Input schedule filename is: " << ioScheduleInputFilename
248  << std::endl;
249 
250  } else {
251  // The built-in option is not selected. However, no schedule file
252  // is specified
253  std::cerr << "Either one among the -b/--builtin, -i/--inventory or "
254  << " -f/--for_schedule and -s/--schedule options "
255  << "must be specified" << std::endl;
256  }
257 
258  if (vm.count ("ond")) {
259  ioODInputFilename = vm["ond"].as< std::string >();
260  std::cout << "Input O&D filename is: " << ioODInputFilename << std::endl;
261  }
262 
263  if (vm.count ("yield")) {
264  ioYieldInputFilename = vm["yield"].as< std::string >();
265  std::cout << "Input yield filename is: " << ioYieldInputFilename << std::endl;
266  }
267  }
268  }
269 
270  if (vm.count ("log")) {
271  ioLogFilename = vm["log"].as< std::string >();
272  std::cout << "Log filename is: " << ioLogFilename << std::endl;
273  }
274 
275  return 0;
276 }
277 
278 
279 // ///////// Utility functions on top of the ZeroMQ library /////////
283 static std::string s_recv (zmq::socket_t& socket) {
284  zmq::message_t message;
285  socket.recv (&message);
286 
287  return std::string (static_cast<char*> (message.data()), message.size());
288 }
289 
293 static bool s_send (zmq::socket_t& socket, const std::string& string) {
294  zmq::message_t message (string.size());
295  memcpy (message.data(), string.data(), string.size());
296 
297  bool rc = socket.send (message);
298  return rc;
299 }
300 
301 
302 // /////////////////////// M A I N ////////////////////////
303 int main (int argc, char* argv[]) {
304 
305  // Server parameters (for ZeroMQ)
306  std::string ioServerProtocol;
307  std::string ioServerAddress;
308  ServerPort_T ioServerPort;
309 
310  // State whether the BOM tree should be built-in or parsed from an
311  // input file
312  bool isBuiltin;
313  bool isForSchedule;
314 
315  // Input file names
316  stdair::Filename_T lInventoryFilename;
317  stdair::Filename_T lScheduleInputFilename;
318  stdair::Filename_T lODInputFilename;
319  stdair::Filename_T lYieldInputFilename;
320 
321  // Output log File
322  stdair::Filename_T lLogFilename;
323 
324  // Call the command-line option parser
325  const int lOptionParserStatus =
326  readConfiguration (argc, argv, ioServerProtocol, ioServerAddress,
327  ioServerPort, isBuiltin, isForSchedule,
328  lInventoryFilename, lScheduleInputFilename,
329  lODInputFilename, lYieldInputFilename, lLogFilename);
330 
331  if (lOptionParserStatus == K_AIRINV_EARLY_RETURN_STATUS) {
332  return 0;
333  }
334 
335  // Set the log parameters
336  std::ofstream logOutputFile;
337  // Open and clean the log outputfile
338  logOutputFile.open (lLogFilename.c_str());
339  logOutputFile.clear();
340 
341  // Initialise the inventory service
342  const stdair::BasLogParams lLogParams (stdair::LOG::DEBUG, logOutputFile);
343  AIRINV::AIRINV_Master_Service airinvService (lLogParams);
344 
345  // DEBUG
346  STDAIR_LOG_DEBUG ("Initialisation of the AirInv server");
347 
348  // Check wether or not a (CSV) input file should be read
349  if (isBuiltin == true) {
350 
351  // Build the sample BOM tree for RMOL
352  airinvService.buildSampleBom();
353 
354  } else {
355  if (isForSchedule == true) {
356  // Build the BOM tree from parsing a schedule file (and O&D list)
357  AIRRAC::YieldFilePath lYieldFilePath (lYieldInputFilename);
358  airinvService.parseAndLoad (lScheduleInputFilename, lODInputFilename,
359  lYieldFilePath);
360 
361  } else {
362  // Build the BOM tree from parsing an inventory dump file
363  airinvService.parseAndLoad (lInventoryFilename);
364  }
365  }
366 
367  // Build the connection string (e.g., "tcp://*:5555", which is the default)
368  std::ostringstream oZeroMQBindStream;
369  oZeroMQBindStream << ioServerProtocol << ioServerAddress
370  << ":" << ioServerPort;
371  const std::string lZeroMQBindString (oZeroMQBindStream.str());
372 
373  // Prepare the context and socket of the server
374  zmq::context_t context (1);
375  zmq::socket_t socket (context, ZMQ_REP);
376  socket.bind (lZeroMQBindString.c_str());
377 
378  // DEBUG
379  STDAIR_LOG_DEBUG ("The AirInv server is ready to receive requests...");
380 
381  while (true) {
382 
383  // Wait for next request from client, which is expected to give
384  // the JSON-ified details of the requested flight-date
385  const std::string& lFlightDateKeyJSONString = s_recv (socket);
386 
387  // DEBUG
388  STDAIR_LOG_DEBUG ("Received: '" << lFlightDateKeyJSONString << "'");
389 
390  // Extract, from the JSON-ified string an airline code
391  stdair::AirlineCode_T lAirlineCode;
392  stdair::BomJSONImport::jsonImportInventoryKey (lFlightDateKeyJSONString,
393  lAirlineCode);
394 
395  // Extract, from the JSON-ified string a flight number and a departure date
396  stdair::FlightNumber_T lFlightNumber;
397  stdair::Date_T lDate;
398  stdair::BomJSONImport::jsonImportFlightDateKey (lFlightDateKeyJSONString,
399  lFlightNumber, lDate);
400 
401  // DEBUG
402  STDAIR_LOG_DEBUG ("=> airline code = '" << lAirlineCode
403  << "', flight number = " << lFlightNumber
404  << "', departure date = '" << lDate << "'");
405 
406  // DEBUG: Display the flight-date dump
407  const std::string& lFlightDateCSVDump =
408  airinvService.csvDisplay (lAirlineCode, lFlightNumber, lDate);
409  STDAIR_LOG_DEBUG (std::endl << lFlightDateCSVDump);
410 
411  // Dump the full details of the flight-date into the JSON-ified flight-date
412  const std::string& lFlightDateJSONDump =
413  airinvService.jsonExport (lAirlineCode, lFlightNumber, lDate);
414 
415  // DEBUG
416  STDAIR_LOG_DEBUG ("Send: '" << lFlightDateJSONDump << "'");
417 
418  // Send back the flight-date details to the client
419  s_send (socket, lFlightDateJSONDump);
420  }
421 
422  return 0;
423 }
424