From 19eefb3c2c33c54602a43ce12eeccfd5bf164e0f Mon Sep 17 00:00:00 2001 From: Steven de Ridder Date: Mon, 24 Jan 2022 16:02:26 +0100 Subject: [PATCH] Initial commit. dependencies not resolved yet. --- .gitignore | 2 ++ CMakeLists.txt | 25 +++++++++++++++++++++++++ README.md | 0 src/CMakeLists.txt | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/jobscheduler.cpp | 155 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/jobscheduler.h | 131 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/jobtimer.cpp | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ src/jobtimer.h | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ tests/CMakeLists.txt | 30 ++++++++++++++++++++++++++++++ 9 files changed, 544 insertions(+), 0 deletions(-) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 README.md create mode 100644 src/CMakeLists.txt create mode 100644 src/jobscheduler.cpp create mode 100644 src/jobscheduler.h create mode 100644 src/jobtimer.cpp create mode 100644 src/jobtimer.h create mode 100644 tests/CMakeLists.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0ff047c --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +build/ +CMakeLists.txt.user diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..6dcf2b2 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,25 @@ +cmake_minimum_required(VERSION 3.0) + +# Check to see where cmake is located. +if( IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/cmake ) + LIST(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) +elseif( IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../cmake ) + LIST(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../cmake) +else() + return() +endif() + +# Check to see if there is versioning information available +if(IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/osdev_versioning/cmake) + LIST(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/osdev_versioning/cmake) + include(osdevversion) +endif() + +include(projectheader) +project_header(osdev_jobscheduler) + +add_subdirectory(src) +add_subdirectory(tests) + +# include(packaging) +# package_component() diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/README.md diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..69c11f8 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,52 @@ +cmake_minimum_required(VERSION 3.0) +LIST(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../../../external/hsoa_create_version_include/cmake) +include(projectheader) +project_header(jobscheduler) + +find_package( Qt5Core REQUIRED ) +find_package( Qt5Sql REQUIRED ) + +include_directories( SYSTEM + ${Qt5Core_INCLUDE_DIRS} +) + +include(compiler) + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR}/../logutils + ${CMAKE_CURRENT_SOURCE_DIR}/../config + ${CMAKE_CURRENT_SOURCE_DIR}/../dcxml + ${CMAKE_CURRENT_SOURCE_DIR}/../global +) + +set(SRC_LIST + ${CMAKE_CURRENT_SOURCE_DIR}/jobscheduler.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/jobtimer.cpp +) + +include(qtmoc) +create_mocs( SRC_LIST MOC_LIST + ${CMAKE_CURRENT_SOURCE_DIR}/jobscheduler.h + ${CMAKE_CURRENT_SOURCE_DIR}/jobtimer.h +) + +set_source_files_properties( + ${MOC_LIST} + PROPERTIES + COMPILE_FLAGS -Wno-undefined-reinterpret-cast +) + +link_directories( + ${CMAKE_BINARY_DIR}/lib +) + +include(library) +add_libraries( + ${Qt5Core_LIBRARIES} + logutils + global + config +) + +include(installation) +install_component() diff --git a/src/jobscheduler.cpp b/src/jobscheduler.cpp new file mode 100644 index 0000000..367d47d --- /dev/null +++ b/src/jobscheduler.cpp @@ -0,0 +1,155 @@ +/* **************************************************************************** + * Copyright 2019 Open Systems Development BV * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the "Software"), * + * to deal in the Software without restriction, including without limitation * + * the rights to use, copy, modify, merge, publish, distribute, sublicense, * + * and/or sell copies of the Software, and to permit persons to whom the * + * Software is furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included in * + * all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * + * DEALINGS IN THE SOFTWARE. * + * ***************************************************************************/ + +#include "jobscheduler.h" +#include "log.h" + +using namespace osdev::components; + +JobScheduler::JobScheduler( QObject *_parent ) + : QObject( _parent ) + , m_jobSchedule() +{ + +} + +JobScheduler::JobScheduler( const QList& lstJobs, QObject *_parent ) + : QObject( _parent ) + , m_jobSchedule() +{ + for( const auto& jobItem : lstJobs ) + { + this->createJob( jobItem ); + } +} + +void JobScheduler::slotRunJob( const QString& jobName ) +{ + LogInfo( "JobScheduler::slotRunJob", QString( "SlotRunJob fired for job : %1" ).arg( jobName ) ); + if( m_jobSchedule.contains( jobName ) ) + { + emit signalRunJob( m_jobSchedule.value( jobName )->jobData() ); + } + + this->rescheduleJob( jobName ); +} + +void JobScheduler::scheduleJob( const QString& _job_name, + const QHash& _param_list, + const int _interval, + const QString& _target_object, + const QTime& _run_time, + const QDate& _run_date ) +{ + + // Get the corresponding job from the map. + QPointer schedJob = m_jobSchedule.value( _job_name ); + if( nullptr == schedJob ) + { + LogInfo( "[JobScheduler::scheduleJob]", QString( "Job %1 not added to the an unknown error." ).arg( _job_name ) ); + return; + } + + // Scheduling is done within 24 Hours. After each timer-fire we check if the rundate is equal to the currentDate. + // If so.. Run the job. If not, reschedule for the next 24 hours. + if( _run_time.isValid() || _run_date.isValid() ) + { + QDateTime schedDT( QDate::currentDate(), _run_time ); + + if( QDateTime::currentDateTime().secsTo( schedDT ) <= 0 ) + { + // Add one day from today. + schedDT = schedDT.addDays( 1 ); + } + + // Check if the jobName already exists. If so, re-schedule the existing job. If not, create the job. + if( !m_jobSchedule.contains( _job_name ) ) + { + this->createJob( JobData( _job_name, _param_list, _run_time, _interval, _target_object, _run_date ) ); + } + + if( 0 == _interval ) + { + qint64 secondsToRun = QDateTime::currentDateTime().secsTo( schedDT ); + schedJob->start( static_cast( secondsToRun * 1000 ) ); + } + } + else if( 0 < _interval ) + { + schedJob->start( _interval * 1000 ); + } + + if( schedJob->isActive() ) + { + LogInfo( "[JobScheduler::scheduleJob]", QString( "Job : %1 scheduled to run in %2 seconds ( Date : %3, Time : %4 )" ) + .arg( _job_name ) + .arg( schedJob->remainingTime() / 1000 ) + .arg( QDateTime::currentDateTime().addSecs( schedJob->remainingTime() / 1000 ).date().toString() ) + .arg( QDateTime::currentDateTime().addSecs( schedJob->remainingTime() / 1000 ).time().toString() ) ); + } + else + { + LogError( "[JobScheduler::scheduleJob]", QString( "Job : %1 failed to schedule." ) + .arg( _job_name ) ); + + } +} + +void JobScheduler::rescheduleJob ( const QString& _job_name ) +{ + if( m_jobSchedule.contains( _job_name ) ) + { + QPointer schedJob = m_jobSchedule.value( _job_name ); + if( nullptr == schedJob ) + { + LogInfo( "[JobScheduler::rescheduleJob]", QString( "Job %1 not rescheduled to the an unknown error." ).arg( _job_name ) ); + return; + } + + this->scheduleJob( _job_name, + schedJob->jobData().paramList(), + schedJob->jobData().runInterval(), + schedJob->jobData().targetObject(), + schedJob->jobData().runTime(), + schedJob->jobData().runDate() ); + } + else + { + LogError( "[JobScheduler::scheduleJob]", QString( "Unable to re-schedule job %1 as it is unknown." ).arg( _job_name ) ); + } +} + +void JobScheduler::createJob( const JobData& _jobItem ) +{ + QPointer newJob = new JobTimer( _jobItem, this ); // Create a new job + m_jobSchedule.insert( _jobItem.jobName(), newJob ); // Add to the list + QObject::connect( newJob.data(), &JobTimer::signalRunJob, this, &JobScheduler::slotRunJob ); +} + +void JobScheduler::start() +{ + // Schedule all stored jobs. + for( const QString& _jobName : QStringList( m_jobSchedule.keys() ) ) + { + this->rescheduleJob( _jobName ); + } +} diff --git a/src/jobscheduler.h b/src/jobscheduler.h new file mode 100644 index 0000000..bf34fdc --- /dev/null +++ b/src/jobscheduler.h @@ -0,0 +1,131 @@ +/* **************************************************************************** + * Copyright 2019 Open Systems Development BV * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the "Software"), * + * to deal in the Software without restriction, including without limitation * + * the rights to use, copy, modify, merge, publish, distribute, sublicense, * + * and/or sell copies of the Software, and to permit persons to whom the * + * Software is furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included in * + * all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * + * DEALINGS IN THE SOFTWARE. * + * ***************************************************************************/ + +#ifndef OSDEV_COMPONENTS_JOBSCHEDULER_H +#define OSDEV_COMPONENTS_JOBSCHEDULER_H + +#include "jobdata.h" +#include "jobtimer.h" + +#include +#include +#include +#include +#include + +namespace osdev { +namespace components { +/* + * ________________________________________ + * / Real computer scientists despise the \ + * | idea of actual hardware. Hardware has | + * | limitations, software doesn't. It's a | + * | real shame that Turing machines are so | + * \ poor at I/O. / + * ---------------------------------------- + * \ + * \ + * .--. + * |o_o | + * |:_/ | + * // \ \ + * (| | ) + * /'\_ _/`\ + * \___)=(___/ + *//*! + * \brief Schedule jobs to be executed on a specific Date / Time or on a regular interval. + * At this moment, it will schedule in intervals of 24 hours, if the date is set in the past. + * If the dat is in the future, it will be run for the first time on that specific date / Time + * and after that every 24 hours. + */ +class JobScheduler : public QObject +{ + Q_OBJECT + +public: + /*! + * \brief JobScheduler Constructor. + * \param _parent - The object creating the JobScheduler. + * By adding this pointer, we use the cascade deletion construction that comes with Qt. + */ + JobScheduler( QObject *_parent = nullptr ); + + /*! + * \brief JobScheduler Constructor + * \param lstJobs - The list of jobs, coming from the configuration that we want to have scheduled. + * \param _parent - The object creating the JobScheduler. + * By adding this pointer, we use the cascade deletion construction that comes with Qt. + */ + JobScheduler( const QList < osdev::components::JobData > &lstJobs, QObject * _parent = nullptr ); + + /*! + * \brief Schedule the job based on the parameters and settings. + * \param _job_name - The name of this job used for registration + * \param _param_list - Parameters by the job. + * \param _interval - The interval this job should be scheduled to. + * \param _target_object - The plugin or object this job is intended for. Used as input to the pluginmanager. + * \param _run_time - The time this job should run. Empty or '*' if interval based. + * \param _run_date - The date this job should run. Empty or '*' if daily. + */ + void scheduleJob( const QString& _job_name, + const QHash& _param_list, + const int _interval, + const QString& _target_object, + const QTime& _run_time, + const QDate& _run_date = QDate::currentDate() ); + + /*! + * \brief Added for convenience. It will search for the given name and try to reschedule the job. + */ + void rescheduleJob( const QString& _jobName ); + + /*! + * \brief Start and initialize the jobscheduler. + * All configured Jobs are started and reported to the logfile. + */ + void start(); + +private: + /*! + * \brief Create the requested job and add it to the Schedule list. + * \param _jobItem - Structure containing the data needed for this job. + */ + void createJob( const JobData& _jobItem ); + + QHash> m_jobSchedule; ///< The scheduler list + +private slots: + /*! + * \brief Called by the TimerObjects. It's identification (jobName) is used to determine + * which job has to be run + */ + void slotRunJob( const QString& jobName ); + +signals: + void signalRunJob( const JobData& data ); + +}; + +} /* End namespace components */ +} /* End namespace osdev */ + +#endif /* OSDEV_COMPONENTS_JOBSCHEDULER_H */ diff --git a/src/jobtimer.cpp b/src/jobtimer.cpp new file mode 100644 index 0000000..6181d8a --- /dev/null +++ b/src/jobtimer.cpp @@ -0,0 +1,49 @@ +/* **************************************************************************** + * Copyright 2019 Open Systems Development BV * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the "Software"), * + * to deal in the Software without restriction, including without limitation * + * the rights to use, copy, modify, merge, publish, distribute, sublicense, * + * and/or sell copies of the Software, and to permit persons to whom the * + * Software is furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included in * + * all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * + * DEALINGS IN THE SOFTWARE. * + * ***************************************************************************/ + +#include "jobtimer.h" + +using namespace osdev::components; + +JobTimer::JobTimer( const JobData& _jobData, QObject *_parent ) + : QTimer( _parent ) + , m_jobData( _jobData ) +{ + this->setTimerType( Qt::PreciseTimer ); ///< 1 millisecond accuracy + this->setSingleShot( true ); ///< Fire once. This timer has to be rescheduled. + + connectSignalsSlots(); +} + +JobTimer::~JobTimer() +{ +} + +void JobTimer::connectSignalsSlots() +{ + QObject::connect( this, &QTimer::timeout, this, &JobTimer::slotTimeOut ); +} + +void JobTimer::slotTimeOut() +{ + emit JobTimer::signalRunJob( m_jobData.jobName() ); +} diff --git a/src/jobtimer.h b/src/jobtimer.h new file mode 100644 index 0000000..ceece54 --- /dev/null +++ b/src/jobtimer.h @@ -0,0 +1,100 @@ +/* **************************************************************************** + * Copyright 2019 Open Systems Development BV * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the "Software"), * + * to deal in the Software without restriction, including without limitation * + * the rights to use, copy, modify, merge, publish, distribute, sublicense, * + * and/or sell copies of the Software, and to permit persons to whom the * + * Software is furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included in * + * all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * + * DEALINGS IN THE SOFTWARE. * + * ***************************************************************************/ + +#ifndef OSDEV_COMPONENTS_JOBTIMER_H +#define OSDEV_COMPONENTS_JOBTIMER_H + +#include +#include +#include +#include +#include +#include +#include + +#include "jobdata.h" + +namespace osdev { +namespace components { + +/* ______________________________________ + * / Got a dictionary? I want to know the \ + * \ meaning of life. / + * -------------------------------------- + * \ + * \ + * .--. + * |o_o | + * |:_/ | + * // \ \ + * (| | ) + * /'\_ _/`\ + * \___)=(___/ + *//*! + * \brief Instead of using separate timers, The job *is* the timer. + */ +class JobTimer : public QTimer +{ + Q_OBJECT +public: + /*! + * \brief C'tor taking a jobdata structure to initialize the jobTimer. + */ + JobTimer( const JobData& _jobData, QObject *_parent = nullptr ); + + /*! + * \brief D'tor + */ + virtual ~JobTimer(); + + /*! + * \brief Get the jobData as a structure from the scheduled object. + * \return The data as object. Empty if no data was set. + */ + JobData jobData() const { return m_jobData; } + +private: + /*! + * \brief Connect all internal signals and slots. + */ + void connectSignalsSlots(); + + JobData m_jobData; ///< Structure to hold all jobInformation. + +signals: + /*! + * \brief Send the requested job by its name to all connected libraries. + */ + void signalRunJob( const QString& jobName ); + +private slots: + /*! + * \brief Will be called by the parent object (QTimer) times out. + */ + void slotTimeOut(); + +}; + +} /* End namespace components */ +} /* End namespace osdev */ + +#endif /* OSDEV_COMPONENTS_JOBTIMER_H */ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..3635320 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,30 @@ +cmake_minimum_required(VERSION 3.0) +LIST(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../cmake) + +include(projectheader) +project_header(test_logutils) + +include_directories( SYSTEM + ${CMAKE_CURRENT_SOURCE_DIR}/../../src +) + +include(compiler) +set(SRC_LIST +) + +# add_executable( ${PROJECT_NAME} +# ${SRC_LIST} +# ) + +# target_link_libraries( +# ${PROJECT_NAME} +# ) + +# set_target_properties( ${PROJECT_NAME} PROPERTIES +# RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin +# LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib +# ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/archive +# ) + +# include(installation) +# install_application() -- libgit2 0.21.4