OpenTREP Logo  0.08.02
C++ Open Travel Request Parsing Library
Loading...
Searching...
No Matches
opentrep-dbmgr.cpp
Go to the documentation of this file.
1// STL
2#include <cassert>
3#include <iostream>
4#include <sstream>
5#include <fstream>
6#include <vector>
7#include <string>
8// Boost (Extended STL)
9#include <boost/date_time/posix_time/posix_time.hpp>
10#include <boost/date_time/gregorian/gregorian.hpp>
11#include <boost/regex.hpp>
12#include <boost/tokenizer.hpp>
13#include <boost/algorithm/string.hpp>
14#include <boost/program_options.hpp>
15// GNU Readline Wrapper
17// OpenTREP
20#include <opentrep/Location.hpp>
24#include <opentrep/config/opentrep-paths.hpp>
26
27
28// //////// Type definitions ///////
29typedef std::vector<std::string> WordList_T;
30
31
32// //////// Constants //////
36const std::string K_OPENTREP_DEFAULT_LOG_FILENAME ("opentrep-dbmgr.log");
37
38
39// ///////// Parsing of Options & Configuration /////////
42
47typedef std::vector<std::string> TokenList_T;
48
80
81// ///////// Parsing of Options & Configuration /////////
82// A helper function to simplify the main part.
83template<class T> std::ostream& operator<< (std::ostream& os,
84 const std::vector<T>& v) {
85 std::copy (v.begin(), v.end(), std::ostream_iterator<T> (std::cout, " "));
86 return os;
87}
88
92int readConfiguration (int argc, char* argv[],
93 std::string& ioPORFilepath,
94 std::string& ioXapianDBFilepath,
95 std::string& ioSQLDBTypeString,
96 std::string& ioSQLDBConnectionString,
97 unsigned short& ioDeploymentNumber,
98 bool& ioIncludeNonIATAPOR,
99 bool& ioIndexPORInXapian,
100 bool& ioAddPORInDB,
101 std::string& ioLogFilename,
102 std::string& ioCommand) {
103
104 // Declare a group of options that will be allowed only on command line
105 boost::program_options::options_description generic ("Generic options");
106 generic.add_options()
107 ("prefix", "print installation prefix")
108 ("version,v", "print version string")
109 ("help,h", "produce help message");
110
111 // Declare a group of options that will be allowed both on command
112 // line and in config file
113 boost::program_options::options_description config ("Configuration");
114 config.add_options()
115 ("porfile,p",
116 boost::program_options::value< std::string >(&ioPORFilepath)->default_value(OPENTREP::DEFAULT_OPENTREP_POR_FILEPATH),
117 "POR file-path (e.g., ori_por_public.csv)")
118 ("xapiandb,d",
119 boost::program_options::value< std::string >(&ioXapianDBFilepath)->default_value(OPENTREP::DEFAULT_OPENTREP_XAPIAN_DB_FILEPATH),
120 "Xapian database filepath (e.g., /tmp/opentrep/xapian_traveldb)")
121 ("sqldbtype,t",
122 boost::program_options::value< std::string >(&ioSQLDBTypeString)->default_value(OPENTREP::DEFAULT_OPENTREP_SQL_DB_TYPE),
123 "SQL database type (e.g., nodb for no SQL database, sqlite for SQLite, mysql for MariaDB/MySQL, pg for PostgreSQL)")
124 ("sqldbconx,s",
125 boost::program_options::value< std::string >(&ioSQLDBConnectionString),
126 "SQL database connection string (e.g., ~/tmp/opentrep/sqlite_travel.db for SQLite, \"db=trep_trep user=trep password=trep\" for MariaDB/MySQL or PostgreSQL)")
127 ("deploymentnb,m",
128 boost::program_options::value<unsigned short>(&ioDeploymentNumber)->default_value(OPENTREP::DEFAULT_OPENTREP_DEPLOYMENT_NUMBER),
129 "Deployment number (from to N, where N=1 normally)")
130 ("noniata,n",
131 boost::program_options::value<bool>(&ioIncludeNonIATAPOR)->default_value(OPENTREP::DEFAULT_OPENTREP_INCLUDE_NONIATA_POR),
132 "Whether or not to include POR not referenced by IATA (0 = only IATA-referenced POR, 1 = all POR are included)")
133 ("xapianindex,x",
134 boost::program_options::value<bool>(&ioIndexPORInXapian)->default_value(OPENTREP::DEFAULT_OPENTREP_INDEX_IN_XAPIAN),
135 "Whether or not to index the POR in Xapian (0 = do not touch the Xapian index, 1 = re-index all the POR in Xapian)")
136 ("dbadd,a",
137 boost::program_options::value<bool>(&ioAddPORInDB)->default_value(OPENTREP::DEFAULT_OPENTREP_ADD_IN_DB),
138 "Whether or not to add and index the POR in the SQL-based database (0 = do not touch the SQL-based database, 1 = add and re-index all the POR in the SQL-based database)")
139 ("log,l",
140 boost::program_options::value< std::string >(&ioLogFilename)->default_value(K_OPENTREP_DEFAULT_LOG_FILENAME),
141 "Filepath for the logs")
142 ("command,c",
143 boost::program_options::value< std::string >(&ioCommand)->default_value(""),
144 "Execute the given semicolon-separated dbmgr command(s) (e.g., \"list_nb ; list_by_iata nce\") in non-interactive mode, and then exit")
145 ;
146
147 // Hidden options, will be allowed both on command line and
148 // in config file, but will not be shown to the user.
149 boost::program_options::options_description hidden ("Hidden options");
150 hidden.add_options()
151 ("copyright",
152 boost::program_options::value< std::vector<std::string> >(),
153 "Show the copyright (license)");
154
155 boost::program_options::options_description cmdline_options;
156 cmdline_options.add(generic).add(config).add(hidden);
157
158 boost::program_options::options_description config_file_options;
159 config_file_options.add(config).add(hidden);
160
161 boost::program_options::options_description visible ("Allowed options");
162 visible.add(generic).add(config);
163
164 boost::program_options::positional_options_description p;
165 p.add ("copyright", -1);
166
167 boost::program_options::variables_map vm;
168 boost::program_options::
169 store (boost::program_options::command_line_parser (argc, argv).
170 options (cmdline_options).positional(p).run(), vm);
171
172 std::ifstream ifs ("opentrep-dbmgr.cfg");
173 boost::program_options::store (parse_config_file (ifs, config_file_options),
174 vm);
175 boost::program_options::notify (vm);
176
177 if (vm.count ("help")) {
178 std::cout << visible << std::endl;
180 }
181
182 if (vm.count ("version")) {
183 std::cout << PACKAGE_NAME << ", version " << PACKAGE_VERSION << std::endl;
185 }
186
187 if (vm.count ("prefix")) {
188 std::cout << "Installation prefix: " << PREFIXDIR << std::endl;
190 }
191
192 if (vm.count ("porfile")) {
193 ioPORFilepath = vm["porfile"].as< std::string >();
194 }
195
196 if (vm.count ("deploymentnb")) {
197 ioDeploymentNumber = vm["deploymentnb"].as< unsigned short >();
198 std::cout << "Deployment number " << ioDeploymentNumber << std::endl;
199 }
200
201 if (vm.count ("xapiandb")) {
202 ioXapianDBFilepath = vm["xapiandb"].as< std::string >();
203 std::cout << "Xapian index/database filepath is: " << ioXapianDBFilepath
204 << ioDeploymentNumber << std::endl;
205 }
206
207 // Parse the SQL database type, if any is given
208 if (vm.count ("sqldbtype")) {
209 ioSQLDBTypeString = vm["sqldbtype"].as< std::string >();
210 std::cout << "SQL database type is: " << ioSQLDBTypeString
211 << std::endl;
212 }
213
225 const OPENTREP::DBType lDBType (ioSQLDBTypeString);
226 if (lDBType == OPENTREP::DBType::NODB) {
227 ioAddPORInDB = false;
228 ioSQLDBConnectionString = "";
229
230 } else if (lDBType == OPENTREP::DBType::SQLITE3) {
231 ioAddPORInDB = true;
232 ioSQLDBConnectionString = OPENTREP::DEFAULT_OPENTREP_SQLITE_DB_FILEPATH;
233
234 } else if (lDBType == OPENTREP::DBType::PG) {
235 ioAddPORInDB = true;
236 ioSQLDBConnectionString = OPENTREP::DEFAULT_OPENTREP_PG_CONN_STRING;
237
238 } else if (lDBType == OPENTREP::DBType::MYSQL) {
239 ioAddPORInDB = true;
240 ioSQLDBConnectionString = OPENTREP::DEFAULT_OPENTREP_MYSQL_CONN_STRING;
241 }
242
243 // Set the SQL database connection string, if any is given
244 if (vm.count ("sqldbconx")) {
245 ioSQLDBConnectionString = vm["sqldbconx"].as< std::string >();
246 }
247
248 // Reporting of the SQL database connection string
249 if (lDBType == OPENTREP::DBType::SQLITE3
250 || lDBType == OPENTREP::DBType::MYSQL
251 || lDBType == OPENTREP::DBType::PG) {
252 const std::string& lSQLDBConnString =
254 ioSQLDBConnectionString,
255 ioDeploymentNumber);
256 //
257 std::cout << "SQL database connection string is: " << lSQLDBConnString
258 << std::endl;
259 }
260
261 std::cout << "Are non-IATA-referenced POR included? "
262 << ioIncludeNonIATAPOR << std::endl;
263
264 std::cout << "Index the POR in Xapian? "
265 << ioIndexPORInXapian << std::endl;
266
267 std::cout << "Add and re-index the POR in the SQL-based database? "
268 << ioAddPORInDB << std::endl;
269
270 if (vm.count ("log")) {
271 ioLogFilename = vm["log"].as< std::string >();
272 }
273
274 if (vm.count ("command")) {
275 ioCommand = vm["command"].as< std::string >();
276 }
277
278 // Information
279 std::cout << "Type the 'info' command to get a few details (e.g., file-path)"
280 << std::endl;
281
282 return 0;
283}
284
285// //////////////////////////////////////////////////////////////////
286void initReadline (swift::SReadline& ioInputReader) {
287
288 // Prepare the list of my own completers
289 std::vector<std::string> Completers;
290
291 // The following is supported:
292 // - "identifiers"
293 // - special identifier %file - means to perform a file name completion
294 Completers.push_back ("help");
295 Completers.push_back ("info");
296 Completers.push_back ("tutorial");
297 Completers.push_back ("create_user");
298 Completers.push_back ("reset_connection_string %connection_string");
299 Completers.push_back ("create_tables");
300 Completers.push_back ("create_indexes");
301 Completers.push_back ("toggle_deployment_number");
302 Completers.push_back ("toggle_noniata_indexing_flag");
303 Completers.push_back ("toggle_xapian_idexing_flag");
304 Completers.push_back ("toggle_sqldb_inserting_flag");
305 Completers.push_back ("fill_from_por_file");
306 Completers.push_back ("list_by_iata %iata_code");
307 Completers.push_back ("list_by_icao %icao_code");
308 Completers.push_back ("list_by_faa %faa_code");
309 Completers.push_back ("list_by_unlocode %unlocode_code");
310 Completers.push_back ("list_by_uiccode %uic_code");
311 Completers.push_back ("list_by_geonameid %geoname_id");
312 Completers.push_back ("list_nb");
313 Completers.push_back ("list_all");
314 Completers.push_back ("list_cont");
315 Completers.push_back ("quit");
316
317 // Now register the completers.
318 // Actually it is possible to re-register another set at any time
319 ioInputReader.RegisterCompletions (Completers);
320}
321
322// //////////////////////////////////////////////////////////////////
325
326 // Interpret the user input
327 if (ioTokenList.empty() == false) {
328 TokenList_T::iterator itTok = ioTokenList.begin();
329 std::string lCommand (*itTok);
330 boost::algorithm::to_lower (lCommand);
331 if (lCommand == "help") {
332 oCommandType = Command_T::HELP;
333
334 } else if (lCommand == "info") {
335 oCommandType = Command_T::INFO;
336
337 } else if (lCommand == "tutorial") {
338 oCommandType = Command_T::TUTORIAL;
339
340 } else if (lCommand == "create_user") {
341 oCommandType = Command_T::CREATE_USER;
342
343 } else if (lCommand == "reset_connection_string") {
345
346 } else if (lCommand == "create_tables") {
347 oCommandType = Command_T::CREATE_TABLES;
348
349 } else if (lCommand == "create_indexes") {
350 oCommandType = Command_T::CREATE_INDEXES;
351
352 } else if (lCommand == "toggle_deployment_number") {
354
355 } else if (lCommand == "toggle_noniata_indexing_flag") {
357
358 } else if (lCommand == "toggle_xapian_idexing_flag") {
360
361 } else if (lCommand == "toggle_sqldb_inserting_flag") {
363
364 } else if (lCommand == "fill_from_por_file") {
365 oCommandType = Command_T::FILL_FROM_POR_FILE;
366
367 } else if (lCommand == "list_by_iata") {
368 oCommandType = Command_T::LIST_BY_IATA;
369
370 } else if (lCommand == "list_by_icao") {
371 oCommandType = Command_T::LIST_BY_ICAO;
372
373 } else if (lCommand == "list_by_faa") {
374 oCommandType = Command_T::LIST_BY_FAA;
375
376 } else if (lCommand == "list_by_unlocode") {
377 oCommandType = Command_T::LIST_BY_UNLOCODE;
378
379 } else if (lCommand == "list_by_uiccode") {
380 oCommandType = Command_T::LIST_BY_UICCODE;
381
382 } else if (lCommand == "list_by_geonameid") {
383 oCommandType = Command_T::LIST_BY_GEONAMEID;
384
385 } else if (lCommand == "list_nb") {
386 oCommandType = Command_T::LIST_NB;
387
388 } else if (lCommand == "list_all") {
389 oCommandType = Command_T::LIST_ALL;
390
391 } else if (lCommand == "list_cont") {
392 oCommandType = Command_T::LIST_CONT;
393
394 } else if (lCommand == "quit") {
395 oCommandType = Command_T::QUIT;
396 }
397
398 // Remove the first token (the command), as the corresponding information
399 // has been extracted in the form of the returned command type enumeration
400 ioTokenList.erase (itTok);
401
402 } else {
403 oCommandType = Command_T::NOP;
404 }
405
406 return oCommandType;
407}
408
409// //////////////////////////////////////////////////////////////////
410void parseConnectionString (const TokenList_T& iTokenList,
411 std::string& ioConnectionString) {
412 // Interpret the user input
413 if (iTokenList.empty() == false) {
414
415 // Read the database connection string
416 TokenList_T::const_iterator itTok = iTokenList.begin();
417 if (itTok->empty() == false) {
418 ioConnectionString = *itTok;
419 }
420 }
421}
422
423// //////////////////////////////////////////////////////////////////
424void parsePlaceKey (const TokenList_T& iTokenList, std::string& ioPlaceKey) {
425 // Interpret the user input
426 if (iTokenList.empty() == false) {
427
428 // Read the IATA code
429 TokenList_T::const_iterator itTok = iTokenList.begin();
430 if (itTok->empty() == false) {
431 ioPlaceKey = *itTok;
432 }
433 }
434}
435
436// /////////////////////////////////////////////////////////
437std::string toString (const TokenList_T& iTokenList) {
438 std::ostringstream oStr;
439
440 // Re-create the string with all the tokens, trimmed by read-line
441 unsigned short idx = 0;
442 for (TokenList_T::const_iterator itTok = iTokenList.begin();
443 itTok != iTokenList.end(); ++itTok, ++idx) {
444 if (idx != 0) {
445 oStr << " ";
446 }
447 oStr << *itTok;
448 }
449
450 return oStr.str();
451}
452
453// /////////////////////////////////////////////////////////
455 const std::string& iRegularExpression) {
456 TokenList_T oTokenList;
457
458 // Re-create the string with all the tokens (which had been trimmed
459 // by read-line)
460 const std::string lFullLine = toString (iTokenList);
461
462 // See the caller for the regular expression
463 boost::regex expression (iRegularExpression);
464
465 std::string::const_iterator start = lFullLine.begin();
466 std::string::const_iterator end = lFullLine.end();
467
468 boost::match_results<std::string::const_iterator> what;
469 boost::match_flag_type flags = boost::match_default | boost::format_sed;
470 regex_search (start, end, what, expression, flags);
471
472 // Put the matched strings in the list of tokens to be returned back
473 // to the caller
474 const unsigned short lMatchSetSize = what.size();
475 for (unsigned short matchIdx = 1; matchIdx != lMatchSetSize; ++matchIdx) {
476 const std::string lMatchedString (std::string (what[matchIdx].first,
477 what[matchIdx].second));
478 //if (lMatchedString.empty() == false) {
479 oTokenList.push_back (lMatchedString);
480 //}
481 }
482
483 // DEBUG
484 // std::cout << "After (token list): " << oTokenList << std::endl;
485
486 return oTokenList;
487}
488
489// /////////////////////////////////////////////////////////
496 const std::string lRegEx ("^([[:alpha:]]{3})$");
497
498 //
499 const TokenList_T& oTokenList = extractTokenList (iTokenList, lRegEx);
500 return oTokenList;
501}
502
503// /////////////////////////////////////////////////////////
510 const std::string lRegEx ("^(([[:alpha:]]|[[:digit:]]){4})$");
511
512 //
513 const TokenList_T& oTokenList = extractTokenList (iTokenList, lRegEx);
514 return oTokenList;
515}
516
517// /////////////////////////////////////////////////////////
524 const std::string lRegEx ("^(([[:alpha:]]|[[:digit:]]){3,4})$");
525
526 //
527 const TokenList_T& oTokenList = extractTokenList (iTokenList, lRegEx);
528 return oTokenList;
529}
530
531// /////////////////////////////////////////////////////////
538 const std::string lRegEx ("^(([[:alpha:]]|[[:digit:]]){5})$");
539
540 //
541 const TokenList_T& oTokenList = extractTokenList (iTokenList, lRegEx);
542 return oTokenList;
543}
544
545// /////////////////////////////////////////////////////////
552 const std::string lRegEx ("^([[:digit:]]{1,11})$");
553
554 //
555 const TokenList_T& oTokenList = extractTokenList (iTokenList, lRegEx);
556 return oTokenList;
557}
558
559// /////////////////////////////////////////////////////////
566 const std::string lRegEx ("^([[:digit:]]{1,11})$");
567
568 //
569 const TokenList_T& oTokenList = extractTokenList (iTokenList, lRegEx);
570 return oTokenList;
571}
572
573
574// //////////////////////////////////////////////////////////////////
585 const std::string& iCommandName) {
586 if (iDBType == OPENTREP::DBType::NODB) {
587 std::cout << "The '" << iCommandName << "' command requires a SQL "
588 << "database (SQLite3, MySQL/MariaDB or PostgreSQL), but no "
589 << "SQL database has been configured (the SQL database type "
590 << "is currently set to '" << iDBType.describe() << "'). "
591 << "Restart the application with the '--sqldbtype' (-t) "
592 << "option set to 'sqlite', 'mysql' or 'pg', or type 'info' "
593 << "to check the current configuration." << std::endl;
594 return false;
595 }
596 return true;
597}
598
599// //////////////////////////////////////////////////////////////////
608std::vector<std::string> splitCommandLine (const std::string& iCommandLine) {
609 std::vector<std::string> oCommandList;
610
611 boost::char_separator<char> lSeparator (";");
612 boost::tokenizer<boost::char_separator<char> > lTokenizer (iCommandLine,
613 lSeparator);
614 for (boost::tokenizer<boost::char_separator<char> >::const_iterator itTok =
615 lTokenizer.begin(); itTok != lTokenizer.end(); ++itTok) {
616 std::string lSingleCommand (*itTok);
617 boost::algorithm::trim (lSingleCommand);
618 if (lSingleCommand.empty() == false) {
619 oCommandList.push_back (lSingleCommand);
620 }
621 }
622
623 return oCommandList;
624}
625
626// //////////////////////////////////////////////////////////////////
635processUserCommand (const std::string& iUserInput, TokenList_T& ioTokenList,
636 OPENTREP::OPENTREP_Service& ioOpentrepService,
637 const OPENTREP::DBType& iDBType,
638 const std::string& iLogFilename,
639 const std::string& iPORFilepathStr,
640 OPENTREP::DeploymentNumber_T& ioDeploymentNumber,
641 OPENTREP::shouldIndexNonIATAPOR_T& ioIncludeNonIATAPOR,
642 OPENTREP::shouldIndexPORInXapian_T& ioShouldIndexPORInXapian,
643 OPENTREP::shouldAddPORInSQLDB_T& ioShouldAddPORInSQLDB) {
644 // Interpret the user input
645 Command_T::Type_T lCommandType = extractCommand (ioTokenList);
646
647 switch (lCommandType) {
648
649 // ////////////////////////////// Help ////////////////////////
650 case Command_T::HELP: {
651 std::cout << std::endl;
652 std::cout << "Commands: " << std::endl;
653 std::cout << " CTRL-L (Control and L keys)" << "\t" << "Clean the screen"
654 << std::endl;
655 std::cout << " help" << "\t\t\t\t" << "Display this help" << std::endl;
656 std::cout << " info" << "\t\t\t\t"
657 << "Display details for the current session "
658 << "(e.g., file-paths for the log file, SQL database)"
659 << std::endl;
660 std::cout << " tutorial" << "\t\t\t" << "Display examples" << std::endl;
661 std::cout << " quit" << "\t\t\t\t" << "Quit the application" << std::endl;
662 std::cout << " create_user" << "\t\t\t"
663 << "On SQL database, create the 'trep' user and the 'trep_trep' "
664 << "database. SQL database administrative rights are required."
665 << std::endl;
666 std::cout << " reset_connection_string" << "\t"
667 << "Reset/update the connection string to a MySQL or PostgreSQL database."
668 << " The connection string must be given"
669 << std::endl;
670 std::cout << " create_tables" << "\t\t\t"
671 << "Create/reset the SQL database (eg, SQLite3, PostgreSQL, MySQL) tables"
672 << std::endl;
673 std::cout << " create_indexes" << "\t\t\t"
674 << "Create/reset the SQL database (eg, SQLite3, PostgreSQL, MySQL) indices"
675 << std::endl;
676 std::cout << " toggle_deployment_number" << "\t"
677 << "Toggle the deployment number/version. "
678 << "To see the deployment version/number, type 'info'"
679 << std::endl;
680 std::cout << " toggle_noniata_indexing_flag" << "\t"
681 << "Toggle the flag for the indexing (or not) of the non-IATA referenced POR."
682 << " To see the flag, type 'info'"
683 << std::endl;
684 std::cout << " toggle_xapian_idexing_flag" << "\t"
685 << "Toggle the flag for the Xapian indexing (or not) of the POR."
686 << " To see the flag, type 'info'"
687 << std::endl;
688 std::cout << " toggle_sqldb_inserting_flag" << "\t"
689 << "Toggle the flag for inserting (or not) the POR into the SQL database."
690 << " To see the flag, type 'info'"
691 << std::endl;
692 std::cout << " fill_from_por_file" << "\t\t"
693 << "Parse the file of POR and fill-in the SQL database optd_por table."
694 << std::endl << "\t\t\t\t"
695 << "That command (re-)creates both the Xapian index and the SQL tables (as well as the indices), if needed."
696 << std::endl << "\t\t\t\t"
697 << "Note that, as that command takes minutes, the connection to the SQL database may be lost and the program will exit abnormally."
698 << std::endl << "\t\t\t\t"
699 << "In that latter case, just re-execute the program and check how far the indexation went by executing the following command."
700 << std::endl;
701 std::cout << " list_nb" << "\t\t\t"
702 << "Display the number of the entries of the database."
703 << std::endl;
704 std::cout << " list_all" << "\t\t\t"
705 << "List all the entries of the database, page by page."
706 << "Type the 'list_cont' command for a page down" << std::endl;
707 std::cout << " list_by_iata" << "\t\t\t"
708 << "List all the entries for a given IATA code"
709 << std::endl;
710 std::cout << " list_by_icao" << "\t\t\t"
711 << "List all the entries for a given ICAO code"
712 << std::endl;
713 std::cout << " list_by_faa" << "\t\t\t"
714 << "List all the entries for a given FAA code"
715 << std::endl;
716 std::cout << " list_by_unlocode" << "\t\t\t"
717 << "List all the entries for a given UN/LOCODE code"
718 << std::endl;
719 std::cout << " list_by_uiccode" << "\t\t\t"
720 << "List all the entries for a given UIC code"
721 << std::endl;
722 std::cout << " list_by_geonameid" << "\t\t"
723 << "List all the entries for a given Geoname ID"
724 << std::endl;
725 std::cout << std::endl;
726 break;
727 }
728
729 // ////////////////////////////// Information ////////////////////////
730 case Command_T::INFO: {
732 ioOpentrepService.getFilePaths();
734 lFPSet.second;
735 const OPENTREP::TravelDBFilePath_T& lXapianDBFP = lDBFPPair.first;
736 const OPENTREP::SQLDBConnectionString_T& lSQLConnStr = lDBFPPair.second;
737 std::cout << std::endl;
738 std::cout << "Log file-path: " << "\t\t\t\t\t" << iLogFilename
739 << std::endl;
740 std::cout << "POR file-path: " << "\t\t\t\t\t" << iPORFilepathStr
741 << std::endl;
742 std::cout << "Xapian index/database file-path: " << "\t\t"
743 << lXapianDBFP << std::endl;
744 std::cout << "SQL database type: " << "\t\t\t\t" << iDBType.describe()
745 << std::endl;
746 std::cout << "SQL database connection string: " << "\t\t" << lSQLConnStr
747 << std::endl;
748 std::cout << "Deployment number/version: " << "\t\t\t"
749 << ioDeploymentNumber << "/"
751 << std::endl;
752 std::cout << "Whether to index NON-IATA-referenced POR: " << "\t"
753 << ioIncludeNonIATAPOR << std::endl;
754 std::cout << "Whether to index the POR in Xapian: " << "\t\t"
755 << ioShouldIndexPORInXapian << std::endl;
756 std::cout << "Whether to insert the POR in the SQL DB: " << "\t"
757 << ioShouldAddPORInSQLDB << std::endl;
758 std::cout << std::endl;
759 break;
760 }
761
762 // /////////////////////////// Help with Examples //////////////////////
763 case Command_T::TUTORIAL: {
764 std::cout << std::endl;
765 std::cout << "Typical succession of commands" << std::endl;
766 std::cout << " -------- " << std::endl;
767 std::cout << "Check with the 'info' command and adjust the various flags:"
768 << std::endl;
769 std::cout << " toggle_deployment_number" << std::endl;
770 std::cout << " toggle_noniata_indexing_flag" << std::endl;
771 std::cout << " toggle_xapian_idexing_flag" << std::endl;
772 std::cout << " toggle_sqldb_inserting_flag" << std::endl;
773 std::cout << std::endl;
774 std::cout << " -------- " << std::endl;
775 std::cout << "Re-indexing of the POR data file:" << std::endl;
776 std::cout << " fill_from_por_file" << std::endl;
777 std::cout << std::endl;
778 std::cout << " -------- " << std::endl;
779 std::cout << "Check the content of the SQL database:" << std::endl;
780 std::cout << " list_nb" << std::endl;
781 std::cout << " list_by_iata nce" << std::endl;
782 std::cout << " list_by_icao lfmn" << std::endl;
783 std::cout << " list_by_faa jfk" << std::endl;
784 std::cout << " list_by_unlocode deham" << std::endl;
785 std::cout << " list_by_uiccode 87775007" << std::endl;
786 std::cout << " list_by_geonameid 6299418" << std::endl;
787 std::cout << std::endl;
788 std::cout << " -------- " << std::endl;
789 std::cout << "Management of the database user and database:" << std::endl;
790 std::cout << "* For PostgreSQL:" << std::endl;
791 std::cout <<" reset_connection_string db=postgres user=$USER password=<passwd>"
792 << std::endl;
793 std::cout << "* For MySQL:" << std::endl;
794 std::cout <<" reset_connection_string db=mysql user=root password=<passwd>"
795 << std::endl;
796 std::cout << " create_user" << std::endl;
797 std::cout <<" reset_connection_string db=trep_trep user=trep password=trep"
798 << std::endl;
799 std::cout << " create_tables" << std::endl;
800 std::cout << " create_indexes" << std::endl;
801 std::cout << std::endl;
802 break;
803 }
804
805 // ////////////////////////////// Quit ////////////////////////
806 case Command_T::QUIT: {
807 break;
808 }
809
810 // ////////////////////////////// List Number /////////////////////////
811 case Command_T::LIST_NB: {
812 // Call the underlying OpenTREP service
813 if (iDBType == OPENTREP::DBType::NODB) {
814 const OPENTREP::NbOfDBEntries_T nbOfEntries =
815 ioOpentrepService.getIndexSize();
816
817 // Reporting
818 std::cout << nbOfEntries
819 << " POR (points of reference) have been found in the Xapian "
820 << "index. Type 'info' to know where that Xapian index is "
821 "located." << std::endl;
822
823 } else {
824 const OPENTREP::NbOfDBEntries_T nbOfEntries =
825 ioOpentrepService.getNbOfPORFromDB();
826
827 // Reporting
828 std::cout << nbOfEntries
829 << " POR (points of reference) have been found in the "
830 << iDBType.describe() << " database" << std::endl;
831 }
832
833 break;
834 }
835
836 // ////////////////////////////// List All /////////////////////////
837 case Command_T::LIST_ALL: {
838 if (requireSQLDatabase (iDBType, "list_all") == false) {
839 break;
840 }
841
842 // For now, just hard code a single IATA code.
843 // TODO: implement the page down process, so that the full list
844 // can be retrieved and browsed.
845 const std::string lIataCodeStr ("NCE");
846
847 // Call the underlying OpenTREP service
848 const OPENTREP::IATACode_T lIataCode (lIataCodeStr);
849 OPENTREP::LocationList_T lLocationList;
850 const OPENTREP::NbOfMatches_T nbOfMatches =
851 ioOpentrepService.listByIataCode (lIataCode, lLocationList);
852
853 //
854 std::cout << nbOfMatches << " (geographical) location(s) have been found "
855 << "matching the IATA code ('" << lIataCodeStr << "')."
856 << std::endl;
857
858 if (nbOfMatches != 0) {
860 for (OPENTREP::LocationList_T::const_iterator itLocation =
861 lLocationList.begin();
862 itLocation != lLocationList.end(); ++itLocation, ++idx) {
863 const OPENTREP::Location& lLocation = *itLocation;
864 std::cout << " [" << idx << "]: " << lLocation.toString() << std::endl;
865 }
866
867 } else {
868 std::cout << "List of unmatched words:" << std::endl;
869 std::cout << " [" << 1 << "]: " << lIataCodeStr << std::endl;
870 }
871
872 break;
873 }
874
875 // ////////////////////////// List by IATA code ////////////////////////
877 if (requireSQLDatabase (iDBType, "list_by_iata") == false) {
878 break;
879 }
880
881 //
882 TokenList_T lTokenList = extractTokenListForIataCode(ioTokenList);
883
884 // Parse the parameters given by the user, giving default values
885 // in case the user does not specify some (or all) of them
886 std::string lIataCodeStr ("nce");
887 parsePlaceKey (lTokenList, lIataCodeStr);
888
889 // Call the underlying OpenTREP service
890 const OPENTREP::IATACode_T lIataCode (lIataCodeStr);
891 OPENTREP::LocationList_T lLocationList;
892 const OPENTREP::NbOfMatches_T nbOfMatches =
893 ioOpentrepService.listByIataCode (lIataCode, lLocationList);
894
895 //
896 std::cout << nbOfMatches << " (geographical) location(s) have been found "
897 << "matching the IATA code ('" << lIataCodeStr << "')."
898 << std::endl;
899
900 if (nbOfMatches != 0) {
902 for (OPENTREP::LocationList_T::const_iterator itLocation =
903 lLocationList.begin();
904 itLocation != lLocationList.end(); ++itLocation, ++idx) {
905 const OPENTREP::Location& lLocation = *itLocation;
906 std::cout << " [" << idx << "]: " << lLocation << std::endl;
907 }
908
909 } else {
910 std::cout << "List of unmatched words:" << std::endl;
911 std::cout << " [" << 1 << "]: " << lIataCodeStr << std::endl;
912 }
913
914 break;
915 }
916
917 // ////////////////////////// List by ICAO code ////////////////////////
919 if (requireSQLDatabase (iDBType, "list_by_icao") == false) {
920 break;
921 }
922
923 //
924 TokenList_T lTokenList = extractTokenListForIcaoCode(ioTokenList);
925
926 // Parse the parameters given by the user, giving default values
927 // in case the user does not specify some (or all) of them
928 std::string lIcaoCodeStr ("lfmn");
929 parsePlaceKey (lTokenList, lIcaoCodeStr);
930
931 // Call the underlying OpenTREP service
932 const OPENTREP::ICAOCode_T lIcaoCode (lIcaoCodeStr);
933 OPENTREP::LocationList_T lLocationList;
934 const OPENTREP::NbOfMatches_T nbOfMatches =
935 ioOpentrepService.listByIcaoCode (lIcaoCode, lLocationList);
936
937 //
938 std::cout << nbOfMatches << " (geographical) location(s) have been found "
939 << "matching the ICAO code ('" << lIcaoCodeStr << "')."
940 << std::endl;
941
942 if (nbOfMatches != 0) {
944 for (OPENTREP::LocationList_T::const_iterator itLocation =
945 lLocationList.begin();
946 itLocation != lLocationList.end(); ++itLocation, ++idx) {
947 const OPENTREP::Location& lLocation = *itLocation;
948 std::cout << " [" << idx << "]: " << lLocation << std::endl;
949 }
950
951 } else {
952 std::cout << "List of unmatched words:" << std::endl;
953 std::cout << " [" << 1 << "]: " << lIcaoCodeStr << std::endl;
954 }
955
956 break;
957 }
958
959 // ////////////////////////// List by FAA code ////////////////////////
961 if (requireSQLDatabase (iDBType, "list_by_faa") == false) {
962 break;
963 }
964
965 //
966 TokenList_T lTokenList = extractTokenListForFaaCode(ioTokenList);
967
968 // Parse the parameters given by the user, giving default values
969 // in case the user does not specify some (or all) of them
970 std::string lFaaCodeStr ("jfk");
971 parsePlaceKey (lTokenList, lFaaCodeStr);
972
973 // Call the underlying OpenTREP service
974 const OPENTREP::FAACode_T lFaaCode (lFaaCodeStr);
975 OPENTREP::LocationList_T lLocationList;
976 const OPENTREP::NbOfMatches_T nbOfMatches =
977 ioOpentrepService.listByFaaCode (lFaaCode, lLocationList);
978
979 //
980 std::cout << nbOfMatches << " (geographical) location(s) have been found "
981 << "matching the FAA code ('" << lFaaCodeStr << "')."
982 << std::endl;
983
984 if (nbOfMatches != 0) {
986 for (OPENTREP::LocationList_T::const_iterator itLocation =
987 lLocationList.begin();
988 itLocation != lLocationList.end(); ++itLocation, ++idx) {
989 const OPENTREP::Location& lLocation = *itLocation;
990 std::cout << " [" << idx << "]: " << lLocation << std::endl;
991 }
992
993 } else {
994 std::cout << "List of unmatched words:" << std::endl;
995 std::cout << " [" << 1 << "]: " << lFaaCodeStr << std::endl;
996 }
997
998 break;
999 }
1000
1001 // //////////////////////// List by UN/LOCODE code //////////////////////
1003 if (requireSQLDatabase (iDBType, "list_by_unlocode") == false) {
1004 break;
1005 }
1006
1007 //
1008 TokenList_T lTokenList = extractTokenListForUNLOCode(ioTokenList);
1009
1010 // Parse the parameters given by the user, giving default values
1011 // in case the user does not specify some (or all) of them
1012 std::string lUNLOCodeStr ("deham");
1013 parsePlaceKey (lTokenList, lUNLOCodeStr);
1014
1015 // Call the underlying OpenTREP service
1016 const OPENTREP::UNLOCode_T lUNLOCode (lUNLOCodeStr);
1017 OPENTREP::LocationList_T lLocationList;
1018 const OPENTREP::NbOfMatches_T nbOfMatches =
1019 ioOpentrepService.listByUNLOCode (lUNLOCode, lLocationList);
1020
1021 //
1022 std::cout << nbOfMatches << " (geographical) location(s) have been found "
1023 << "matching the UN/LOCODE code ('" << lUNLOCodeStr << "')."
1024 << std::endl;
1025
1026 if (nbOfMatches != 0) {
1028 for (OPENTREP::LocationList_T::const_iterator itLocation =
1029 lLocationList.begin();
1030 itLocation != lLocationList.end(); ++itLocation, ++idx) {
1031 const OPENTREP::Location& lLocation = *itLocation;
1032 std::cout << " [" << idx << "]: " << lLocation << std::endl;
1033 }
1034
1035 } else {
1036 std::cout << "List of unmatched words:" << std::endl;
1037 std::cout << " [" << 1 << "]: " << lUNLOCodeStr << std::endl;
1038 }
1039
1040 break;
1041 }
1042
1043 // //////////////////////// List by UIC code //////////////////////
1045 if (requireSQLDatabase (iDBType, "list_by_uiccode") == false) {
1046 break;
1047 }
1048
1049 //
1050 TokenList_T lTokenList = extractTokenListForUICCode(ioTokenList);
1051
1052 // Parse the parameters given by the user, giving default values
1053 // in case the user does not specify some (or all) of them
1054 std::string lUICCodeStr ("87775007");
1055 parsePlaceKey (lTokenList, lUICCodeStr);
1056
1057 // Convert the string into an integer
1058 OPENTREP::UICCode_T lUICCode;
1059
1060 try {
1061
1062 lUICCode = boost::lexical_cast<OPENTREP::UICCode_T> (lUICCodeStr);
1063
1064 } catch (boost::bad_lexical_cast& eCast) {
1065 lUICCode = 87775007;
1066 std::cerr << "The UIC code ('" << lUICCodeStr
1067 << "') cannot be understood. The default value ("
1068 << lUICCode << ") is kept." << std::endl;
1069 }
1070
1071 // Call the underlying OpenTREP service
1072 OPENTREP::LocationList_T lLocationList;
1073 const OPENTREP::NbOfMatches_T nbOfMatches =
1074 ioOpentrepService.listByUICCode (lUICCode, lLocationList);
1075
1076 //
1077 std::cout << nbOfMatches << " (geographical) location(s) have been found "
1078 << "matching the UIC code ('" << lUICCodeStr << "')."
1079 << std::endl;
1080
1081 if (nbOfMatches != 0) {
1083 for (OPENTREP::LocationList_T::const_iterator itLocation =
1084 lLocationList.begin();
1085 itLocation != lLocationList.end(); ++itLocation, ++idx) {
1086 const OPENTREP::Location& lLocation = *itLocation;
1087 std::cout << " [" << idx << "]: " << lLocation << std::endl;
1088 }
1089
1090 } else {
1091 std::cout << "List of unmatched words:" << std::endl;
1092 std::cout << " [" << 1 << "]: " << lUICCodeStr << std::endl;
1093 }
1094
1095 break;
1096 }
1097
1098 // ////////////////////////// List by Geoname ID ////////////////////////
1100 if (requireSQLDatabase (iDBType, "list_by_geonameid") == false) {
1101 break;
1102 }
1103
1104 //
1105 TokenList_T lTokenList =
1106 extractTokenListForGeonameID (ioTokenList);
1107
1108 // Parse the parameters given by the user, giving default values
1109 // in case the user does not specify some (or all) of them
1110 std::string lGeonameIDStr ("6299418");
1111 parsePlaceKey (lTokenList, lGeonameIDStr);
1112
1113 // Convert the string into an integer
1114 OPENTREP::GeonamesID_T lGeonameID;
1115
1116 try {
1117
1118 lGeonameID = boost::lexical_cast<OPENTREP::GeonamesID_T> (lGeonameIDStr);
1119
1120 } catch (boost::bad_lexical_cast& eCast) {
1121 lGeonameID = 6299418;
1122 std::cerr << "The Geoname ID ('" << lGeonameIDStr
1123 << "') cannot be understood. The default value ("
1124 << lGeonameID << ") is kept." << std::endl;
1125 }
1126
1127 // Call the underlying OpenTREP service
1128 OPENTREP::LocationList_T lLocationList;
1129 const OPENTREP::NbOfMatches_T nbOfMatches =
1130 ioOpentrepService.listByGeonameID (lGeonameID, lLocationList);
1131
1132 //
1133 std::cout << nbOfMatches << " (geographical) location(s) have been found "
1134 << "matching the Geoname ID ('" << lGeonameIDStr << "')."
1135 << std::endl;
1136
1137 if (nbOfMatches != 0) {
1139 for (OPENTREP::LocationList_T::const_iterator itLocation =
1140 lLocationList.begin();
1141 itLocation != lLocationList.end(); ++itLocation, ++idx) {
1142 const OPENTREP::Location& lLocation = *itLocation;
1143 std::cout << " [" << idx << "]: " << lLocation << std::endl;
1144 }
1145
1146 } else {
1147 std::cout << "List of unmatched items:" << std::endl;
1148 std::cout << " [" << 1 << "]: " << lGeonameIDStr << std::endl;
1149 }
1150
1151 break;
1152 }
1153
1154 // ///////////////////////// Database Creation /////////////////////////
1156 //
1157 std::cout << "Creating the 'trep' user and 'trep_trep' database"
1158 << std::endl;
1159
1160 // On MySQL/MariaDB and PostgreSQL, create the 'trep' user and 'trep_trep'
1161 // database.
1162 // On SQLite, delete the directory hosting the database, and re-create it.
1163 // On other database types, do nothing.
1164 //
1165 // Note: on MySQL/MariaDB and PostgreSQL, that command connects to the
1166 // deployment-slot-suffixed database (e.g., 'trep0') in order to
1167 // (re-)create the 'trep' user/role and that same database. If that
1168 // database does not exist yet, and/or the connecting user lacks the
1169 // privilege to create it, the connection attempt fails and throws a
1170 // SQLDatabaseException (e.g., SQLDatabaseImpossibleConnectionException
1171 // or SQLDatabaseUserCreationException). That exception is caught here
1172 // so that such a (mis-)configuration is reported as a friendly error
1173 // message instead of aborting the whole application.
1174 try {
1175 const bool lCreationSuccessful = ioOpentrepService.createSQLDBUser();
1176
1177 // Reporting
1178 if (lCreationSuccessful == true) {
1179 std::cout << "The 'trep' user and 'trep_trep' database have been created"
1180 << std::endl;
1181 } else {
1182 std::cout << "The 'trep' user and 'trep_trep' database could not be "
1183 << "created. See the log file ('" << iLogFilename
1184 << "') for details." << std::endl;
1185 }
1186
1187 } catch (const OPENTREP::SQLDatabaseException& eSQLDBException) {
1188 std::cerr << "The 'trep' user and '" << iDBType.describe()
1189 << "' database could not be created: "
1190 << eSQLDBException.what() << ". This may happen when the "
1191 << "deployment-slot database (e.g., 'trep0') does not "
1192 << "exist yet and/or the connecting user/role lacks the "
1193 << "privilege to create databases. On PostgreSQL, that "
1194 << "database may need to be pre-created (e.g., "
1195 << "'createdb -h localhost -U trep trep0'), or the 'trep' "
1196 << "role may need the CREATEDB privilege." << std::endl;
1197 }
1198
1199 break;
1200 }
1201
1202 // ///////////////////// Database connection string //////////////////////
1204 // Parse the parameters given by the user, giving default values
1205 // in case the user does not specify some (or all) of them
1206 const std::string lConnectionStringStr = toString (ioTokenList);
1207
1208 //
1209 std::cout << "Reset the connection string" << std::endl;
1210
1211 // Reset the connection string
1212 //
1213 // Note: the connection string format is specific to the current SQL
1214 // database type. For instance, PostgreSQL expects libpq-style
1215 // keywords (e.g., "dbname=trep user=trep password=trep"), whereas
1216 // MySQL/MariaDB expects "db=trep user=trep password=trep". Setting
1217 // the connection string triggers its parsing (so as to be able to
1218 // later append the deployment number/version to the database name),
1219 // which throws a SQLDatabaseConnectionStringParsingException when the
1220 // given string does not match the format expected for that database
1221 // type. That exception is caught here so that a malformed connection
1222 // string reports a friendly error message instead of aborting the
1223 // whole application.
1224 try {
1226 lConnectionString (lConnectionStringStr);
1227 ioOpentrepService.setSQLDBConnectString (lConnectionString);
1228
1229 //
1230 std::cout << "The connection string has been reset" << std::endl;
1231
1233 std::cerr << "The connection string ('" << lConnectionStringStr
1234 << "') cannot be understood for the '" << iDBType.describe()
1235 << "' database type: " << eParsing.what() << ". "
1236 << "The connection string has not been changed." << std::endl;
1237 }
1238
1239 break;
1240 }
1241
1242 // /////////////////// Deployment number/version /////////////////////
1244 // Toggle the deployment number/version
1245 ioDeploymentNumber = ioOpentrepService.toggleDeploymentNumber();
1246
1247 // Reporting
1248 std::cout << "The new deployment number/version is: " << ioDeploymentNumber
1250 << std::endl;
1251
1252 break;
1253 }
1254
1255 // /////////////////// Index or not non-IATA POR /////////////////////
1257 // Toggle the flag
1258 ioIncludeNonIATAPOR = ioOpentrepService.toggleShouldIncludeAllPORFlag();
1259
1260 // Reporting
1261 std::cout << "The new flag is: " << ioIncludeNonIATAPOR << std::endl;
1262
1263 break;
1264 }
1265
1266 // ///////////////////// Index or not in Xapian ///////////////////////
1268 // Toggle the flag
1269 ioShouldIndexPORInXapian =
1270 ioOpentrepService.toggleShouldIndexPORInXapianFlag();
1271
1272 // Reporting
1273 std::cout << "The new flag is: " << ioShouldIndexPORInXapian << std::endl;
1274
1275 break;
1276 }
1277
1278 // ///////////////////// Add or not in SQL DB ///////////////////////
1280 // Toggle the flag
1281 ioShouldAddPORInSQLDB = ioOpentrepService.toggleShouldAddPORInSQLDBFlag();
1282
1283 // Reporting
1284 std::cout << "The new flag is: " << ioShouldAddPORInSQLDB << std::endl;
1285
1286 break;
1287 }
1288
1289 // ///////////////////////// Tables Creation /////////////////////////
1291 //
1292 std::cout << "Creating/resetting the " << iDBType.describe()
1293 << " database tables" << std::endl;
1294
1295 // Create/reset the tables (on SQLite3, PostgreSQL, MySQL)
1296 //
1297 // Note: this connects to the deployment-slot-suffixed database (e.g.,
1298 // 'trep0'). If that database has not been created beforehand (see the
1299 // 'create_user' command) and/or the DDL statements fail (e.g., due to
1300 // insufficient privileges), a SQLDatabaseException is thrown. It is
1301 // caught here so as to report a friendly error message instead of
1302 // aborting the whole application.
1303 try {
1304 ioOpentrepService.createSQLDBTables();
1305
1306 //
1307 std::cout << "The " << iDBType.describe()
1308 << " tables has been created/resetted" << std::endl;
1309
1310 } catch (const OPENTREP::SQLDatabaseException& eSQLDBException) {
1311 std::cerr << "The " << iDBType.describe() << " database tables could "
1312 << "not be created/reset: " << eSQLDBException.what()
1313 << ". Make sure that the '" << iDBType.describe()
1314 << "' database has already been created (see the "
1315 << "'create_user' command) and that the corresponding "
1316 << "connection string is correct (see the 'info' command)."
1317 << std::endl;
1318 }
1319
1320 break;
1321 }
1322
1323 // ///////////////////////// Indexes Creation /////////////////////////
1325 //
1326 std::cout << "Creating/resetting the " << iDBType.describe()
1327 << " database indices" << std::endl;
1328
1329 // Create/reset the indices (on SQLite3, PostgreSQL, MySQL)
1330 //
1331 // See the note in the 'create_tables' case above: the same class of
1332 // exception can be thrown here (e.g., if the database does not exist,
1333 // or the underlying tables have not been created yet), and is caught
1334 // for the same reason.
1335 try {
1336 ioOpentrepService.createSQLDBIndexes();
1337
1338 //
1339 std::cout << "The " << iDBType.describe()
1340 << " indices has been created/resetted" << std::endl;
1341
1342 } catch (const OPENTREP::SQLDatabaseException& eSQLDBException) {
1343 std::cerr << "The " << iDBType.describe() << " database indices "
1344 << "could not be created/reset: " << eSQLDBException.what()
1345 << ". Make sure that the '" << iDBType.describe()
1346 << "' database and tables have already been created (see "
1347 << "the 'create_user' and 'create_tables' commands)."
1348 << std::endl;
1349 }
1350
1351 break;
1352 }
1353
1354 // ///////////////////////// POR File Indexing /////////////////////////
1356 //
1357 std::cout << "Indexing the POR file and filling in the SQL database may "
1358 << "take a few minutes on some architectures "
1359 << "(and a few seconds on fastest ones)..."
1360 << std::endl;
1361
1362 // Launch the indexation
1363 const OPENTREP::NbOfDBEntries_T lNbOfEntries =
1364 ioOpentrepService.insertIntoDBAndXapian();
1365
1366 //
1367 std::cout << lNbOfEntries << " entries have been processed" << std::endl;
1368
1369 break;
1370 }
1371
1372 // /////////////////////////// Default / No value ///////////////////////
1373 case Command_T::NOP: {
1374 break;
1375 }
1376
1378 default: {
1379 // DEBUG
1380 std::ostringstream oStr;
1381 oStr << "That command is not yet understood: '" << iUserInput
1382 << "' => " << ioTokenList;
1383 OPENTREP_LOG_DEBUG (oStr.str());
1384 std::cout << oStr.str() << std::endl;
1385 }
1386 }
1387
1388
1389 return lCommandType;
1390}
1391
1392// /////////////// M A I N /////////////////
1393int main (int argc, char* argv[]) {
1394
1395 // Readline history
1396 const unsigned int lHistorySize (100);
1397 const std::string lHistoryFilename ("opentrep-dbmgr.hist");
1398 const std::string lHistoryBackupFilename ("opentrep-dbmgr.hist.bak");
1399
1400 // Output log File
1401 std::string lLogFilename;
1402
1403 // File-path of POR (points of reference)
1404 std::string lPORFilepathStr;
1405
1406 // Xapian database name (directory of the index)
1407 std::string lXapianDBNameStr;
1408
1409 // SQL database type
1410 std::string lSQLDBTypeStr;
1411
1412 // SQL database connection string
1413 std::string lSQLDBConnectionStr;
1414
1415 // Deployment number/version
1416 OPENTREP::DeploymentNumber_T lDeploymentNumber;
1417
1418 // Whether or not to include non-IATA-referenced POR
1419 OPENTREP::shouldIndexNonIATAPOR_T lIncludeNonIATAPOR;
1420
1421 // Whether or not to index the POR in Xapian
1422 OPENTREP::shouldIndexPORInXapian_T lShouldIndexPORInXapian;
1423
1424 // Whether or not to insert the POR in the SQL database
1425 OPENTREP::shouldAddPORInSQLDB_T lShouldAddPORInSQLDB;
1426
1427 // Semicolon-separated command(s) to execute in non-interactive mode
1428 // (-c/--command option)
1429 std::string lCommandStr;
1430
1431 // Call the command-line option parser
1432 const int lOptionParserStatus =
1433 readConfiguration (argc, argv, lPORFilepathStr, lXapianDBNameStr,
1434 lSQLDBTypeStr, lSQLDBConnectionStr, lDeploymentNumber,
1435 lIncludeNonIATAPOR, lShouldIndexPORInXapian,
1436 lShouldAddPORInSQLDB, lLogFilename, lCommandStr);
1437
1438 if (lOptionParserStatus == K_OPENTREP_EARLY_RETURN_STATUS) {
1439 return 0;
1440 }
1441
1442 // Set the log parameters
1443 std::ofstream logOutputFile;
1444 // open and clean the log outputfile
1445 logOutputFile.open (lLogFilename.c_str());
1446 logOutputFile.clear();
1447
1448 // Initialise the context
1449 const OPENTREP::PORFilePath_T lPORFilepath (lPORFilepathStr);
1450 const OPENTREP::TravelDBFilePath_T lXapianDBName (lXapianDBNameStr);
1451 const OPENTREP::DBType lDBType (lSQLDBTypeStr);
1452 const OPENTREP::SQLDBConnectionString_T lSQLDBConnStr (lSQLDBConnectionStr);
1453 OPENTREP::OPENTREP_Service opentrepService (logOutputFile, lPORFilepath,
1454 lXapianDBName,
1455 lDBType, lSQLDBConnStr,
1456 lDeploymentNumber,
1457 lIncludeNonIATAPOR,
1458 lShouldIndexPORInXapian,
1459 lShouldAddPORInSQLDB);
1460
1461 // If one (or several) command(s) have been given on the command-line
1462 // (-c/--command option), execute them in a non-interactive way (i.e.,
1463 // without prompting the user, nor using the GNU readline library),
1464 // and then exit.
1465 if (lCommandStr.empty() == false) {
1466 // DEBUG
1467 OPENTREP_LOG_DEBUG ("==================================================");
1468 OPENTREP_LOG_DEBUG ("= Beginning of the non-interactive session =");
1469 OPENTREP_LOG_DEBUG ("==================================================");
1470
1471 const TokenList_T lCommandLineList = splitCommandLine (lCommandStr);
1472 Command_T::Type_T lNonInteractiveCommandType (Command_T::NOP);
1473
1474 for (TokenList_T::const_iterator itCommand = lCommandLineList.begin();
1475 itCommand != lCommandLineList.end()
1476 && lNonInteractiveCommandType != Command_T::QUIT; ++itCommand) {
1477 const std::string& lSingleCommandStr = *itCommand;
1478
1479 // Echo the command being executed, so that the (non-interactive)
1480 // session remains easy to follow (e.g., when scripted)
1481 std::cout << "opentrep> " << lSingleCommandStr << std::endl;
1482
1483 // Tokenise that single command, the same way the GNU readline
1484 // library would have done for the interactive session
1485 TokenList_T lTokenList;
1486 SplitTokens (lSingleCommandStr, lTokenList);
1487
1488 // Interpret and execute the command, re-using the very same
1489 // dispatcher as the interactive session
1490 lNonInteractiveCommandType =
1491 processUserCommand (lSingleCommandStr, lTokenList, opentrepService,
1492 lDBType, lLogFilename, lPORFilepathStr,
1493 lDeploymentNumber, lIncludeNonIATAPOR,
1494 lShouldIndexPORInXapian, lShouldAddPORInSQLDB);
1495 }
1496
1497 // DEBUG
1498 OPENTREP_LOG_DEBUG ("End of the session. Exiting.");
1499 std::cout << "End of the session. Exiting." << std::endl;
1500
1501 // Close the Log outputFile
1502 logOutputFile.close();
1503
1504 return 0;
1505 }
1506
1507 // DEBUG
1508 OPENTREP_LOG_DEBUG ("====================================================");
1509 OPENTREP_LOG_DEBUG ("= Beginning of the interactive session =");
1510 OPENTREP_LOG_DEBUG ("====================================================");
1511
1512 // Initialise the GNU readline wrapper
1513 swift::SReadline lReader (lHistoryFilename, lHistorySize);
1514 initReadline (lReader);
1515
1516 // Now we can ask user for a line
1517 std::string lUserInput;
1518 bool EndOfInput (false);
1519 Command_T::Type_T lCommandType (Command_T::NOP);
1520
1521 while (lCommandType != Command_T::QUIT && EndOfInput == false) {
1522 // Prompt
1523 std::ostringstream oPromptStr;
1524 oPromptStr << "opentrep> ";
1525
1526 // Call read-line, which will fill the list of tokens
1527 TokenList_T lTokenListByReadline;
1528 lUserInput = lReader.GetLine (oPromptStr.str(), lTokenListByReadline,
1529 EndOfInput);
1530
1531 // The history can be saved to an arbitrary file at any time
1532 lReader.SaveHistory (lHistoryBackupFilename);
1533
1534 // The end-of-input typically corresponds to a CTRL-D typed by the user
1535 if (EndOfInput) {
1536 std::cout << std::endl;
1537 break;
1538 }
1539
1540 // Interpret and execute the user command, reusing the same dispatcher
1541 // as the non-interactive command mode (-c/--command option)
1542 lCommandType =
1543 processUserCommand (lUserInput, lTokenListByReadline, opentrepService,
1544 lDBType, lLogFilename, lPORFilepathStr,
1545 lDeploymentNumber, lIncludeNonIATAPOR,
1546 lShouldIndexPORInXapian, lShouldAddPORInSQLDB);
1547 }
1548
1549 // DEBUG
1550 OPENTREP_LOG_DEBUG ("End of the session. Exiting.");
1551 std::cout << "End of the session. Exiting." << std::endl;
1552
1553 // Close the Log outputFile
1554 logOutputFile.close();
1555
1556 return 0;
1557}
#define OPENTREP_LOG_DEBUG(iToBeLogged)
Definition Logger.hpp:33
C++ wrapper around libreadline.
Interface for the OPENTREP Services.
NbOfMatches_T listByIataCode(const IATACode_T &, LocationList_T &)
NbOfMatches_T listByUNLOCode(const UNLOCode_T &, LocationList_T &)
void setSQLDBConnectString(const SQLDBConnectionString_T &)
OPENTREP::shouldIndexNonIATAPOR_T toggleShouldIncludeAllPORFlag()
std::pair< const PORFilePath_T, const DBFilePathPair_T > FilePathSet_T
FilePathSet_T getFilePaths() const
NbOfMatches_T listByFaaCode(const FAACode_T &, LocationList_T &)
NbOfMatches_T listByUICCode(const UICCode_T &, LocationList_T &)
NbOfMatches_T listByIcaoCode(const ICAOCode_T &, LocationList_T &)
NbOfMatches_T listByGeonameID(const GeonamesID_T &, LocationList_T &)
OPENTREP::shouldIndexPORInXapian_T toggleShouldIndexPORInXapianFlag()
std::pair< const TravelDBFilePath_T, const SQLDBConnectionString_T > DBFilePathPair_T
NbOfDBEntries_T insertIntoDBAndXapian()
OPENTREP::DeploymentNumber_T toggleDeploymentNumber()
OPENTREP::shouldAddPORInSQLDB_T toggleShouldAddPORInSQLDBFlag()
The readline library wrapper.
bool SaveHistory(std::ostream &OS)
Saves the history to the given file stream.
std::string GetLine(const std::string &Prompt)
Gets a single line from a user.
void RegisterCompletions(const ContainerType &Container)
Allows to register custom completers.
const std::string DEFAULT_OPENTREP_SQLITE_DB_FILEPATH
unsigned int UICCode_T
const std::string DEFAULT_OPENTREP_PG_CONN_STRING
bool shouldAddPORInSQLDB_T
const unsigned short DEFAULT_OPENTREP_DEPLOYMENT_NUMBER_SIZE
unsigned int NbOfDBEntries_T
const bool DEFAULT_OPENTREP_INCLUDE_NONIATA_POR
const std::string DEFAULT_OPENTREP_SQL_DB_TYPE
std::string parseAndDisplayConnectionString(const DBType &iDBType, const std::string &iSQLDBConnStr, const DeploymentNumber_T &iDeploymentNumber)
std::list< Location > LocationList_T
const bool DEFAULT_OPENTREP_INDEX_IN_XAPIAN
const unsigned short DEFAULT_OPENTREP_DEPLOYMENT_NUMBER
bool shouldIndexPORInXapian_T
const std::string DEFAULT_OPENTREP_MYSQL_CONN_STRING
unsigned short DeploymentNumber_T
const std::string DEFAULT_OPENTREP_XAPIAN_DB_FILEPATH
unsigned short NbOfMatches_T
const bool DEFAULT_OPENTREP_ADD_IN_DB
unsigned int GeonamesID_T
const std::string DEFAULT_OPENTREP_POR_FILEPATH
bool shouldIndexNonIATAPOR_T
int main(int argc, char *argv[])
void parseConnectionString(const TokenList_T &iTokenList, std::string &ioConnectionString)
TokenList_T extractTokenListForIataCode(const TokenList_T &iTokenList)
TokenList_T extractTokenListForIcaoCode(const TokenList_T &iTokenList)
Command_T::Type_T processUserCommand(const std::string &iUserInput, TokenList_T &ioTokenList, OPENTREP::OPENTREP_Service &ioOpentrepService, const OPENTREP::DBType &iDBType, const std::string &iLogFilename, const std::string &iPORFilepathStr, OPENTREP::DeploymentNumber_T &ioDeploymentNumber, OPENTREP::shouldIndexNonIATAPOR_T &ioIncludeNonIATAPOR, OPENTREP::shouldIndexPORInXapian_T &ioShouldIndexPORInXapian, OPENTREP::shouldAddPORInSQLDB_T &ioShouldAddPORInSQLDB)
std::string toString(const TokenList_T &iTokenList)
bool requireSQLDatabase(const OPENTREP::DBType &iDBType, const std::string &iCommandName)
TokenList_T extractTokenList(const TokenList_T &iTokenList, const std::string &iRegularExpression)
int readConfiguration(int argc, char *argv[], std::string &ioPORFilepath, std::string &ioXapianDBFilepath, std::string &ioSQLDBTypeString, std::string &ioSQLDBConnectionString, unsigned short &ioDeploymentNumber, bool &ioIncludeNonIATAPOR, bool &ioIndexPORInXapian, bool &ioAddPORInDB, std::string &ioLogFilename, std::string &ioCommand)
const std::string K_OPENTREP_DEFAULT_LOG_FILENAME("opentrep-dbmgr.log")
void parsePlaceKey(const TokenList_T &iTokenList, std::string &ioPlaceKey)
std::ostream & operator<<(std::ostream &os, const std::vector< T > &v)
TokenList_T extractTokenListForGeonameID(const TokenList_T &iTokenList)
TokenList_T extractTokenListForFaaCode(const TokenList_T &iTokenList)
void initReadline(swift::SReadline &ioInputReader)
TokenList_T extractTokenListForUNLOCode(const TokenList_T &iTokenList)
TokenList_T extractTokenListForUICCode(const TokenList_T &iTokenList)
Command_T::Type_T extractCommand(TokenList_T &ioTokenList)
std::vector< std::string > TokenList_T
std::vector< std::string > splitCommandLine(const std::string &iCommandLine)
const int K_OPENTREP_EARLY_RETURN_STATUS
std::vector< std::string > WordList_T
const std::string K_OPENTREP_DEFAULT_LOG_FILENAME("opentrep-indexer.log")
@ TOGGLE_XAPIAN_IDEXING_FLAG
@ TOGGLE_SQLDB_INSERTING_FLAG
@ TOGGLE_NONIATA_INDEXING_FLAG
Enumeration of database types.
Definition DBType.hpp:17
const std::string describe() const
Definition DBType.cpp:135
Structure modelling a (geographical) location.
Definition Location.hpp:25
std::string toString() const
Definition Location.cpp:282