diff --git b/.gitignore a/.gitignore new file mode 100644 index 0000000..0ff047c --- /dev/null +++ a/.gitignore @@ -0,0 +1,2 @@ +build/ +CMakeLists.txt.user diff --git b/CMakeLists.txt a/CMakeLists.txt new file mode 100644 index 0000000..8ee620a --- /dev/null +++ a/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_global) + +add_subdirectory(src) +add_subdirectory(tests) + +# include(packaging) +# package_component() diff --git b/README.md a/README.md new file mode 100644 index 0000000..e69de29 --- /dev/null +++ a/README.md diff --git b/src/CMakeLists.txt a/src/CMakeLists.txt new file mode 100644 index 0000000..ddf4e77 --- /dev/null +++ a/src/CMakeLists.txt @@ -0,0 +1,51 @@ +cmake_minimum_required(VERSION 3.0) +LIST(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake) +include(projectheader) +project_header(global) + +find_package( Qt5Core REQUIRED ) + +include_directories( SYSTEM + ${Qt5Core_INCLUDE_DIRS} + ${Qt5Core_PRIVATE_INCLUDE_DIRS} +) + +include(compiler) + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR}/../pugixml + ${CMAKE_CURRENT_SOURCE_DIR}/../config + ${CMAKE_CURRENT_SOURCE_DIR}/../logutils + ${CMAKE_CURRENT_SOURCE_DIR}/../interfaces +) + +set(SRC_LIST + ${CMAKE_CURRENT_SOURCE_DIR}/argumentparserbase.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/systeminfo.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/plugin.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/pluginmanager.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/conversionutils.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/timeutils.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/threadmon.cpp +) + +include(qtmoc) +create_mocs( SRC_LIST MOC_LIST + ${CMAKE_CURRENT_SOURCE_DIR}/pluginmanager.h +) + +link_directories( + ${CMAKE_BINARY_DIR}/lib +) + +include(library) +add_libraries( + ${Qt5Core_LIBRARIES} + logutils + config + interfaces + pugixml +) + +include(installation) +install_component() diff --git b/src/argumentparserbase.cpp a/src/argumentparserbase.cpp new file mode 100644 index 0000000..d13e247 --- /dev/null +++ a/src/argumentparserbase.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. * + * ***************************************************************************/ +// osdev::caelus +#include "argumentparserbase.h" + +using namespace osdev::components; + +ArgumentParserBase::ArgumentParserBase( const QStringList& arguments ) + : m_argument_list( arguments ) +{ +} + +ArgumentParserBase::~ArgumentParserBase() = default; + +void ArgumentParserBase::setArgumentList( const QStringList &arg_list ) +{ + m_argument_list = arg_list; +} + +QString ArgumentParserBase::getArgumentValue( const QString &argument_switch ) const +{ + QString l_result = QString(); + + if( 1 == m_argument_list.count( argument_switch ) ) + { + l_result = m_argument_list.at( m_argument_list.indexOf( argument_switch ) + 1 ); + } + + return l_result; +} diff --git b/src/argumentparserbase.h a/src/argumentparserbase.h new file mode 100644 index 0000000..6805988 --- /dev/null +++ a/src/argumentparserbase.h @@ -0,0 +1,47 @@ +/* **************************************************************************** + * 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_ARGUMENTPARSERBASE_H +#define OSDEV_COMPONENTS_ARGUMENTPARSERBASE_H + +#include +#include + +namespace osdev { +namespace components { + +class ArgumentParserBase +{ +public: + ArgumentParserBase(const QStringList& arguments = QStringList()); + virtual ~ArgumentParserBase(); + + void setArgumentList(const QStringList& arg_list); + QString getArgumentValue(const QString& argument_switch) const; + +private: + QStringList m_argument_list; +}; + +} /* End namespace components */ +} /* End namespace osdev */ + +#endif /* OSDEV_COMPONENTS_ARGUMENTPARSERBASE_H */ diff --git b/src/compat-c++14.h a/src/compat-c++14.h new file mode 100644 index 0000000..d28620a --- /dev/null +++ a/src/compat-c++14.h @@ -0,0 +1,74 @@ +/* **************************************************************************** + * 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_COMPATCXX14 +#define OSDEV_COMPONENTS_COMPATCXX14 + +#include + +// The code below must be skipped if we use a C++ 14 or newer compiler +#if __cplusplus == 201103L + +namespace std +{ + +/// Copied from libstdc++ 4.9.2 bits/unique_ptr.h +template +struct _MakeUniq +{ + typedef unique_ptr<_Tp> __single_object; +}; + +template +struct _MakeUniq<_Tp[]> +{ + typedef unique_ptr<_Tp> __array; +}; + +template +struct _MakeUniq<_Tp[_Bound]> +{ + struct __invalid_type { }; +}; + +/// std::make_unique for single objects +template +inline typename _MakeUniq<_Tp>::__single_object make_unique(_Args&&... __args) +{ + return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); +} + +/// std::make_unique for arrays of unknown bound +template +inline typename _MakeUniq<_Tp>::__array make_unique(size_t __num) +{ + return unique_ptr<_Tp>(new typename remove_extent<_Tp>::type[__num]()); +} + +/// Disable std::make_unique for arrays of known bound +template +inline typename _MakeUniq<_Tp>::__invalid_type make_unique(_Args&&...) = delete; + +} /* End namespace std */ + +#endif /* End check for c++ 14 */ + +#endif /* OSDEV_COMPONENTS_COMPATCXX14 */ diff --git b/src/conversionutils.cpp a/src/conversionutils.cpp new file mode 100644 index 0000000..3b8e6e5 --- /dev/null +++ a/src/conversionutils.cpp @@ -0,0 +1,180 @@ +/* **************************************************************************** + * 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 "conversionutils.h" + +using namespace osdev::components; + +namespace +{ + +QHash gQHTypes( + { + { "UNKNOWN", QVariant::Invalid }, + { "BITARRAY", QVariant::BitArray }, + { "BITMAP", QVariant::Bitmap }, + { "BOOL", QVariant::Bool }, + { "BRUSH", QVariant::Brush }, + { "BYTEARRAY", QVariant::ByteArray }, + { "CHAR", QVariant::Char }, + { "COLOR", QVariant::Color }, + { "CURSOR", QVariant::Cursor }, + { "DATE", QVariant::Date }, + { "DATETIME", QVariant::DateTime }, + { "DOUBLE", QVariant::Double }, + { "EASINGCURVE", QVariant::EasingCurve }, + { "UUID", QVariant::Uuid }, + { "MODELINDEX", QVariant::ModelIndex }, + { "FONT", QVariant::Font }, + { "HASH", QVariant::Hash }, + { "ICON", QVariant::Icon }, + { "IMAGE", QVariant::Image }, + { "INT", QVariant::Int }, + { "SMALLINT", QVariant::Int }, + { "KEYSEQUENCE", QVariant::KeySequence }, + { "LINE", QVariant::Line }, + { "LINEF", QVariant::LineF }, + { "LIST", QVariant::List }, + { "LOCALE", QVariant::Locale }, + { "LONGLONG", QVariant::LongLong }, + { "MAP", QVariant::Map }, + { "MATRIX", QVariant::Matrix }, + { "TRANSFORM", QVariant::Transform }, + { "MATRIX4X4", QVariant::Matrix4x4 }, + { "PALETTE", QVariant::Palette }, + { "PEN", QVariant::Pen }, + { "PIXMAP", QVariant::Pixmap }, + { "POINT", QVariant::Point }, + { "POINTF", QVariant::PointF }, + { "POLYGON", QVariant::Polygon }, + { "POLYGONF", QVariant::PolygonF }, + { "QUATERNION", QVariant::Quaternion }, + { "RECT", QVariant::Rect }, + { "RECTF", QVariant::RectF }, + { "REGEXP", QVariant::RegExp }, + { "REGULAREXPRESSION", QVariant::RegularExpression }, + { "REGION", QVariant::Region }, + { "SIZE", QVariant::Size }, + { "SIZEF", QVariant::SizeF }, + { "SIZEPOLICY", QVariant::SizePolicy }, + { "STRING", QVariant::String }, + { "STRINGLIST", QVariant::StringList }, + { "TEXTFORMAT", QVariant::TextFormat }, + { "TEXTLENGTH", QVariant::TextLength }, + { "TIME", QVariant::Time }, + { "UINT", QVariant::UInt }, + { "ULONGLONG", QVariant::ULongLong }, + { "URL", QVariant::Url }, + { "VECTOR2D", QVariant::Vector2D }, + { "VECTOR3D", QVariant::Vector3D }, + { "VECTOR4D", QVariant::Vector4D }, + { "USERTYPE", QVariant::UserType }, + + // PostGreSQL Datatypes, also aliases for historical purposes + + { "BIGINT", QVariant::Int }, + { "INT8", QVariant::Int }, + { "BIGSERIAL", QVariant::Int }, + { "SERIAL8", QVariant::Int }, + { "BIT", QVariant::String }, + { "BIT VARYING", QVariant::String }, + { "VARBIT", QVariant::String }, + { "BOOLEAN", QVariant::Bool }, + { "BYTEA", QVariant::String }, + { "CHARACTER", QVariant::String }, + { "CHAR", QVariant::String }, + { "CHARACTER VARYING", QVariant::String }, + { "CIDR", QVariant::String }, + { "DATE", QVariant::Date }, + { "DOUBLE PRECISION", QVariant::Double }, + { "FLOAT8", QVariant::Double }, + { "INET", QVariant::String }, + { "INTEGER", QVariant::Int }, + { "INT4", QVariant::Int }, + { "JSON", QVariant::String }, + { "MACADDR", QVariant::String }, + { "REAL", QVariant::Double }, + { "FLOAT4", QVariant::Double }, + { "INT2", QVariant::Int }, + { "SMALLSERIAL", QVariant::Int }, + { "SERIAL2", QVariant::Int }, + { "SERIAL", QVariant::Int }, + { "SERIAL4", QVariant::Int }, + { "TEXT", QVariant::String }, + { "TIME", QVariant::Time }, + { "TIMESTAMP", QVariant::DateTime }, + { "TIMESTAMP WITH TIME ZONE", QVariant::DateTime }, + { "TIMESTAMPTZ", QVariant::DateTime }, + { "TSQUERY", QVariant::String }, + { "UUID", QVariant::Uuid }, + { "XML", QVariant::String } + }); + +} // anonymous + +// static +QVariant::Type ConversionUtils::stringToQvarType( const QString& sValueType ) +{ + return gQHTypes.value( sValueType.toUpper() ); +} + +// static +QStringList ConversionUtils::getTypes() +{ + return QStringList( gQHTypes.keys() ); +} + +// static +QVariant ConversionUtils::convertToType( const QVariant &varValue, QVariant::Type varType ) +{ + QVariant varResult = varValue; + + if( varValue.type() == QVariant::Bool && varType == QVariant::String ) + { + if( varValue.toBool() ) + { + varResult = QVariant( QString( "1" ) ); + } + else + { + varResult = QVariant( QString( "0" ) ); + } + } + else if( varValue.type() == QVariant::Bool && varType == QVariant::Int ) + { + if( varValue.toBool() ) + { + varResult = QVariant( 1 ); + } + else + { + varResult = QVariant( 0 ); + } + } + + return varResult; +} + +// static +QVariant ConversionUtils::convertToType(const QVariant &varValue, const QString &varType ) +{ + return convertToType( varValue, stringToQvarType( varType ) ); +} diff --git b/src/conversionutils.h a/src/conversionutils.h new file mode 100644 index 0000000..f0bb945 --- /dev/null +++ a/src/conversionutils.h @@ -0,0 +1,61 @@ +/* **************************************************************************** + * 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_CONVERSIONUTILS_H +#define OSDEV_COMPONENTS_CONVERSIONUTILS_H + +#include +#include +#include +#include + +namespace osdev { +namespace components { + +/*! + * \brief The ConversionUtils class converts an string expression to a QVariant Type. + * The modelmapper is build from a configurationfile and fieldtypes are given in strings + * By mapping those string expressions to the corresponding QVariant Type, we ensure the + * data is handled correctly. + * + * The number of types is *everything* mentioned in to Qt-documentation although + * it is doubtful we'll ever use everything. + * + * Instead of using the nameToType method of QVariant, we did our own translation table, + * making it possible to use Database types or any type whatsoever. + */ + +class ConversionUtils +{ +public: + ConversionUtils() = delete; + + static QVariant::Type stringToQvarType( const QString& sValueType ); + static QStringList getTypes(); + + static QVariant convertToType( const QVariant &varValue, QVariant::Type varType ); + static QVariant convertToType( const QVariant &varValue, const QString& varType ); +}; + +} /* End namespace components */ +} /* End namespace osdev */ + +#endif /* OSDEV_COMPONENTS_CONVERSIONUTILS_H */ diff --git b/src/globallibexport.h a/src/globallibexport.h new file mode 100644 index 0000000..a9a912a --- /dev/null +++ a/src/globallibexport.h @@ -0,0 +1,38 @@ +/* **************************************************************************** + * 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_GLOBAL_LIBEXPORT_H +#define OSDEV_COMPONENTS_GLOBAL_LIBEXPORT_H + +#ifdef WIN32 + +#ifdef GLOBALLIB +#define GLOBALLIBINTERFACE __declspec(dllexport) +#else +#define GLOBALLIBINTERFACE __declspec(dllimport) +#endif + +#else +#define GLOBALLIBINTERFACE +#endif + + +#endif // OSDEV_COMPONENTS_GLOBAL_LIBEXPORT_H diff --git b/src/lockguard.h a/src/lockguard.h new file mode 100644 index 0000000..e356f29 --- /dev/null +++ a/src/lockguard.h @@ -0,0 +1,40 @@ +/* **************************************************************************** + * 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 MLOGIC_COMMON_LOCKGUARD_H +#define MLOGIC_COMMON_LOCKGUARD_H + +// std +#include + +// mlogic::common +#include "mlogic/common/utils.h" + +#define MLOGIC_COMMON_LOCKGUARD(mutexVariableName) \ + std::lock_guard Lock__Guard__##mutexVariableName##__(mutexVariableName); \ + mlogic::common::apply_unused_parameters(Lock__Guard__##mutexVariableName##__); + +#define MLOGIC_COMMON_RECURSIVELOCKGUARD(mutexVariableName) \ + std::lock_guard Lock__Guard__##mutexVariableName##__(mutexVariableName); \ + mlogic::common::apply_unused_parameters(Lock__Guard__##mutexVariableName##__); + +#endif // MLOGIC_COMMON_LOCKGUARD_H + diff --git b/src/plugin.cpp a/src/plugin.cpp new file mode 100644 index 0000000..12ddeed --- /dev/null +++ a/src/plugin.cpp @@ -0,0 +1,67 @@ +/* **************************************************************************** + * 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 "plugin.h" + +namespace osdev { +namespace components { + +Plugin::Plugin( const QString& pluginName, const QString& pluginFile, const QString& pluginPath, + const QString& pluginConfig, const QUuid& pluginUuid, + QObject* ptr_plugin ) + : m_pluginName( pluginName ) + , m_pluginFile( pluginFile ) + , m_pluginPath( pluginPath ) + , m_pluginConfigurationFile( pluginConfig ) + , m_pluginUuid( pluginUuid ) + , m_plugin( ptr_plugin ) +{ +} + +Plugin::Plugin( const Plugin& other ) + : Plugin(other.name(), other.fileName(), other.path(), other.config(), other.uuid(), other.plugin()) +{ +} + +Plugin& Plugin::operator=( const Plugin& other ) +{ + if(this != &other) { + m_pluginName = other.name(); + m_pluginFile = other.fileName(); + m_pluginPath = other.path(); + m_pluginConfigurationFile = other.config(); + m_pluginUuid = other.uuid(); + m_plugin = other.plugin(); + } + return *this; +} + +QString Plugin::asString() +{ + QString PluginData = QString( "[PluginName = %1] [PluginFile = %2] [PluginPath = %3] [PluginConfigFile = %4] [PluginUUId = %5]" ) + .arg( m_pluginName ).arg( m_pluginFile ).arg( m_pluginPath ).arg( m_pluginConfigurationFile ).arg( m_pluginUuid.toString() ); + + return PluginData; +} + +} // End namespace components +} // End namespace osdev + diff --git b/src/plugin.h a/src/plugin.h new file mode 100644 index 0000000..a8b8e90 --- /dev/null +++ a/src/plugin.h @@ -0,0 +1,152 @@ +/* **************************************************************************** + * 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_PLUGIN_H +#define OSDEV_COMPONENTS_PLUGIN_H + +#include +#include + +class QObject; + +namespace osdev { +namespace components { + +/*! + * \brief The Plugin class is a structure representing a single plugin. + * It is used internally by the Pluginmanager and holds all information + * needed. + *//* + * _______________________________________ + * / Heuristics are bug ridden by \ + * | definition. If they didn't have bugs, | + * \ then they'd be algorithms. / + * --------------------------------------- + * \ + * \ + * .--. + * |o_o | + * |:_/ | + * // \ \ + * (| | ) + * /'\_ _/`\ + * \___)=(___/ + * + */ + +class Plugin +{ +public: + //! + /** + * @brief Constructor + * @param pluginName Name of the plugin + * @param pluginPath Path to the plugin + * @param pluginConfig Configuration file for the plugin + * @param pluginUuid UUID for the plugin + * @param ptr_plugin Plugin instance + */ + Plugin(const QString& pluginName = QString(), + const QString& pluginFile = QString(), + const QString& pluginPath = QString(), + const QString& pluginConfig = QString(), + const QUuid& pluginUuid = QUuid(), + QObject* ptr_plugin = nullptr ); + + /** + * @brief Copy-constructor + * @param other Plugin to copy from + */ + Plugin(const Plugin& other); + + /** + * @brief Assignment operator + * @param other Plugin to copy from + * @return Reference to this + */ + Plugin& operator=(const Plugin& other); + + /*** Getters and Setters ***/ + //! @returns Name of the plugin ( like : libplugin_myplugin ). + QString name() const { return m_pluginName; } + + //! @returns Path to the plugin. + QString path() const { return m_pluginPath; } + + //! @returns the filename of the plugin. + QString fileName() const { return m_pluginFile; } + + //! @returns Full pathname to the plugin specific configurationfile. + QString config() const { return m_pluginConfigurationFile; } + + //! @returns Unique Identifier of the plugin. + QUuid uuid() const { return m_pluginUuid; } + + //! @returns Pointer to the plugin-instance as a QObject. + QObject* plugin() const { return m_plugin; } + + //! Sets the name of the plugin. Make sure to omit the extension. + //! @param pluginName Name of the plugin + void setName( const QString& pluginName ) { m_pluginName = pluginName; } + + //! Sets the filename of the plugin. Make sure we omit the extension. + //! @param pluginFile Filename of the plugin. + void setFileName( const QString &fileName ) { m_pluginFile = fileName; } + + //! Sets the path to the plugin. + //! @param pluginPath Path to the plugin + //! + //! PluginManager uses only one pluginpath, but it was added for future use. + void setPath( const QString& pluginPath ) { m_pluginPath = pluginPath; } + + //! Sets the full pathname and name of the plugin specific configuration file + //! @param pluginConfig Configuration file for the plugin + void setConfig( const QString& pluginConfig ) { m_pluginConfigurationFile = pluginConfig; } + + /*! Sets the Unique Identifier of the specific plugin. + * + * If the plugin is not yet loaded, its value is + * {00000000-0000-0000-0000-000000000000} ( or isNull is true ). If a plugin + * is loaded, its value is changed with the value read from the pluginID. + * + * @param pluginUuid UUID for the plugin + */ + void setUuid( const QUuid& pluginUuid ) { m_pluginUuid = pluginUuid; } + + //! Sets the pointer to the plugin-instance. + //! @param ptr_plugin Instance pointer + void setPlugin( QObject* ptr_plugin ) { m_plugin = ptr_plugin; } + + QString asString(); + +private: + QString m_pluginName; ///< Name of the plugin + QString m_pluginFile; ///< Filename of the plugin + QString m_pluginPath; ///< Full path to the plugin + QString m_pluginConfigurationFile; ///< Full path to the configuration file + QUuid m_pluginUuid; ///< Plugin UUID + QObject* m_plugin; ///< Plugin implementation +}; + +} // End namespace components +} // End namespace osdev + +#endif // OSDEV_COMPONENTS_PLUGIN_H diff --git b/src/pluginmanager.cpp a/src/pluginmanager.cpp new file mode 100644 index 0000000..142238e --- /dev/null +++ a/src/pluginmanager.cpp @@ -0,0 +1,347 @@ +/* **************************************************************************** + * 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 "pluginmanager.h" + +#include +#include +#include + +#include "log.h" +#include "dcxmlconfig.h" +#include "iplugin.h" + +#include + +namespace osdev { +namespace components { + +using namespace osdev::caelus; + +std::unique_ptr PluginManager::s_instance( nullptr ); + + +PluginManager& PluginManager::Instance() +{ + if ( nullptr == s_instance ) + { + s_instance = std::unique_ptr( new PluginManager() ); + } + + return *s_instance; +} + +bool PluginManager::addLibrary( const QString& pluginName ) +{ + bool bResult = false; + + if( m_pluginHash.contains( pluginName ) ) + { + bResult = false; + } + else + { + Plugin* l_plugin = new Plugin( pluginName ); + if( nullptr != l_plugin ) + { + m_pluginHash.insert( pluginName, l_plugin ); + bResult = true; + + LogInfo( m_className, QString( "Library : %1 was added to the library list." ).arg( pluginName ) ) + } + } + return bResult; +} + +bool PluginManager::loadPlugin(const QString& pluginName) +{ + bool bStatus = false; + + LogInfo( m_className, QString( "Load plugin %1" ).arg( pluginName ) ) + + QPluginLoader loader( pluginName ); + QObject *plugin = loader.instance(); + if ( plugin ) + { + LogInfo( m_className, "plugin was loaded..." ) + IPlugin *iPlugin = qobject_cast( plugin ); + if ( iPlugin ) + { + LogInfo( m_className, QString( "%1 implements the IPlugin interface.." ).arg( pluginName ) ) + + // Call initialization function on plugin + iPlugin->initialise(); + + // Get the path of the just loaded plugin + QString pluginPath = QFileInfo(loader.fileName()).path(); + + LogInfo( m_className, QString("Plugin name : %1").arg( iPlugin->getName() ) ) + LogInfo( m_className, QString("Plugin uuid : %1").arg( iPlugin->getId().toString() ) ) + LogInfo( m_className, QString("Plugin description : %1").arg( iPlugin->getDescription() ) ) + LogInfo( m_className, QString("Plugin path : %1").arg( pluginPath ) ) + + // Set the created id to the pluginHash. + Plugin *ptrPlugin = m_pluginHash.value( pluginName, nullptr ); + if ( ptrPlugin ) + { // Retrieve the correct pointer and adjust the values. + ptrPlugin->setName( iPlugin->getName() ); + ptrPlugin->setFileName( pluginName ); + ptrPlugin->setUuid( iPlugin->getId() ); + ptrPlugin->setPath( pluginPath ); + ptrPlugin->setPlugin( plugin ); + } + else + { // The plugin just loaded doesn't exist. Create it and add it to the hash. + ptrPlugin = new Plugin( iPlugin->getName(), pluginName, pluginPath, QString(), iPlugin->getId(), plugin ); + m_pluginHash.insert(iPlugin->getName(), ptrPlugin); + } + // Load successfull + bStatus = true; + + } + else + { + LogError( m_className, QString( "Ignoring plugin %1 because it does not support the IPlugin interface." ).arg( pluginName ) ) + } + } + else + { + LogError( m_className, QString( "Loading of plugin %1 failed....." ).arg( pluginName ) ) + LogError( m_className, QString( "PluginLoader reported : %1" ).arg( loader.errorString() ) ) + LogError( m_className, QString( "LibraryPaths : %1 " ).arg( QCoreApplication::libraryPaths().join( "\n" ) ) ) + } + return bStatus; +} + +bool PluginManager::loadPlugins(const QStringList& pluginNames) +{ + bool bStatus = false; + + LogDebug( m_className, QString("Adding %1 to the Hash.").arg( pluginNames.join(" ") ) ) + buildLibraryList(); + + LogDebug( m_className, QString("Looking for plugins in : %1").arg( QCoreApplication::libraryPaths().join(":") ) ) + for( const QString& pluginName : pluginNames ) + { + bStatus &= loadPlugin( pluginName ); + } + + return bStatus; +} + +bool PluginManager::loadPlugins() +{ + bool bStatus = false; + + auto l_pluginNames = m_pluginHash.keys(); + for( const QString& l_pluginName : l_pluginNames ) + { + bStatus &= loadPlugin( l_pluginName ); + } + + return bStatus; +} + +bool PluginManager::unloadPlugin( const QString& pluginName ) +{ + bool bStatus = false; + + QPluginLoader loader( pluginName ); + if ( loader.unload() ) + { + LogInfo(m_className, QString("Plugin %1 successfully unloaded.").arg(pluginName)) + LogInfo(m_className, QString("Removing Plugin %1 form the hashtable.").arg(pluginName)) + Plugin *ptr_plugin = m_pluginHash.take( pluginName ); + delete ptr_plugin; + bStatus = true; + } + else + { + LogError( m_className, QString("Unloading of plugin %1 failed.").arg(pluginName) ) + LogError( m_className, QString("Last PluginError : %1").arg(loader.errorString() ) ) + } + return bStatus; +} + +void PluginManager::addLibraryPaths(const QStringList& paths) +{ + for( const QString& libPath : paths ) + { + QCoreApplication::addLibraryPath( libPath ); + } +} + +void PluginManager::addLibraryPath(const QString& path) +{ + QCoreApplication::addLibraryPath( path ); +} + +QObject* PluginManager::getPlugin(const QUuid &id) const +{ + QObject *l_plugin = nullptr; + + for(auto it = m_pluginHash.begin(); it != m_pluginHash.end(); ++it) + { + if ( id == it.value()->uuid() ) + { + l_plugin = it.value()->plugin(); + } + } + + return l_plugin; +} + +QList PluginManager::getPlugins(const QString& i_interface) const +{ + QList l_pObjectList; + + for(auto it = m_pluginHash.begin(); it != m_pluginHash.end(); ++it ) + { + QObject *l_plugin = it.value()->plugin(); + if( l_plugin && l_plugin->qt_metacast( i_interface.toUtf8().data() ) ) + { + // We've found a plugin with this interface + l_pObjectList.push_back( l_plugin ); + } + } + + return l_pObjectList; +} + +PluginManager::PluginManager() + : m_pluginHash() + , m_libraryList() + , m_className("PluginManager :: ") +{ + QCoreApplication::addLibraryPath( "." ); +} + +void PluginManager::buildLibraryList() +{ + // Get the config object and get the plugins and librarypaths... + DCXmlConfig& l_config = DCXmlConfig::Instance(); + + // Get all the plugins and create their representing objects.. + QStringList l_plugins = l_config.getPlugins(); + for(const QString& pluginName : l_plugins) + { + Plugin* plugin = new Plugin( pluginName ); + if (nullptr != plugin) + { + m_pluginHash.insert(pluginName, plugin); + qDebug() << m_pluginHash; + } + } +} + +QString PluginManager::getLibrary( const QString& pluginName ) const +{ + /// @TODO this should find the actual file name corresponding to the plugin. QFileInfo should be constructed with the actual filename. + /// We are looking for that name so this is not working as intended. + LogDebug( m_className, QString( "Plugin Name looking for : %1" ).arg( pluginName ) ) + for( const QString& library : m_pluginHash.keys() ) + { + LogDebug( m_className, QString( "Library = %1" ).arg( library ) ) + QFileInfo info( library ); + LogDebug( m_className, QString( "Library base of : %1" ).arg( info.baseName() ) ) + if ( pluginName == info.baseName() ) + { // First found can be returned + return library; + } + } + // Nothing found + return QString(); +} + +bool PluginManager::isLoaded( const QString& pluginName ) const +{ + return m_pluginHash.contains( pluginName ); +} + +QUuid PluginManager::getPluginId( const QString& pluginName ) const +{ + if( isLoaded( pluginName ) ) + { + return m_pluginHash.value( pluginName )->uuid(); + } + return QUuid(); +} + +QUuid PluginManager::getPluginIdByInterfaceId( const QString &interface_id ) +{ + for(auto it = m_pluginHash.begin(); it != m_pluginHash.end(); ++it ) + { + QObject *l_plugin = it.value()->plugin(); + if( l_plugin && l_plugin->qt_metacast( interface_id.toUtf8().data() ) ) + { + // We've found a plugin with this interface + IPlugin *iPlugin = qobject_cast( it.value()->plugin() ); + if( iPlugin ) + { + return iPlugin->getId(); + } + else + LogInfo( "[PluginManager::getPluginIdByInterfaceId]", QString( "No plugin found with interface : " + interface_id ) ); + } + } + return QUuid(); +} + +QString PluginManager::getPluginNameByUuid( const QUuid &uuid ) +{ + for( const auto& key : m_pluginHash.keys() ) + { + Plugin *ptr_plugin = m_pluginHash.value( key, nullptr ); + if( nullptr != ptr_plugin ) + { + if( ptr_plugin->uuid() == uuid ) + { + return ptr_plugin->name(); + } + } + } + return QString(); +} + +QUuid PluginManager::getPluginUuidByName( const QString &name ) +{ + for( const auto& key : m_pluginHash.keys() ) + { + Plugin *ptr_plugin = m_pluginHash.value( key, nullptr ); + if( nullptr != ptr_plugin ) + { + if( ptr_plugin->name() == name ) + { + return ptr_plugin->uuid(); + } + } + } + return QUuid(); +} + +void PluginManager::slotConfigChanged( const QString& fileName ) +{ + LogInfo(m_className, + QString( "Configurationfile %1 was changed. Reread the configuration and plugins." ).arg( fileName ) ) +} + +} // End namespace components +} // End namespace osdev diff --git b/src/pluginmanager.h a/src/pluginmanager.h new file mode 100644 index 0000000..65864e5 --- /dev/null +++ a/src/pluginmanager.h @@ -0,0 +1,205 @@ +/* **************************************************************************** + * 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_PLUGINMANAGER_H +#define OSDEV_COMPONENTS_PLUGINMANAGER_H + +#include +#include +#include +#include +#include + +#include "plugin.h" + +#include "globallibexport.h" + +#include + +namespace osdev { +namespace components { + +/** + * \brief This component is responsible for loading plugins. + * + * It also has support for supplying interfaces on the loaded pluins. The plugin + * manager is a singleton component. + *//* + * ________________________________________ + * / One of the signs of Napoleon's \ + * | greatness is the fact that he once had | + * | a publisher shot. | + * | | + * \ -- Siegfried Unseld / + * ---------------------------------------- + * \ + * \ + * .--. + * |o_o | + * |:_/ | + * // \ \ + * (| | ) + * /'\_ _/`\ + * \___)=(___/ + * + */ +class GLOBALLIBINTERFACE PluginManager : public QObject +{ + Q_OBJECT + +public: + //! Constructs the plugin manager + static PluginManager& Instance(); + + /// Deleted copy-constructor + PluginManager( const PluginManager& ) = delete; + /// Deleted assignment operator + PluginManager& operator=(const PluginManager&) = delete; + /// Deleted move-constructor + PluginManager( PluginManager&& ) = delete; + /// Deleted move operator + PluginManager& operator=( PluginManager&& ) = delete; + + //! Adds a plugin not listed in the configuration. + bool addLibrary( const QString& pluginName ); + + //! Load the plugin by its name and location + bool loadPlugin(const QString& pluginName); + + //! Loads a list of plugins. Names are resolved against the paths added with addLibraryPaths(). + bool loadPlugins(const QStringList& pluginNames); + + //! Load all plugins set in the staging table. + bool loadPlugins(); + + //! Unloads a plugin and removes it from the manager + bool unloadPlugin( const QString& pluginName ); + + //! Specify where the plugin manager will look for plugins + void addLibraryPaths(const QStringList& paths); + + //! Specify a single plugin path + void addLibraryPath(const QString& path); + + //! Retrieve a loaded plugin with its object ID. + QObject* getPlugin(const QUuid &id) const; + + //! Retrieve all objects that have the specified interface. + QList getPlugins(const QString& i_interface) const; + + //! Check if a specific plugin was already loaded... + bool isLoaded( const QString& pluginName ) const; + + //! Retrieve the uuid of the given plugin by its filename. + QUuid getPluginId( const QString& pluginName ) const; + + //! Retrieve the uuid of the given plugin by its Interface_id + QUuid getPluginIdByInterfaceId( const QString &interface_id ); + + //! Retrieve the name of the given plugin by its uuid + QString getPluginNameByUuid( const QUuid &uuid ); + + //! Retrieve the plugin_id by its systemname. + QUuid getPluginUuidByName( const QString &name ); + + /** + * @brief Locate the interface with the specified name + * @tparam T Type of interface needed + * @param i_interface Name of the interface + * @return Interface implementation, or nullptr if no valid interface could + * be found + */ + template + T* queryInterface(const QString& i_interface); + +public slots: + /** + * @brief Slot called when a configuration file changed + * @param fileName Name of the changed file + * @todo Implement me! + */ + void slotConfigChanged( const QString& fileName ); + +private: + + //! Constructs the plugin manager (CTor) + PluginManager(); + + /** + * @brief Get all the plugins and create their representing objects + */ + void buildLibraryList(); + + /** + * @brief Find the library associated with a plugin-name + * @param pluginName Plugin name to look for + * @return Library-name, or an empty string if no library was found + */ + QString getLibrary(const QString& pluginName) const; + + // ------------------------------------------------------ + + //! Contains the only instance of a Pluginmanager + static std::unique_ptr s_instance; + + //! Hash table of all plugins. Loaded or not... + QHash m_pluginHash; + + //! List of all possible libraries that may be loaded by the PM.... + QStringList m_libraryList; + + //! Member holding the classname. + QString m_className; +}; + +// ------------------------------------------------------ + +template +T* PluginManager::queryInterface(const QString& i_interface) +{ + // Hash used to store queried interfaces + static QHash ifaceCache; + + T* pInterface = nullptr; + + if ( ifaceCache.contains(i_interface) ) + { + pInterface = ifaceCache[i_interface]; + } + else + { + QList pPluginList = PluginManager::Instance().getPlugins( i_interface ); + if ( !pPluginList.isEmpty() ) + { + // Return the first plugin with the wanted interface. + pInterface = qobject_cast(pPluginList[0]); + /// @todo What if we specify the wrong T for this plugin? + Q_ASSERT(pInterface); + ifaceCache.insert(i_interface, pInterface); + } + } + return pInterface; +} + +} // End namespace components +} // End namespace osdev + +#endif // OSDEV_COMPONENTS_PLUGINMANAGER_H diff --git b/src/systeminfo.cpp a/src/systeminfo.cpp new file mode 100644 index 0000000..56fc1d9 --- /dev/null +++ a/src/systeminfo.cpp @@ -0,0 +1,129 @@ +/* **************************************************************************** + * 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 "systeminfo.h" +#include "log.h" + +#include + +using namespace osdev::components; + +// The only instance of the singleton system info. +std::unique_ptr SystemInfo::s_pInstance(nullptr); + +// The configuration directory. +static const QString qsConfigDir = "config/"; +static const QString qsResourceDir = "resource/"; + +static const QString qsDynaBuilderSystemPluginConfig; +static const QString qsDynaBuilderUiPluginConfig; +static const QString qsDynaBuilderBackendPluginConfig; + + +SystemInfo::SystemInfo() + : m_qsApplicationPath() + , m_qsExecutablePath(QDir::currentPath()) +{ +} + +SystemInfo::~SystemInfo() +{ +} + +SystemInfo& SystemInfo::Instance() +{ + // Is it the first call? + if (nullptr == s_pInstance) + { + // Create sole instance + s_pInstance.reset(new SystemInfo()); + } + + // Return the address of sole instance + return *s_pInstance.get(); +} + +void SystemInfo::destroyInstance() +{ + s_pInstance.reset(); +} + +void SystemInfo::setApplicationPath(const QString& qsName) +{ + QDir dir( qsName ); + + m_qsApplicationPath = dir.absolutePath(); + + LogInfo("SystemInfo::setApplicationPath", + "ApplicationPath before :: " + m_qsApplicationPath); + + // Remove appl name. + int lSlashPosition = m_qsApplicationPath.lastIndexOf ( '/' ); + + // And platform path. + // lSlashPosition = m_qsApplicationPath.lastIndexOf ( '/', lSlashPosition - 1); + m_qsApplicationPath = m_qsApplicationPath.left( lSlashPosition + 1 ); + + QString strBin = "bin"; + + m_qsApplicationPath = m_qsApplicationPath.left( m_qsApplicationPath.lastIndexOf( strBin ) ); + + LogInfo("SystemInfo::setApplicationPath", + "ApplicationPath after :: " + m_qsApplicationPath); + + /// @todo The application can be started via the PATH variable. This path + /// should be prepended to the path. +} + +QString SystemInfo::getApplicationPath() const +{ + return m_qsApplicationPath; +} + +QString SystemInfo::getExecutablePath() const +{ + return m_qsExecutablePath; +} + +QString SystemInfo::getResourcePath() const +{ + return getApplicationPath() + qsResourceDir; +} + +QString SystemInfo::getConfigurationPath() const +{ + return getApplicationPath() + qsConfigDir; +} + +QString SystemInfo::getConfigFile(ConfigFile fileType) const +{ + switch(fileType) + { + case ConfigFile::System: + return getApplicationPath() + qsConfigDir + qsDynaBuilderSystemPluginConfig; + case ConfigFile::UI: + return getApplicationPath() + qsConfigDir + qsDynaBuilderUiPluginConfig; + case ConfigFile::Backend: + return getApplicationPath() + qsConfigDir + qsDynaBuilderBackendPluginConfig; + } + Q_ASSERT(0 && "Unknown configuration file type"); + return QString(); +} diff --git b/src/systeminfo.h a/src/systeminfo.h new file mode 100644 index 0000000..af45b8a --- /dev/null +++ a/src/systeminfo.h @@ -0,0 +1,104 @@ +/* **************************************************************************** + * 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_SYSTEMINFO_H +#define OSDEV_COMPONENTS_SYSTEMINFO_H + +#include "globallibexport.h" + +#include +#include + +namespace osdev { +namespace components { + +/** + * @brief Collects information about the current system + * + * Singleton class. + */ +class GLOBALLIBINTERFACE SystemInfo +{ +public: + /// Supported classes of configuration file + enum class ConfigFile { + System, ///< System configuration + UI, ///< UI configuration + Backend ///< Backend configuration + }; + + //! Constructs the systeminfo (Ctor). + //! @return Reference to the SystemInfo instance + static SystemInfo& Instance(); + + /// Deleted copy-constructor + SystemInfo(const SystemInfo&) = delete; + /// Deleted assignment operator + SystemInfo& operator= (const SystemInfo&) = delete; + /// Deleted move-constructor + SystemInfo(SystemInfo&&) = delete; + /// Deleted move operator + SystemInfo& operator=(SystemInfo&&) = delete; + + //! Destructs the config parser (Dtor) + ~SystemInfo(); + + //! Destroy single instance + static void destroyInstance(); + + //! Set the application path. + void setApplicationPath(const QString& qsName); + + //! Returns the application path. + QString getApplicationPath() const; + + //! Returns the location (path to) the executable + QString getExecutablePath() const; + + //! Return xml configuration path. + QString getConfigurationPath() const; + + //! Return resource path. + QString getResourcePath() const; + + //! Returns the path of a config file. + QString getConfigFile( ConfigFile fileType ) const; + +private: + //! Constructs the config parser (Ctor) + SystemInfo(); + +private: + + //! Contains the only instance of a CSystemInfo. + static std::unique_ptr s_pInstance; + + //! The name of the configfile. + QString m_qsApplicationPath; + + //! The path with the location of the executable + QString m_qsExecutablePath; +}; + +} // End namespace components +} // End namespace osdev + +#endif /* OSDEV_COMPONENTS_SYSTEMINFO_H */ diff --git b/src/threadmon.cpp a/src/threadmon.cpp new file mode 100644 index 0000000..fc6d2dd --- /dev/null +++ a/src/threadmon.cpp @@ -0,0 +1,40 @@ +/* **************************************************************************** + * 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 "threadmon.h" +#include + +using namespace osdev::components; + +int ThreadMon::postedEventsCountForThread(QThread* pThread) +{ + /* Check if we have a valid pointer */ + if (nullptr == pThread) + return -1; + + auto threadData = QThreadData::get2(pThread); + if (nullptr == threadData) + return -1; + + QMutexLocker lock(&threadData->postEventList.mutex); + + return (threadData->postEventList.size() - threadData->postEventList.startOffset); +} diff --git b/src/threadmon.h a/src/threadmon.h new file mode 100644 index 0000000..cf7c326 --- /dev/null +++ a/src/threadmon.h @@ -0,0 +1,44 @@ +/* **************************************************************************** + * 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_THREADMON_H +#define OSDEV_COMPONENTS_THREADMON_H + +#include + +namespace osdev { +namespace components { + +class ThreadMon +{ +public: + /*! + * \brief postedEventsCountForThread will report the number of meesages waiting in the eventloop of the given QThread + * \param pThread - raw-pointer to the thread we want to investigate. + * \return -1 if nothing to report. >= 0 if the thread is valid and the eventQueue was queried. + */ + static int postedEventsCountForThread(QThread* pThread); +}; + +} /* End namespace components */ +} /* End namespace osdev */ + +#endif /* OSDEV_COMPONENTS_THREADMON_H */ diff --git b/src/timeutils.cpp a/src/timeutils.cpp new file mode 100644 index 0000000..445d0cb --- /dev/null +++ a/src/timeutils.cpp @@ -0,0 +1,33 @@ +/* **************************************************************************** + * 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 "timeutils.h" + +// std +#include + +using namespace osdev::components; + +std::uint64_t TimeUtils::getEpochUSecs() +{ + auto tsUSec = std::chrono::time_point_cast(std::chrono::system_clock::now() ); + return static_cast(tsUSec.time_since_epoch().count()); +} diff --git b/src/timeutils.h a/src/timeutils.h new file mode 100644 index 0000000..2f66bca --- /dev/null +++ a/src/timeutils.h @@ -0,0 +1,40 @@ +/* **************************************************************************** + * 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_TIMEUTILS_H +#define OSDEV_COMPONENTS_TIMEUTILS_H + +#include +#include + +namespace osdev { +namespace components { + +class TimeUtils +{ +public: + static std::uint64_t getEpochUSecs(); +}; + +} /* End namespace components */ +} /* End namespace osdev */ + +#endif /* OSDEV_COMPONENTS_TIMEUTILS_H */ diff --git b/tests/CMakeLists.txt a/tests/CMakeLists.txt new file mode 100644 index 0000000..3635320 --- /dev/null +++ a/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()