AirRAC Logo  1.00.0
C++ Simulated Revenue Accounting (RAC) System Library
 All Classes Namespaces Files Functions Variables Typedefs Friends Pages
YieldParserHelper.cpp
Go to the documentation of this file.
1 // //////////////////////////////////////////////////////////////////////
2 // Import section
3 // //////////////////////////////////////////////////////////////////////
4 // STL
5 #include <cassert>
6 #include <fstream>
7 #include <vector>
8 // StdAir
9 #include <stdair/basic/BasFileMgr.hpp>
10 #include <stdair/basic/BasConst_Request.hpp>
11 #include <stdair/bom/BomRoot.hpp>
12 #include <stdair/service/Logger.hpp>
13 //#define BOOST_SPIRIT_DEBUG
14 #include <stdair/basic/BasParserTypes.hpp>
15 // Airrac
18 
19 namespace AIRRAC {
20 
21  namespace YieldParserHelper {
22 
23  // //////////////////////////////////////////////////////////////////
24  // Semantic actions
25  // //////////////////////////////////////////////////////////////////
26 
29  : _yieldRule (ioYieldRule) {
30  }
31 
32  // //////////////////////////////////////////////////////////////////
35  : ParserSemanticAction (ioYieldRule) {
36  }
37 
38  // //////////////////////////////////////////////////////////////////
39  void storeYieldId::operator() (unsigned int iYieldId,
40  boost::spirit::qi::unused_type,
41  boost::spirit::qi::unused_type) const {
42  _yieldRule.setYieldID (iYieldId);
43 
44  // DEBUG
45  //STDAIR_LOG_DEBUG ( "Yield Id: " << _yieldRule.getYieldID ());
46 
47  const stdair::AirlineCode_T lEmptyAirlineCode ("");
48  _yieldRule.setAirlineCode(lEmptyAirlineCode);
50  const stdair::ClassCode_T lEmptyClassCode ("");
51  _yieldRule.setClassCode(lEmptyClassCode);
54 
55  }
56 
57  // //////////////////////////////////////////////////////////////////
60  : ParserSemanticAction (ioYieldRule) {
61  }
62 
63  // //////////////////////////////////////////////////////////////////
64  void storeOrigin::operator() (std::vector<char> iChar,
65  boost::spirit::qi::unused_type,
66  boost::spirit::qi::unused_type) const {
67  const stdair::AirportCode_T lOrigin (iChar.begin(), iChar.end());
68  _yieldRule.setOrigin (lOrigin);
69  // DEBUG
70  //STDAIR_LOG_DEBUG ( "Origin: " << _yieldRule.getOrigin ());
71  }
72 
73  // //////////////////////////////////////////////////////////////////
76  : ParserSemanticAction (ioYieldRule) {
77  }
78 
79  // //////////////////////////////////////////////////////////////////
80  void storeDestination::operator() (std::vector<char> iChar,
81  boost::spirit::qi::unused_type,
82  boost::spirit::qi::unused_type) const {
83  const stdair::AirportCode_T lDestination (iChar.begin(), iChar.end());
84  _yieldRule.setDestination (lDestination);
85  // DEBUG
86  //STDAIR_LOG_DEBUG ( "Destination: " << _yieldRule.getDestination ());
87  }
88 
89  // //////////////////////////////////////////////////////////////////
92  : ParserSemanticAction (ioYieldRule) {
93  }
94 
95  // //////////////////////////////////////////////////////////////////
96  void storeTripType::operator() (std::vector<char> iChar,
97  boost::spirit::qi::unused_type,
98  boost::spirit::qi::unused_type) const {
99  const stdair::TripType_T lTripType (iChar.begin(), iChar.end());
100  if (lTripType == "OW" || lTripType == "RT") {
101  _yieldRule.setTripType (lTripType);
102  } else {
103  // ERROR
104  STDAIR_LOG_ERROR ("Invalid trip type " << lTripType);
105  }
106  // DEBUG
107  //STDAIR_LOG_DEBUG ("TripType: " << _yieldRule.getTripType ());
108  }
109 
110 
111  // //////////////////////////////////////////////////////////////////
114  : ParserSemanticAction (ioYieldRule) {
115  }
116 
117  // //////////////////////////////////////////////////////////////////
118  void storeDateRangeStart::operator() (boost::spirit::qi::unused_type,
119  boost::spirit::qi::unused_type,
120  boost::spirit::qi::unused_type) const {
121  const stdair::Date_T& lDateStart = _yieldRule.calculateDate ();
122  _yieldRule.setDateRangeStart (lDateStart);
123  // DEBUG
124  //STDAIR_LOG_DEBUG ("Date Range Start: "<< _yieldRule.getDateRangeStart ());
125  }
126 
127  // //////////////////////////////////////////////////////////////////
130  : ParserSemanticAction (ioYieldRule) {
131  }
132 
133  // //////////////////////////////////////////////////////////////////
134  void storeDateRangeEnd::operator() (boost::spirit::qi::unused_type,
135  boost::spirit::qi::unused_type,
136  boost::spirit::qi::unused_type) const {
137  const stdair::Date_T& lDateEnd = _yieldRule.calculateDate ();
138  // As a Boost date period (DatePeriod_T) defines the last day of
139  // the period to be end-date - one day, we have to add one day to that
140  // end date before.
141  const stdair::DateOffset_T oneDay (1);
142  const stdair::Date_T lBoostDateEnd = lDateEnd + oneDay;
143  _yieldRule.setDateRangeEnd (lBoostDateEnd);
144  // DEBUG
145  //STDAIR_LOG_DEBUG ("Date Range End: " << _yieldRule.getDateRangeEnd ());
146  }
147 
148  // //////////////////////////////////////////////////////////////////
151  : ParserSemanticAction (ioYieldRule) {
152  }
153 
154  // //////////////////////////////////////////////////////////////////
155  void storeStartRangeTime::operator() (boost::spirit::qi::unused_type,
156  boost::spirit::qi::unused_type,
157  boost::spirit::qi::unused_type) const {
158  const stdair::Duration_T& lTimeStart = _yieldRule.calculateTime ();
159  _yieldRule.setTimeRangeStart (lTimeStart);
160  // DEBUG
161  //STDAIR_LOG_DEBUG ("Time Range Start: " << _yieldRule.getTimeRangeStart ());
162  // Reset the number of seconds
164  }
165 
166  // //////////////////////////////////////////////////////////////////
169  : ParserSemanticAction (ioYieldRule) {
170  }
171 
172  // //////////////////////////////////////////////////////////////////
173  void storeEndRangeTime::operator() (boost::spirit::qi::unused_type,
174  boost::spirit::qi::unused_type,
175  boost::spirit::qi::unused_type) const {
176  const stdair::Duration_T& lTimeEnd = _yieldRule.calculateTime ();
177  _yieldRule.setTimeRangeEnd (lTimeEnd);
178  // DEBUG
179  //STDAIR_LOG_DEBUG ("Time Range End: " << _yieldRule.getTimeRangeEnd ());
180  // Reset the number of seconds
182  }
183 
184  // //////////////////////////////////////////////////////////////////
187  : ParserSemanticAction (ioYieldRule) {
188  }
189 
190  // //////////////////////////////////////////////////////////////////
191  void storePOS::operator() (std::vector<char> iChar,
192  boost::spirit::qi::unused_type,
193  boost::spirit::qi::unused_type) const {
194  const stdair::CityCode_T lPOS (iChar.begin(), iChar.end());
195  if (lPOS == _yieldRule.getOrigin() || lPOS == _yieldRule.getDestination() ) {
196  _yieldRule.setPOS (lPOS);
197  } else if (lPOS == "ROW") {
198  const stdair::CityCode_T lPOSROW ("ROW");
199  _yieldRule.setPOS (lPOSROW);
200  } else if (lPOS == stdair::DEFAULT_POS) {
201  _yieldRule.setPOS (stdair::DEFAULT_POS);
202  } else {
203  // ERROR
204  STDAIR_LOG_ERROR ("Invalid point of sale " << lPOS);
205  }
206  // DEBUG
207  //STDAIR_LOG_DEBUG ("POS: " << _yieldRule.getPOS ());
208  }
209 
210  // //////////////////////////////////////////////////////////////////
213  : ParserSemanticAction (ioYieldRule) {
214  }
215 
216  // //////////////////////////////////////////////////////////////////
218  boost::spirit::qi::unused_type,
219  boost::spirit::qi::unused_type) const {
220  std::ostringstream ostr;
221  ostr << iChar;
222  const std::string& cabinCodeStr = ostr.str();
223  const stdair::CabinCode_T lCabinCode (cabinCodeStr);
224  _yieldRule.setCabinCode (lCabinCode);
225 
226  // DEBUG
227  //STDAIR_LOG_DEBUG ("Cabin Code: " << _yieldRule.getCabinCode ());
228 
229  }
230 
231  // //////////////////////////////////////////////////////////////////
234  : ParserSemanticAction (ioYieldRule) {
235  }
236 
237  // //////////////////////////////////////////////////////////////////
238  void storeChannel::operator() (std::vector<char> iChar,
239  boost::spirit::qi::unused_type,
240  boost::spirit::qi::unused_type) const {
241  const stdair::ChannelLabel_T lChannel (iChar.begin(), iChar.end());
242  if (lChannel != "IN" && lChannel != "IF" && lChannel != "DN"
243  && lChannel != "DF" && lChannel != stdair::DEFAULT_CHANNEL) {
244  // ERROR
245  STDAIR_LOG_ERROR ("Invalid channel " << lChannel);
246  }
247  _yieldRule.setChannel (lChannel);
248  // DEBUG
249  //STDAIR_LOG_DEBUG ("Channel: " << _yieldRule.getChannel ());
250  }
251 
252  // //////////////////////////////////////////////////////////////////
255  : ParserSemanticAction (ioYieldRule) {
256  }
257 
258  // //////////////////////////////////////////////////////////////////
259  void storeYield::operator() (double iYield,
260  boost::spirit::qi::unused_type,
261  boost::spirit::qi::unused_type) const {
262  const stdair::YieldValue_T lYield= iYield;
263  _yieldRule.setYield (lYield);
264  // DEBUG
265  //STDAIR_LOG_DEBUG ("Yield: " << _yieldRule.getYield ());
266  }
267 
268  // //////////////////////////////////////////////////////////////////
271  : ParserSemanticAction (ioYieldRule) {
272  }
273 
274  // //////////////////////////////////////////////////////////////////
275  void storeAirlineCode::operator() (std::vector<char> iChar,
276  boost::spirit::qi::unused_type,
277  boost::spirit::qi::unused_type) const {
278 
279  const stdair::AirlineCode_T lAirlineCode (iChar.begin(), iChar.end());
280  // Update the airline code
281  _yieldRule.setAirlineCode (lAirlineCode);
282  // Insertion of this airline Code list in the whole AirlineCode name
283  _yieldRule.addAirlineCode (lAirlineCode);
284  // DEBUG
285  //STDAIR_LOG_DEBUG ( "Airline code: " << lAirlineCode);
286  }
287 
288  // //////////////////////////////////////////////////////////////////
291  : ParserSemanticAction (ioYieldRule) {
292  }
293 
294  // //////////////////////////////////////////////////////////////////
295  void storeClass::operator() (std::vector<char> iChar,
296  boost::spirit::qi::unused_type,
297  boost::spirit::qi::unused_type) const {
298  std::ostringstream ostr;
299  for (std::vector<char>::const_iterator lItVector = iChar.begin();
300  lItVector != iChar.end();
301  lItVector++) {
302  ostr << *lItVector;
303  }
304  const std::string& classCodeStr = ostr.str();
305  const stdair::ClassCode_T lClassCode (classCodeStr);
306  // Insertion of this class Code list in the whole classCode name
307  _yieldRule.addClassCode (lClassCode);
308  // DEBUG
309  //STDAIR_LOG_DEBUG ("Class Code: " << classCodeStr);
310  }
311 
312  // //////////////////////////////////////////////////////////////////
314  doEndYield (stdair::BomRoot& ioBomRoot,
315  YieldRuleStruct& ioYieldRule)
316  : ParserSemanticAction (ioYieldRule),
317  _bomRoot (ioBomRoot) {
318  }
319 
320  // //////////////////////////////////////////////////////////////////
321  void doEndYield::operator() (boost::spirit::qi::unused_type,
322  boost::spirit::qi::unused_type,
323  boost::spirit::qi::unused_type) const {
324  // DEBUG
325  // STDAIR_LOG_DEBUG ("Do End");
326  // Generation of the yield rule object.
327  YieldRuleGenerator::createAirportPair (_bomRoot, _yieldRule);
328  STDAIR_LOG_DEBUG (_yieldRule.describe());
329  }
330 
331  // ///////////////////////////////////////////////////////////////////
332  //
333  // Utility Parsers
334  //
335  // ///////////////////////////////////////////////////////////////////
337  namespace bsq = boost::spirit::qi;
338  namespace bsa = boost::spirit::ascii;
339 
341  stdair::int1_p_t int1_p;
342 
344  stdair::uint2_p_t uint2_p;
345 
347  stdair::uint4_p_t uint4_p;
348 
350  stdair::uint1_4_p_t uint1_4_p;
351 
353  stdair::hour_p_t hour_p;
354  stdair::minute_p_t minute_p;
355  stdair::second_p_t second_p;
356 
358  stdair::year_p_t year_p;
359  stdair::month_p_t month_p;
360  stdair::day_p_t day_p;
361 
363  //
364  // (Boost Spirit) Grammar Definition
365  //
367 
387  struct YieldRuleParser :
388  public boost::spirit::qi::grammar<stdair::iterator_t,
389  boost::spirit::ascii::space_type> {
390 
391  YieldRuleParser (stdair::BomRoot& ioBomRoot,
392  YieldRuleStruct& ioYieldRule) :
393  YieldRuleParser::base_type(start),
394  _bomRoot(ioBomRoot), _yieldRule(ioYieldRule) {
395 
396  start = *(comments | yield_rule);
397 
398  comments = (bsq::lexeme[bsq::repeat(2)[bsa::char_('/')]
399  >> +(bsa::char_ - bsq::eol)
400  >> bsq::eol]
401  | bsq::lexeme[bsa::char_('/') >>bsa::char_('*')
402  >> +(bsa::char_ - bsa::char_('*'))
403  >> bsa::char_('*') >> bsa::char_('/')]);
404 
406  >> ';' >> origin >> ';' >> destination
407  >> ';' >> tripType
408  >> ';' >> dateRangeStart >> ';' >> dateRangeEnd
409  >> ';' >> timeRangeStart >> ';' >> timeRangeEnd
410  >> ';' >> point_of_sale >> ';' >> cabinCode
411  >> ';' >> channel >> ';' >> yield
412  >> +( ';' >> segment )
414  ;
415 
417 
418  origin = bsq::repeat(3)[bsa::char_("A-Z")][storeOrigin(_yieldRule)];
419 
420  destination =
421  bsq::repeat(3)[bsa::char_("A-Z")][storeDestination(_yieldRule)];
422 
423  tripType =
424  bsq::repeat(2)[bsa::char_("A-Z")][storeTripType(_yieldRule)];
425 
427 
429 
430  date = bsq::lexeme
431  [year_p[boost::phoenix::ref(_yieldRule._itYear) = bsq::labels::_1]
432  >> '-'
433  >> month_p[boost::phoenix::ref(_yieldRule._itMonth) = bsq::labels::_1]
434  >> '-'
435  >> day_p[boost::phoenix::ref(_yieldRule._itDay) = bsq::labels::_1] ];
436 
438 
440 
441  time = bsq::lexeme
442  [hour_p[boost::phoenix::ref(_yieldRule._itHours) = bsq::labels::_1]
443  >> ':'
444  >> minute_p[boost::phoenix::ref(_yieldRule._itMinutes) = bsq::labels::_1]
445  >> - (':' >> second_p[boost::phoenix::ref(_yieldRule._itSeconds) = bsq::labels::_1]) ];
446 
447  point_of_sale = bsq::repeat(3)[bsa::char_("A-Z")][storePOS(_yieldRule)];
448 
449  cabinCode = bsa::char_("A-Z")[storeCabinCode(_yieldRule)];
450 
451  channel = bsq::repeat(2)[bsa::char_("A-Z")][storeChannel(_yieldRule)];
452 
453  yield = bsq::double_[storeYield(_yieldRule)];
454 
455  segment = bsq::repeat(2)[bsa::char_("A-Z")][storeAirlineCode(_yieldRule)]
456  >> ';'
457  >> bsq::repeat(1,bsq::inf)[bsa::char_("A-Z")][storeClass(_yieldRule)];
458 
459  yield_rule_end = bsa::char_(';');
460 
461  // BOOST_SPIRIT_DEBUG_NODE (YieldParser);
462  BOOST_SPIRIT_DEBUG_NODE (start);
463  BOOST_SPIRIT_DEBUG_NODE (comments);
464  BOOST_SPIRIT_DEBUG_NODE (yield_rule);
465  BOOST_SPIRIT_DEBUG_NODE (yield_id);
466  BOOST_SPIRIT_DEBUG_NODE (origin);
467  BOOST_SPIRIT_DEBUG_NODE (destination);
468  BOOST_SPIRIT_DEBUG_NODE (tripType);
469  BOOST_SPIRIT_DEBUG_NODE (dateRangeStart);
470  BOOST_SPIRIT_DEBUG_NODE (dateRangeEnd);
471  BOOST_SPIRIT_DEBUG_NODE (date);
472  BOOST_SPIRIT_DEBUG_NODE (timeRangeStart);
473  BOOST_SPIRIT_DEBUG_NODE (timeRangeEnd);
474  BOOST_SPIRIT_DEBUG_NODE (time);
475  BOOST_SPIRIT_DEBUG_NODE (point_of_sale);
476  BOOST_SPIRIT_DEBUG_NODE (cabinCode);
477  BOOST_SPIRIT_DEBUG_NODE (channel);
478  BOOST_SPIRIT_DEBUG_NODE (yield);
479  BOOST_SPIRIT_DEBUG_NODE (segment);
480  BOOST_SPIRIT_DEBUG_NODE (yield_rule_end);
481 
482  }
483 
484  // Instantiation of rules
485  boost::spirit::qi::rule<stdair::iterator_t,
486  boost::spirit::ascii::space_type>
491 
492  // Parser Context
493  stdair::BomRoot& _bomRoot;
495  };
496 
497  }
498 
499 
501  //
502  // Entry class for the file parser
503  //
505 
506  // //////////////////////////////////////////////////////////////////////
507  YieldFileParser::YieldFileParser (stdair::BomRoot& ioBomRoot,
508  const std::string& iFilename)
509  : _filename (iFilename), _bomRoot (ioBomRoot) {
510  init();
511  }
512 
513  // //////////////////////////////////////////////////////////////////////
514  void YieldFileParser::init() {
515 
516  // Check that the file exists and is readable
517  const bool doesExistAndIsReadable =
518  stdair::BasFileMgr::doesExistAndIsReadable (_filename);
519 
520  if (doesExistAndIsReadable == false) {
521  STDAIR_LOG_ERROR ("The yield schedule file " << _filename
522  << " does not exist or can not be read.");
523 
524  throw YieldInputFileNotFoundException ("The yield file " + _filename + " does not exist or can not be read");
525  }
526  }
527 
528  // //////////////////////////////////////////////////////////////////////
530 
531  STDAIR_LOG_DEBUG ("Parsing yield input file: " << _filename);
532 
533  // File to be parsed
534  std::ifstream fileToBeParsed (_filename.c_str(), std::ios_base::in);
535 
536  // Check the filename exists and can be open
537  if (fileToBeParsed.is_open() == false) {
538  STDAIR_LOG_ERROR ("The yield store file " << _filename
539  << " can not be open."
540  << std::endl);
541 
542  throw YieldInputFileNotFoundException ("The file " + _filename
543  + " does not exist or can not be read");
544  }
545 
546  // Create an input iterator
547  stdair::base_iterator_t inputBegin (fileToBeParsed);
548 
549  // Convert input iterator to an iterator usable by spirit parser
550  stdair::iterator_t
551  start (boost::spirit::make_default_multi_pass (inputBegin));
552  stdair::iterator_t end;
553 
554  // Initialise the parser (grammar) with the helper/staging structure.
555  YieldParserHelper::YieldRuleParser lYParser(_bomRoot, _yieldRule);
556 
557  // Launch the parsing of the file and, thanks to the doEndYield
558  // call-back structure, the building of the whole BomRoot BOM
559  const bool hasParsingBeenSuccesful =
560  boost::spirit::qi::phrase_parse (start, end, lYParser,
561  boost::spirit::ascii::space);
562 
563  if (hasParsingBeenSuccesful == false) {
564  // TODO: decide whether to throw an exceqption
565  STDAIR_LOG_ERROR ("Parsing of yield input file: " << _filename
566  << " failed");
567  throw YieldFileParsingFailedException ("Parsing of yield input file: "
568  + _filename + " failed");
569  }
570  if (start != end) {
571  // TODO: decide whether to throw an exception
572  STDAIR_LOG_ERROR ("Parsing of yield input file: " << _filename
573  << " failed");
574  throw YieldFileParsingFailedException ("Parsing of yield input file: "
575  + _filename + " failed");
576  }
577  if (hasParsingBeenSuccesful == true && start == end) {
578  STDAIR_LOG_DEBUG ("Parsing of yield input file: " << _filename
579  << " succeeded");
580  }
581 
582  }
583 
584 }