diff --git a/statistics/CMakeLists.txt b/statistics/CMakeLists.txt index a468c9af7a30b7a37741034fe040bdac7b0dc3c9..fc4ed891dfe2157a61d2501b5a610332fce65703 100644 --- a/statistics/CMakeLists.txt +++ b/statistics/CMakeLists.txt @@ -54,6 +54,7 @@ set (STATISTICS_LIB_SRC_FILES MySQLStatisticsService.cpp DatabaseStatisticsServiceFactory.cpp StatisticsServiceFactory.cpp + JsonStatisticsService.cpp ) add_library (ctastatistics SHARED diff --git a/statistics/JsonStatisticsService.cpp b/statistics/JsonStatisticsService.cpp new file mode 100644 index 0000000000000000000000000000000000000000..37cec03a9480cdd52763334e31ce03b7ae16a18a --- /dev/null +++ b/statistics/JsonStatisticsService.cpp @@ -0,0 +1,48 @@ +/* + * The CERN Tape Archive (CTA) project + * Copyright (C) 2019 CERN + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "JsonStatisticsService.hpp" + +namespace cta { +namespace statistics { + +JsonStatisticsService::JsonStatisticsService(OutputStream * output):m_output(output),m_input(nullptr) { + +} + +JsonStatisticsService::JsonStatisticsService(OutputStream * output, InputStream * input):m_output(output),m_input(input) { + +} + +void JsonStatisticsService::saveStatistics(const cta::statistics::Statistics& statistics){ + *m_output << statistics; +} + +std::unique_ptr<cta::statistics::Statistics> JsonStatisticsService::getStatistics(){ + throw cta::exception::Exception("In JsonStatisticsService::getStatistics(), method not implemented."); +} + +void JsonStatisticsService::updateStatisticsPerTape(){ + throw cta::exception::Exception("In JsonStatistics::updateStatisticsPerTape(), method not implemented."); +} + + +JsonStatisticsService::~JsonStatisticsService() { +} + +}} \ No newline at end of file diff --git a/statistics/JsonStatisticsService.hpp b/statistics/JsonStatisticsService.hpp new file mode 100644 index 0000000000000000000000000000000000000000..2d0e4e0d8ca4f8d2f8bf33695eafd7e138c6959b --- /dev/null +++ b/statistics/JsonStatisticsService.hpp @@ -0,0 +1,62 @@ +/* + * The CERN Tape Archive (CTA) project + * Copyright (C) 2019 CERN + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include "StatisticsService.hpp" +#include "Statistics.hpp" + + +namespace cta { namespace statistics { + + /** + * This class is a JSON statistics service + * allowing to perform statistics operation + * to and from a JSON file + */ +class JsonStatisticsService: public StatisticsService { +public: + typedef std::ostream OutputStream; + typedef std::istream InputStream; + + /** + * Constructor of the service with a OutputStream object + */ + JsonStatisticsService(OutputStream * output); + + /** + * Constructor of the service with the OutputStream and InputStream objects + * @param output the OutputStream object + * @param input the InputStream object + */ + JsonStatisticsService(OutputStream * output, InputStream * input); + + JsonStatisticsService(const JsonStatisticsService& orig) = delete; + + virtual void saveStatistics(const cta::statistics::Statistics& statistics) override; + virtual std::unique_ptr<cta::statistics::Statistics> getStatistics() override; + virtual void updateStatisticsPerTape() override; + + virtual ~JsonStatisticsService(); + +private: + OutputStream * m_output; + InputStream * m_input; +}; + +}} \ No newline at end of file diff --git a/statistics/JsonStatisticsServiceFactory.hpp b/statistics/JsonStatisticsServiceFactory.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a21d8cb545ca45a98cfa4745a0a23eeb748f1446 --- /dev/null +++ b/statistics/JsonStatisticsServiceFactory.hpp @@ -0,0 +1,36 @@ +/* + * The CERN Tape Archive (CTA) project + * Copyright (C) 2019 CERN + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include "common/make_unique.hpp" +#include "JsonStatisticsService.hpp" + +namespace cta{ +namespace statistics { + +class JsonStatisticsServiceFactory { +public: + static std::unique_ptr<JsonStatisticsService> create(JsonStatisticsService::OutputStream *output, JsonStatisticsService::InputStream *input = nullptr){ + return cta::make_unique<JsonStatisticsService>(output,input); + } +private: + +}; + +}} \ No newline at end of file diff --git a/statistics/StatisticsSaveCmd.cpp b/statistics/StatisticsSaveCmd.cpp index fdec45dbf2e53c6276bdd3a47803d4e261854325..bcc7727a6e5af51cda0d24f18d902b4da452d155 100644 --- a/statistics/StatisticsSaveCmd.cpp +++ b/statistics/StatisticsSaveCmd.cpp @@ -57,30 +57,54 @@ int StatisticsSaveCmd::exceptionThrowingMain(const int argc, char *const *const verifyCmdLineArgs(cmdLineArgs); - const uint64_t maxNbConns = 1; + bool isJsonOutput = cmdLineArgs.jsonOutput; - auto loginStatistics = rdbms::Login::parseFile(cmdLineArgs.statisticsDbConfigPath); - rdbms::ConnPool statisticsConnPool(loginStatistics, maxNbConns); - auto statisticsConn = statisticsConnPool.getConn(); + const uint64_t maxNbConns = 1; + + std::unique_ptr<StatisticsService> statisticsStatisticsService; - //Get the statistics schema so that we can create, drop and check the presence of the database - auto statisticsSchema = StatisticsSchemaFactory::create(loginStatistics.dbType); + std::unique_ptr<rdbms::ConnPool> statisticsConnPool; + std::unique_ptr<rdbms::Conn> statisticsConn; + if(!cmdLineArgs.statisticsDbConfigPath.empty()){ - if(cmdLineArgs.buildDatabase){ - //Build the database - buildStatisticsDatabase(statisticsConn,*statisticsSchema); - return EXIT_SUCCESS; - } - - if(cmdLineArgs.dropDatabase){ - //drop the database - if(userConfirmDropStatisticsSchemaFromDb(loginStatistics)){ - dropStatisticsDatabase(statisticsConn,*statisticsSchema); + auto loginStatistics = rdbms::Login::parseFile(cmdLineArgs.statisticsDbConfigPath); + statisticsConnPool = cta::make_unique<rdbms::ConnPool>(loginStatistics, maxNbConns); + statisticsConn = cta::make_unique<rdbms::Conn>(statisticsConnPool->getConn()); + + //Get the statistics schema so that we can create, drop and check the presence of the database + auto statisticsSchema = StatisticsSchemaFactory::create(loginStatistics.dbType); + + if(cmdLineArgs.buildDatabase){ + //Build the database + buildStatisticsDatabase(*statisticsConn,*statisticsSchema); + return EXIT_SUCCESS; + } + + if(cmdLineArgs.dropDatabase){ + //drop the database + if(userConfirmDropStatisticsSchemaFromDb(loginStatistics)){ + dropStatisticsDatabase(*statisticsConn,*statisticsSchema); + } + return EXIT_SUCCESS; + } + + //Check that the statistics schema tables are in the statistics database + SchemaChecker::Builder statisticsCheckerBuilder("statistics",loginStatistics.dbType,*statisticsConn); + std::unique_ptr<SchemaChecker> statisticsChecker = + statisticsCheckerBuilder.useCppSchemaStatementsReader(*statisticsSchema) + .useSQLiteSchemaComparer() + .build(); + SchemaChecker::Status compareTablesStatus = statisticsChecker->compareTablesLocatedInSchema(); + if(compareTablesStatus == SchemaChecker::Status::FAILURE){ + return EXIT_FAILURE; } - return EXIT_SUCCESS; - } - //Save the CTA statistics + statisticsStatisticsService = StatisticsServiceFactory::create(*statisticsConn,loginStatistics.dbType); + } else if (isJsonOutput){ + statisticsStatisticsService = StatisticsServiceFactory::create(std::cout); + } else { + throw cta::exception::Exception("No --json option provided and no statistics database configuration file provided."); + } //Connect to the catalogue database auto loginCatalogue = rdbms::Login::parseFile(cmdLineArgs.catalogueDbConfigPath); @@ -108,24 +132,12 @@ int StatisticsSaveCmd::exceptionThrowingMain(const int argc, char *const *const if(tapeTableStatus == SchemaChecker::Status::FAILURE || voTableStatus == SchemaChecker::Status::FAILURE ){ return EXIT_FAILURE; } - - //Check that the statistics schema tables are in the statistics database - SchemaChecker::Builder statisticsCheckerBuilder("statistics",loginStatistics.dbType,statisticsConn); - std::unique_ptr<SchemaChecker> statisticsChecker = - statisticsCheckerBuilder.useCppSchemaStatementsReader(*statisticsSchema) - .useSQLiteSchemaComparer() - .build(); - SchemaChecker::Status compareTablesStatus = statisticsChecker->compareTablesLocatedInSchema(); - if(compareTablesStatus == SchemaChecker::Status::FAILURE){ - return EXIT_FAILURE; - } //Compute the statistics std::unique_ptr<StatisticsService> catalogueStatisticsService = StatisticsServiceFactory::create(catalogueConn,loginCatalogue.dbType); std::unique_ptr<Statistics> statistics = catalogueStatisticsService->getStatistics(); //Insert them into the statistics database try { - std::unique_ptr<StatisticsService> statisticsStatisticsService = StatisticsServiceFactory::create(statisticsConn,loginStatistics.dbType); statisticsStatisticsService->saveStatistics(*statistics); } catch (cta::exception::Exception &ex) { std::cerr << ex.getMessageValue() << std::endl; @@ -158,9 +170,15 @@ void StatisticsSaveCmd::verifyCmdLineArgs(const StatisticsSaveCmdLineArgs& cmdLi if(statisticsDbConfigPathEmpty && (cmdLineArgs.buildDatabase || cmdLineArgs.dropDatabase)){ throw cta::exception::Exception("The statistics database configuration file should be provided."); } - if((!cmdLineArgs.buildDatabase && !cmdLineArgs.dropDatabase) && (catalogueDbConfigPathEmpty || statisticsDbConfigPathEmpty)){ + if(cmdLineArgs.jsonOutput && !statisticsDbConfigPathEmpty){ + throw cta::exception::Exception("The statistics database connection file should not be provided when --json flag is set."); + } + if((!cmdLineArgs.buildDatabase && !cmdLineArgs.dropDatabase && !cmdLineArgs.jsonOutput) && (catalogueDbConfigPathEmpty || statisticsDbConfigPathEmpty)){ throw cta::exception::Exception("You should provide the catalogue database and the statistics database connection files."); - } + } + if((!cmdLineArgs.buildDatabase && !cmdLineArgs.dropDatabase && cmdLineArgs.jsonOutput) && catalogueDbConfigPathEmpty){ + throw cta::exception::Exception("The catalogue database connection file should be provided when --json flag is set."); + } } void StatisticsSaveCmd::buildStatisticsDatabase(cta::rdbms::Conn& statisticsDatabaseConn, const StatisticsSchema& statisticsSchema) { diff --git a/statistics/StatisticsSaveCmdLineArgs.cpp b/statistics/StatisticsSaveCmdLineArgs.cpp index 90b005c32fd52d3802898f54bf9979043aae628a..bda54fd78fe89ed359cb33a0b91c511730f6cd66 100644 --- a/statistics/StatisticsSaveCmdLineArgs.cpp +++ b/statistics/StatisticsSaveCmdLineArgs.cpp @@ -37,6 +37,7 @@ StatisticsSaveCmdLineArgs::StatisticsSaveCmdLineArgs(const int argc, char *const {"statisticsconf",required_argument,NULL,'s'}, {"build",no_argument, NULL, 'b'}, {"drop", no_argument, NULL, 'd'}, + {"json", no_argument, NULL, 'j'}, {"help", no_argument, NULL, 'h'}, {NULL , 0, NULL, 0} }; @@ -46,7 +47,7 @@ StatisticsSaveCmdLineArgs::StatisticsSaveCmdLineArgs(const int argc, char *const opterr = 0; int opt = 0; - while((opt = getopt_long(argc, argv, ":hbdc:s:", longopts, NULL)) != -1) { + while((opt = getopt_long(argc, argv, ":hbdjc:s:", longopts, NULL)) != -1) { switch(opt) { case 'h': help = true; @@ -63,6 +64,9 @@ StatisticsSaveCmdLineArgs::StatisticsSaveCmdLineArgs(const int argc, char *const case 'd': dropDatabase = true; break; + case 'j': + jsonOutput = true; + break; case ':': // Missing parameter { exception::CommandLineNotParsed ex; @@ -112,21 +116,23 @@ StatisticsSaveCmdLineArgs::StatisticsSaveCmdLineArgs(const int argc, char *const void StatisticsSaveCmdLineArgs::printUsage(std::ostream &os) { os << "Usage:" << std::endl << - " cta-statistics-save --catalogueconf catalogueDbConnectionFile --statisticsconf statisticsDbConnectionFile [options]" << std::endl << + " cta-statistics-save --catalogueconf catalogueDbConnectionFile [options]" << std::endl << "Where:" << std::endl << " catalogueDbConnectionFile" << std::endl << " The path to the file containing the connection details of the CTA" << std::endl << " catalogue database" << std::endl << - " statisticsDbConnectionFile" << std::endl << + "Options:" << std::endl << + " -s,--statisticsconf statisticsDbConnectionFile" << std::endl << " The path to the file containing the connection details of the CTA" << std::endl << " statistics database" << std::endl << - "Options:" << std::endl << " -h,--help" << std::endl << " Prints this usage message" << std::endl << " -b, --build" << std::endl << " Builds the statistics database" << std::endl << " -d, --drop" << std::endl << - " Drops the statistics database" << std::endl; + " Drops the statistics database" << std::endl << + " -j, --json" << std::endl << + " Dumps the statistics in json format on stdout" << std::endl; } } // namespace statistics diff --git a/statistics/StatisticsSaveCmdLineArgs.hpp b/statistics/StatisticsSaveCmdLineArgs.hpp index 6dc083a0314a68e9c3e260f9c86d8e4b0be35a30..8a45640e63855750f3acb33df30d47bb1283db9a 100644 --- a/statistics/StatisticsSaveCmdLineArgs.hpp +++ b/statistics/StatisticsSaveCmdLineArgs.hpp @@ -55,6 +55,11 @@ struct StatisticsSaveCmdLineArgs { */ bool dropDatabase = false; + /** + * True if the --json flag has been provided + */ + bool jsonOutput = false; + /** * Constructor that parses the specified command-line arguments. * diff --git a/statistics/StatisticsServiceFactory.cpp b/statistics/StatisticsServiceFactory.cpp index 78c1bd4923ec92a2cc8cbbefd666f9cea9a2b80b..2c6bb4ccd8573dc291a5e41b2fb1ea81c69b51e8 100644 --- a/statistics/StatisticsServiceFactory.cpp +++ b/statistics/StatisticsServiceFactory.cpp @@ -19,6 +19,7 @@ #include "StatisticsServiceFactory.hpp" #include "DatabaseStatisticsServiceFactory.hpp" +#include "JsonStatisticsServiceFactory.hpp" namespace cta { namespace statistics { @@ -26,4 +27,8 @@ std::unique_ptr<StatisticsService> StatisticsServiceFactory::create(cta::rdbms:: return DatabaseStatisticsServiceFactory::create(connection,dbType); } +std::unique_ptr<StatisticsService> StatisticsServiceFactory::create(std::ostream& ostream) { + return JsonStatisticsServiceFactory::create(&ostream); +} + }} \ No newline at end of file diff --git a/statistics/StatisticsServiceFactory.hpp b/statistics/StatisticsServiceFactory.hpp index 4287a95f2f7a75339ff4303d92beb89dfc8b0a29..0c28590cc45221d1a0fd6b2d2925e57d66f2b04b 100644 --- a/statistics/StatisticsServiceFactory.hpp +++ b/statistics/StatisticsServiceFactory.hpp @@ -35,6 +35,8 @@ public: * @return a unique_ptr containing the StatisticsService */ static std::unique_ptr<StatisticsService> create(cta::rdbms::Conn &connection, cta::rdbms::Login::DbType dbType); + + static std::unique_ptr<StatisticsService> create(std::ostream & ostream); };