From 19309500de243e2f990007ef862bc89c8f101696 Mon Sep 17 00:00:00 2001 From: Jonathan Hollocombe Date: Tue, 5 Dec 2023 15:01:39 +0000 Subject: [PATCH] Adding C++ plugin base class to reduce boilerplate in C++ plugins --- source/plugins/CMakeLists.txt | 9 +- source/plugins/bytes/CMakeLists.txt | 6 +- source/plugins/bytes/bytesPlugin.cpp | 170 +++------------- source/plugins/bytes/help.txt | 9 + .../plugins/bytes/readBytesNonOptimally.cpp | 44 ++--- source/plugins/bytes/readBytesNonOptimally.h | 23 +-- source/plugins/hdf5/CMakeLists.txt | 6 +- source/plugins/hdf5/hdf5plugin.cpp | 182 +++--------------- source/plugins/hdf5/hdf5plugin.h | 4 +- source/plugins/uda_plugin_base.cpp | 128 ++++++++++++ source/plugins/uda_plugin_base.hpp | 88 +++++++++ 11 files changed, 318 insertions(+), 351 deletions(-) create mode 100644 source/plugins/bytes/help.txt create mode 100644 source/plugins/uda_plugin_base.cpp create mode 100644 source/plugins/uda_plugin_base.hpp diff --git a/source/plugins/CMakeLists.txt b/source/plugins/CMakeLists.txt index 52b03f92..f990cb6a 100755 --- a/source/plugins/CMakeLists.txt +++ b/source/plugins/CMakeLists.txt @@ -3,6 +3,7 @@ find_package( LibXml2 REQUIRED ) find_package( fmt REQUIRED ) +find_package( Boost COMPONENTS filesystem REQUIRED ) if( WIN32 OR MINGW ) find_package( XDR REQUIRED ) @@ -67,6 +68,7 @@ endif() set( SOURCE_FILES managePluginFiles.cpp udaPlugin.cpp + uda_plugin_base.cpp ) set( HEADER_FILES @@ -74,12 +76,17 @@ set( HEADER_FILES pluginStructs.h udaPlugin.h udaPluginFiles.h - testplugin/teststructs.h testplugin/teststructs.cpp) + uda_plugin_base.hpp +) add_library( plugins-objects OBJECT ${SOURCE_FILES} ${HEADER_FILES} ) +target_link_libraries( plugins-objects PUBLIC Boost::filesystem ) + add_library( plugins-static STATIC $ ) +target_link_libraries( plugins-static PUBLIC Boost::filesystem ) if( BUILD_SHARED_LIBS ) add_library( plugins-shared SHARED $ ) + target_link_libraries( plugins-shared PUBLIC Boost::filesystem ) endif() set( LINK_LIB ${LIBXML2_LIBRARIES} fmt::fmt ) diff --git a/source/plugins/bytes/CMakeLists.txt b/source/plugins/bytes/CMakeLists.txt index 49045947..de1ded09 100644 --- a/source/plugins/bytes/CMakeLists.txt +++ b/source/plugins/bytes/CMakeLists.txt @@ -1,6 +1,7 @@ ######################################################################################################################## # Dependencies find_package( LibXml2 QUIET ) +find_package( Boost COMPONENTS filesystem REQUIRED ) if( NOT LIBXML2_FOUND ) message( WARNING "Libxml2 not found - skipping template plugin" ) @@ -16,8 +17,7 @@ uda_plugin( EXAMPLE "BYTES::read()" LIBNAME bytes_plugin SOURCES bytesPlugin.cpp readBytesNonOptimally.cpp md5Sum.cpp - EXTRA_INCLUDE_DIRS - ${LIBXML2_INCLUDE_DIR} EXTRA_LINK_LIBS - ${LIBXML2_LIBRARIES} + LibXml2::LibXml2 + Boost::filesystem ) diff --git a/source/plugins/bytes/bytesPlugin.cpp b/source/plugins/bytes/bytesPlugin.cpp index fb6950b7..66c445f0 100644 --- a/source/plugins/bytes/bytesPlugin.cpp +++ b/source/plugins/bytes/bytesPlugin.cpp @@ -1,160 +1,48 @@ #include "bytesPlugin.h" +#include #include #include -#include "readBytesNonOptimally.h" - -static int do_help(IDAM_PLUGIN_INTERFACE* idam_plugin_interface); - -static int do_version(IDAM_PLUGIN_INTERFACE* idam_plugin_interface); - -static int do_builddate(IDAM_PLUGIN_INTERFACE* idam_plugin_interface); - -static int do_defaultmethod(IDAM_PLUGIN_INTERFACE* idam_plugin_interface); - -static int do_maxinterfaceversion(IDAM_PLUGIN_INTERFACE* idam_plugin_interface); - -static int do_read(IDAM_PLUGIN_INTERFACE* idam_plugin_interface); - -int bytesPlugin(IDAM_PLUGIN_INTERFACE* idam_plugin_interface) -{ - static int init = 0; - - //---------------------------------------------------------------------------------------- - // Standard v1 Plugin Interface - - if (idam_plugin_interface->interfaceVersion > THISPLUGIN_MAX_INTERFACE_VERSION) { - RAISE_PLUGIN_ERROR("Plugin Interface Version Unknown to this plugin: Unable to execute the request!"); - } - - idam_plugin_interface->pluginVersion = THISPLUGIN_VERSION; - - //---------------------------------------------------------------------------------------- - // Heap Housekeeping - - // Plugin must maintain a list of open file handles and sockets: loop over and close all files and sockets - // Plugin must maintain a list of plugin functions called: loop over and reset state and free heap. - // Plugin must maintain a list of calls to other plugins: loop over and call each plugin with the housekeeping request - // Plugin must destroy lists at end of housekeeping - - // A plugin only has a single instance on a server. For multiple instances, multiple servers are needed. - // Plugins can maintain state so recursive calls (on the same server) must respect this. - // If the housekeeping action is requested, this must be also applied to all plugins called. - // A list must be maintained to register these plugin calls to manage housekeeping. - // Calls to plugins must also respect access policy and user authentication policy - - REQUEST_DATA* request = idam_plugin_interface->request_data; - - if (idam_plugin_interface->housekeeping || STR_IEQUALS(request->function, "reset")) { - if (!init) return 0; // Not previously initialised: Nothing to do! - // Free Heap & reset counters - init = 0; - return 0; - } - - //---------------------------------------------------------------------------------------- - // Initialise +#include - if (!init || STR_IEQUALS(request->function, "init") - || STR_IEQUALS(request->function, "initialise")) { - - init = 1; - if (STR_IEQUALS(request->function, "init") || STR_IEQUALS(request->function, "initialise")) - return 0; - } - - //---------------------------------------------------------------------------------------- - // Plugin Functions - //---------------------------------------------------------------------------------------- - - //---------------------------------------------------------------------------------------- - // Standard methods: version, builddate, defaultmethod, maxinterfaceversion - - if (STR_IEQUALS(request->function, "help")) { - return do_help(idam_plugin_interface); - } else if (STR_IEQUALS(request->function, "version")) { - return do_version(idam_plugin_interface); - } else if (STR_IEQUALS(request->function, "builddate")) { - return do_builddate(idam_plugin_interface); - } else if (STR_IEQUALS(request->function, "defaultmethod")) { - return do_defaultmethod(idam_plugin_interface); - } else if (STR_IEQUALS(request->function, "maxinterfaceversion")) { - return do_maxinterfaceversion(idam_plugin_interface); - } else if (STR_IEQUALS(request->function, "read")) { - return do_read(idam_plugin_interface); - } else { - RAISE_PLUGIN_ERROR("Unknown function requested!"); - } -} - -/** - * Help: A Description of library functionality - * @param idam_plugin_interface - * @return - */ -int do_help(IDAM_PLUGIN_INTERFACE* idam_plugin_interface) -{ - const char* help = "\nbytes: data reader to access files as a block of bytes without interpretation\n\n"; - const char* desc = "bytes: help = description of this plugin"; - - return setReturnDataString(idam_plugin_interface->data_block, help, desc); -} - -/** - * Plugin version - * @param idam_plugin_interface - * @return - */ -int do_version(IDAM_PLUGIN_INTERFACE* idam_plugin_interface) -{ - return setReturnDataIntScalar(idam_plugin_interface->data_block, THISPLUGIN_VERSION, "Plugin version number"); -} - -/** - * Plugin Build Date - * @param idam_plugin_interface - * @return - */ -int do_builddate(IDAM_PLUGIN_INTERFACE* idam_plugin_interface) -{ - return setReturnDataString(idam_plugin_interface->data_block, __DATE__, "Plugin build date"); -} +#include "readBytesNonOptimally.h" -/** - * Plugin Default Method - * @param idam_plugin_interface - * @return - */ -int do_defaultmethod(IDAM_PLUGIN_INTERFACE* idam_plugin_interface) +class BytesPlugin : public UDAPluginBase { +public: + BytesPlugin(); + int read(IDAM_PLUGIN_INTERFACE* plugin_interface); + int init(IDAM_PLUGIN_INTERFACE* plugin_interface) override { return 0; } + int reset() override { return 0; } +}; + +BytesPlugin::BytesPlugin() + : UDAPluginBase( + "HDF5", + 1, + "read", + boost::filesystem::path(__FILE__).parent_path().append("help.txt").string() + ) { - return setReturnDataString(idam_plugin_interface->data_block, THISPLUGIN_DEFAULT_METHOD, "Plugin default method"); + register_method("read", static_cast(&BytesPlugin::read)); } -/** - * Plugin Maximum Interface Version - * @param idam_plugin_interface - * @return - */ -int do_maxinterfaceversion(IDAM_PLUGIN_INTERFACE* idam_plugin_interface) +int bytesPlugin(IDAM_PLUGIN_INTERFACE* plugin_interface) { - return setReturnDataIntScalar(idam_plugin_interface->data_block, THISPLUGIN_MAX_INTERFACE_VERSION, "Maximum Interface Version"); + static BytesPlugin plugin = {}; + return plugin.call(plugin_interface); } //---------------------------------------------------------------------------------------- // Add functionality here .... -int do_read(IDAM_PLUGIN_INTERFACE* idam_plugin_interface) +int BytesPlugin::read(IDAM_PLUGIN_INTERFACE* plugin_interface) { - DATA_SOURCE* data_source = idam_plugin_interface->data_source; - SIGNAL_DESC* signal_desc = idam_plugin_interface->signal_desc; - DATA_BLOCK* data_block = idam_plugin_interface->data_block; - - const char* path; - FIND_REQUIRED_STRING_VALUE(idam_plugin_interface->request_data->nameValueList, path); + std::string path = required_arg(plugin_interface, "path"); - StringCopy(data_source->path, path, MAXPATH); - UDA_LOG(UDA_LOG_DEBUG, "expandEnvironmentvariables! \n"); - expand_environment_variables(data_source->path); + char c_path[MAXPATH]; + StringCopy(c_path, path.c_str(), MAXPATH); + debug("expand_environment_variables!"); + expand_environment_variables(c_path); - return readBytes(*data_source, *signal_desc, data_block, idam_plugin_interface->environment); + return readBytes(c_path, plugin_interface); } diff --git a/source/plugins/bytes/help.txt b/source/plugins/bytes/help.txt new file mode 100644 index 00000000..fa97888d --- /dev/null +++ b/source/plugins/bytes/help.txt @@ -0,0 +1,9 @@ +UDA plugin to read files as a block of bytes without interpretation + +Functions: + +read + Arguments: + path the path of the file to read + Example: + path(read=/path/to/file.txt) diff --git a/source/plugins/bytes/readBytesNonOptimally.cpp b/source/plugins/bytes/readBytesNonOptimally.cpp index 0df0f26b..90b5f736 100755 --- a/source/plugins/bytes/readBytesNonOptimally.cpp +++ b/source/plugins/bytes/readBytesNonOptimally.cpp @@ -1,24 +1,3 @@ -/*--------------------------------------------------------------- -* IDAM Plugin data Reader to Access Files as a Block of Bytes without Interpretation -* -* Input Arguments: DATA_SOURCE data_source -* SIGNAL_DESC signal_desc -* -* Returns: readBytes 0 if read was successful -* otherwise an Error Code is returned -* DATA_BLOCK Structure with Data from the target File -* -* Calls freeDataBlock to free Heap memory if an Error Occurs -* -* Notes: All memory required to hold data is allocated dynamically -* in heap storage. Pointers to these areas of memory are held -* by the passed DATA_BLOCK structure. Local memory allocations -* are freed on exit. However, the blocks reserved for data are -* not and MUST BE FREED by the calling routine. -** -* ToDo: -* -*-----------------------------------------------------------------------------*/ #include "readBytesNonOptimally.h" #include @@ -31,30 +10,41 @@ #include #include -int readBytes(DATA_SOURCE data_source, SIGNAL_DESC signal_desc, DATA_BLOCK* data_block, const ENVIRONMENT* environment) +#define BYTEFILEDOESNOTEXIST 100001 +#define BYTEFILEATTRIBUTEERROR 100002 +#define BYTEFILEISNOTREGULAR 100003 +#define BYTEFILEOPENERROR 100004 +#define BYTEFILEHEAPERROR 100005 +#define BYTEFILEMD5ERROR 100006 +#define BYTEFILEMD5DIFF 100007 + +int readBytes(const std::string& path, IDAM_PLUGIN_INTERFACE* plugin_interface) { int err = 0; char md5file[2 * MD5_SIZE + 1] = ""; char md5check[2 * MD5_SIZE + 1] = ""; + const ENVIRONMENT* environment = plugin_interface->environment; + DATA_BLOCK* data_block = plugin_interface->data_block; + //---------------------------------------------------------------------- // Block Access to External Users if (environment->external_user) { err = 999; addIdamError(UDA_CODE_ERROR_TYPE, "readBytes", err, "This Service is Disabled"); - UDA_LOG(UDA_LOG_DEBUG, "Disabled Service - Requested File: %s \n", data_source.path); + UDA_LOG(UDA_LOG_DEBUG, "Disabled Service - Requested File: %s \n", path.c_str()); return err; } //---------------------------------------------------------------------- // Test the filepath - if (!IsLegalFilePath(data_source.path)) { + if (!IsLegalFilePath(path.c_str())) { err = 999; addIdamError(UDA_CODE_ERROR_TYPE, "readBytes", err, "The directory path has incorrect syntax"); - UDA_LOG(UDA_LOG_DEBUG, "The directory path has incorrect syntax [%s] \n", data_source.path); + UDA_LOG(UDA_LOG_DEBUG, "The directory path has incorrect syntax [%s] \n", path.c_str()); return err; } @@ -63,7 +53,7 @@ int readBytes(DATA_SOURCE data_source, SIGNAL_DESC signal_desc, DATA_BLOCK* data err = 0; - UDA_LOG(UDA_LOG_DEBUG, "File Name : %s \n", data_source.path); + UDA_LOG(UDA_LOG_DEBUG, "File Name : %s \n", path.c_str()); //---------------------------------------------------------------------- // File Attributes @@ -74,7 +64,7 @@ int readBytes(DATA_SOURCE data_source, SIGNAL_DESC signal_desc, DATA_BLOCK* data // Open the File as a Binary Stream errno = 0; - FILE* fh = fopen(data_source.path, "rb"); + FILE* fh = fopen(path.c_str(), "rb"); int serrno = errno; diff --git a/source/plugins/bytes/readBytesNonOptimally.h b/source/plugins/bytes/readBytesNonOptimally.h index 792f8c74..09b06237 100755 --- a/source/plugins/bytes/readBytesNonOptimally.h +++ b/source/plugins/bytes/readBytesNonOptimally.h @@ -4,27 +4,10 @@ #include #include -#ifdef __cplusplus -extern "C" { -#endif +#include +#include -LIBRARY_API int readBytes(DATA_SOURCE data_source, SIGNAL_DESC signal_desc, DATA_BLOCK *data_block, const ENVIRONMENT* environment); - -#ifndef NOBINARYPLUGIN - -#define BYTEFILEDOESNOTEXIST 100001 -#define BYTEFILEATTRIBUTEERROR 100002 -#define BYTEFILEISNOTREGULAR 100003 -#define BYTEFILEOPENERROR 100004 -#define BYTEFILEHEAPERROR 100005 -#define BYTEFILEMD5ERROR 100006 -#define BYTEFILEMD5DIFF 100007 - -#endif - -#ifdef __cplusplus -} -#endif +int readBytes(const std::string& path, IDAM_PLUGIN_INTERFACE* plugin_interface); #endif // UDA_PLUGIN_READBYTESNONOPTIMALLY_H diff --git a/source/plugins/hdf5/CMakeLists.txt b/source/plugins/hdf5/CMakeLists.txt index b5b20ea6..3b3308b9 100755 --- a/source/plugins/hdf5/CMakeLists.txt +++ b/source/plugins/hdf5/CMakeLists.txt @@ -15,10 +15,10 @@ endif() include( plugins ) uda_plugin( - NAME NEWHDF5 - ENTRY_FUNC udaHDF5 + NAME HDF5 + ENTRY_FUNC hdf5Plugin DESCRIPTION "HDF5 Data Reader" - EXAMPLE "NEWHDF5::read()" + EXAMPLE "HDF5::read()" LIBNAME hdf5_plugin SOURCES hdf5plugin.cpp hdf5plugin.h readHDF58.cpp readHDF58.h EXTRA_INCLUDE_DIRS diff --git a/source/plugins/hdf5/hdf5plugin.cpp b/source/plugins/hdf5/hdf5plugin.cpp index 60dd48af..b235887d 100644 --- a/source/plugins/hdf5/hdf5plugin.cpp +++ b/source/plugins/hdf5/hdf5plugin.cpp @@ -1,176 +1,52 @@ -/*--------------------------------------------------------------- -* v1 IDAM Plugin: HDF5 Data Reader -* -* Input Arguments: IDAM_PLUGIN_INTERFACE *idam_plugin_interface -* -* Returns: 0 if the plugin functionality was successful -* otherwise a Error Code is returned -* -* Standard functionality: -* -* help a description of what this plugin does together with a list of functions available -* -* reset frees all previously allocated heap, closes file handles and resets all static parameters. -* This has the same functionality as setting the housekeeping directive in the plugin interface -* data structure to TRUE (1) -* -* init Initialise the plugin: read all required data and process. Retain staticly for -* future reference. -* -*---------------------------------------------------------------------------------------------------------------*/ #include "hdf5plugin.h" -#include -#include +#include #include "readHDF58.h" -UDA_PLUGIN_FILE_LIST pluginFileList; // Private list of open data file handles - -static int do_help(IDAM_PLUGIN_INTERFACE* idam_plugin_interface); - -static int do_version(IDAM_PLUGIN_INTERFACE* idam_plugin_interface); - -static int do_builddate(IDAM_PLUGIN_INTERFACE* idam_plugin_interface); - -static int do_defaultmethod(IDAM_PLUGIN_INTERFACE* idam_plugin_interface); - -static int do_maxinterfaceversion(IDAM_PLUGIN_INTERFACE* idam_plugin_interface); - -static int do_read(IDAM_PLUGIN_INTERFACE* idam_plugin_interface); - -extern int udaHDF5(IDAM_PLUGIN_INTERFACE* idam_plugin_interface) -{ - static short init = 0; - - //---------------------------------------------------------------------------------------- - // Standard v1 Plugin Interface - - unsigned short housekeeping; - - if (idam_plugin_interface->interfaceVersion > THISPLUGIN_MAX_INTERFACE_VERSION) { - RAISE_PLUGIN_ERROR("Plugin Interface Version Unknown to this plugin: Unable to execute the request!"); +class HDF5Plugin : public UDAPluginBase { +public: + HDF5Plugin(); + int read(IDAM_PLUGIN_INTERFACE* plugin_interface); + int hello(IDAM_PLUGIN_INTERFACE* plugin_interface) + { + return setReturnDataString(plugin_interface->data_block, "hello!", nullptr); } - - idam_plugin_interface->pluginVersion = THISPLUGIN_VERSION; - - REQUEST_DATA* request = idam_plugin_interface->request_data; - - housekeeping = idam_plugin_interface->housekeeping; - - if (housekeeping || STR_IEQUALS(request->function, "reset")) { - - if (!init) return 0; // Not previously initialised: Nothing to do! - - // Free Heap & reset counters - - closeIdamPluginFiles(&pluginFileList); // Close all open files - - init = 0; - - return 0; - } - - //---------------------------------------------------------------------------------------- - // Initialise - - if (!init || STR_IEQUALS(request->function, "init") - || STR_IEQUALS(request->function, "initialise")) { - - initIdamPluginFileList(&pluginFileList); - - init = 1; - if (STR_IEQUALS(request->function, "init") || STR_IEQUALS(request->function, "initialise")) - return 0; + static int foo(IDAM_PLUGIN_INTERFACE* plugin_interface) + { + return setReturnDataString(plugin_interface->data_block, "foo!", nullptr); } + int init(IDAM_PLUGIN_INTERFACE* plugin_interface) override { return 0; } + int reset() override { return 0; } +}; - //---------------------------------------------------------------------------------------- - // Plugin Functions - //---------------------------------------------------------------------------------------- - - if (STR_IEQUALS(request->function, "help")) { - return do_help(idam_plugin_interface); - } else if (STR_IEQUALS(request->function, "version")) { - return do_version(idam_plugin_interface); - } else if (STR_IEQUALS(request->function, "builddate")) { - return do_builddate(idam_plugin_interface); - } else if (STR_IEQUALS(request->function, "defaultmethod")) { - return do_defaultmethod(idam_plugin_interface); - } else if (STR_IEQUALS(request->function, "maxinterfaceversion")) { - return do_maxinterfaceversion(idam_plugin_interface); - } else if (STR_IEQUALS(request->function, "read")) { - return do_read(idam_plugin_interface); - } else { - RAISE_PLUGIN_ERROR("Unknown function requested!"); - } - - return 0; -} - -/** - * Help: A Description of library functionality - * @param idam_plugin_interface - * @return - */ -int do_help(IDAM_PLUGIN_INTERFACE* idam_plugin_interface) -{ - const char* help = "\nnewHDF5: get - Read data from a HDF5 file\n\n"; - const char* desc = "newHDF5: help = description of this plugin"; - - return setReturnDataString(idam_plugin_interface->data_block, help, desc); -} - -/** - * Plugin version - * @param idam_plugin_interface - * @return - */ -int do_version(IDAM_PLUGIN_INTERFACE* idam_plugin_interface) -{ - return setReturnDataIntScalar(idam_plugin_interface->data_block, THISPLUGIN_VERSION, "Plugin version number"); -} - -/** - * Plugin Build Date - * @param idam_plugin_interface - * @return - */ -int do_builddate(IDAM_PLUGIN_INTERFACE* idam_plugin_interface) +HDF5Plugin::HDF5Plugin() + : UDAPluginBase("HDF5", 1, "read", "") { - return setReturnDataString(idam_plugin_interface->data_block, __DATE__, "Plugin build date"); + register_method("read", static_cast(&HDF5Plugin::read)); + register_method("hello", static_cast(&HDF5Plugin::hello)); + register_function("foo", &HDF5Plugin::foo); } /** - * Plugin Default Method - * @param idam_plugin_interface - * @return + * Entry function */ -int do_defaultmethod(IDAM_PLUGIN_INTERFACE* idam_plugin_interface) +extern int hdf5Plugin(IDAM_PLUGIN_INTERFACE* plugin_interface) { - return setReturnDataString(idam_plugin_interface->data_block, THISPLUGIN_DEFAULT_METHOD, "Plugin default method"); -} - -/** - * Plugin Maximum Interface Version - * @param idam_plugin_interface - * @return - */ -int do_maxinterfaceversion(IDAM_PLUGIN_INTERFACE* idam_plugin_interface) -{ - return setReturnDataIntScalar(idam_plugin_interface->data_block, THISPLUGIN_MAX_INTERFACE_VERSION, "Maximum Interface Version"); + static HDF5Plugin plugin = {}; + return plugin.call(plugin_interface); } //---------------------------------------------------------------------------------------- // Read data from a HDF5 File -// If the client has specified a specific file, the path will be found at request_block->path -// otherwise the path is determined by a query against the metadata catalog -int do_read(IDAM_PLUGIN_INTERFACE* idam_plugin_interface) + +int HDF5Plugin::read(IDAM_PLUGIN_INTERFACE* plugin_interface) { - DATA_SOURCE* data_source = idam_plugin_interface->data_source; - SIGNAL_DESC* signal_desc = idam_plugin_interface->signal_desc; - REQUEST_DATA* request = idam_plugin_interface->request_data; - DATA_BLOCK* data_block = idam_plugin_interface->data_block; + DATA_SOURCE* data_source = plugin_interface->data_source; + SIGNAL_DESC* signal_desc = plugin_interface->signal_desc; + REQUEST_DATA* request = plugin_interface->request_data; + DATA_BLOCK* data_block = plugin_interface->data_block; const char* file_path = nullptr; FIND_REQUIRED_STRING_VALUE(request->nameValueList, file_path); diff --git a/source/plugins/hdf5/hdf5plugin.h b/source/plugins/hdf5/hdf5plugin.h index 0cdd0c78..9d4405c7 100755 --- a/source/plugins/hdf5/hdf5plugin.h +++ b/source/plugins/hdf5/hdf5plugin.h @@ -21,9 +21,7 @@ extern "C" { extern UDA_PLUGIN_FILE_LIST pluginFileList; -LIBRARY_API int udaHDF5(IDAM_PLUGIN_INTERFACE* idam_plugin_interface); -LIBRARY_API int readHDF5IdamType(H5T_class_t classtype, int precision, int issigned); -LIBRARY_API int readHDF5Att(hid_t file_id, char* object, hid_t att_id, char* attname, DATA_BLOCK* data_block); +LIBRARY_API int hdf5Plugin(IDAM_PLUGIN_INTERFACE* plugin_interface); #ifdef __cplusplus } diff --git a/source/plugins/uda_plugin_base.cpp b/source/plugins/uda_plugin_base.cpp new file mode 100644 index 00000000..61c63344 --- /dev/null +++ b/source/plugins/uda_plugin_base.cpp @@ -0,0 +1,128 @@ +#include "uda_plugin_base.hpp" +#include "udaPlugin.h" +#include "clientserver/stringUtils.h" + +#include +#include +#include +#include + +int UDAPluginBase::call(IDAM_PLUGIN_INTERFACE* plugin_interface) { + try { + if (plugin_interface->interfaceVersion > m_interface_version) { + RAISE_PLUGIN_ERROR("Plugin Interface Version Unknown to this plugin: Unable to execute the request!"); + } + + plugin_interface->pluginVersion = m_version; + + do_reset(); + do_init(plugin_interface); + + //---------------------------------------------------------------------------------------- + // Plugin Functions + //---------------------------------------------------------------------------------------- + + std::string function = get_function(plugin_interface); + + if (m_function_map.find(function) != m_function_map.end()) { + return m_function_map.at(function)(plugin_interface); + } else if (m_method_map.find(function) != m_method_map.end()) { + auto fn = m_method_map.at(function); + return (this->*fn)(plugin_interface); + } else { + UDA_LOG(UDA_LOG_ERROR, "Unknown function requested %s\n", function.c_str()); + addIdamError(UDA_CODE_ERROR_TYPE, "UDAPluginBase::call", 999, "Unknown function requested"); + concatUdaError(&plugin_interface->error_stack); + return 999; + } + } catch (std::exception& ex) { + UDA_LOG(UDA_LOG_ERROR, "Exception: %s\n", ex.what()); + addIdamError(UDA_CODE_ERROR_TYPE, "UDAPluginBase::call", 999, ex.what()); + concatUdaError(&plugin_interface->error_stack); + return 999; + } +} + +std::string UDAPluginBase::get_function(IDAM_PLUGIN_INTERFACE* plugin_interface) { + REQUEST_DATA* request = plugin_interface->request_data; + return boost::to_lower_copy(request->function); +} + +int UDAPluginBase::do_init(IDAM_PLUGIN_INTERFACE* plugin_interface) { + std::string function = get_function(plugin_interface); + if (!m_init || (function == "init" || function == "initialise")) { + int rc = init(plugin_interface); + if (rc == 0) { + m_init = true; + } + return rc; + } + return 0; +} + +int UDAPluginBase::do_reset() { + if (!m_init) { + // Not previously initialised: Nothing to do! + return 0; + } + + reset(); + m_init = false; + + return 0; +} + +int UDAPluginBase::help(IDAM_PLUGIN_INTERFACE *plugin_interface) { + std::string desc = m_name + ": help = description of this plugin"; + + if (m_help_file.empty()) { + const char* help = "No help available"; + return setReturnDataString(plugin_interface->data_block, help, desc.c_str()); + } + + auto path = boost::filesystem::path(m_help_file); + if (!boost::filesystem::exists(path)) { + auto help = (boost::format("help file %1% does not exist") % path).str(); + return setReturnDataString(plugin_interface->data_block, help.c_str(), desc.c_str()); + } + + std::ifstream help_file{ path.string() }; + std::stringstream buffer; + buffer << help_file.rdbuf(); + auto help = buffer.str(); + + return setReturnDataString(plugin_interface->data_block, help.c_str(), desc.c_str()); +} + +int UDAPluginBase::version(IDAM_PLUGIN_INTERFACE *plugin_interface) { + return setReturnDataIntScalar(plugin_interface->data_block, m_version, "Plugin version number"); +} + +int UDAPluginBase::build_date(IDAM_PLUGIN_INTERFACE *plugin_interface) { + return setReturnDataString(plugin_interface->data_block, __DATE__, "Plugin build date"); +} + +int UDAPluginBase::default_method(IDAM_PLUGIN_INTERFACE *plugin_interface) { + return setReturnDataString(plugin_interface->data_block, m_default_method.c_str(), "Plugin default method"); +} + +int UDAPluginBase::max_interface_version(IDAM_PLUGIN_INTERFACE *plugin_interface) { + return setReturnDataIntScalar(plugin_interface->data_block, m_interface_version, "Maximum Interface Version"); +} + +void UDAPluginBase::register_method(const std::string &name, plugin_member_type plugin_method) { + m_method_map[name] = plugin_method; +} + +void UDAPluginBase::register_function(const std::string &name, plugin_function_type plugin_function) { + m_function_map[name] = plugin_function; +} + +void UDAPluginBase::debug(const std::string& message) { + UDA_LOG(UDA_LOG_DEBUG, "%s", message.c_str()); +} + +void UDAPluginBase::error(const std::string &message) { + UDA_LOG(UDA_LOG_ERROR, "%s", message.c_str()); + throw std::runtime_error{ message.c_str() }; +} \ No newline at end of file diff --git a/source/plugins/uda_plugin_base.hpp b/source/plugins/uda_plugin_base.hpp new file mode 100644 index 00000000..3e0892cb --- /dev/null +++ b/source/plugins/uda_plugin_base.hpp @@ -0,0 +1,88 @@ +#pragma once + +#ifndef UDA_UDA_PLUGIN_H +#define UDA_UDA_PLUGIN_H + +#include + +#include +#include +#include "udaPlugin.h" + +class UDAPluginBase; + +typedef int (*plugin_function_type)(IDAM_PLUGIN_INTERFACE*); + +/** + * Abstract base class to be used to provide helper functions to make it easier to create C++ plugins. + */ +class UDAPluginBase { +public: + typedef int (UDAPluginBase::*plugin_member_type)(IDAM_PLUGIN_INTERFACE*); + int call(IDAM_PLUGIN_INTERFACE* plugin_interface); + +protected: + UDAPluginBase(std::string name, int version, std::string default_method, std::string help_file) + : m_init{ false } + , m_name{ std::move(name) } + , m_version{ version } + , m_interface_version{ 1 } + , m_default_method{ std::move(default_method) } + , m_help_file{ std::move(help_file) } + , m_method_map{} + , m_function_map{} + { + register_method("help", &UDAPluginBase::help); + register_method("version", &UDAPluginBase::version); + register_method("builddate", &UDAPluginBase::build_date); + register_method("defaultmethod", &UDAPluginBase::default_method); + register_method("maxinterfaceversion", &UDAPluginBase::max_interface_version); + } + + virtual int init(IDAM_PLUGIN_INTERFACE* plugin_interface) = 0; + virtual int reset() = 0; + + void register_method(const std::string& name, plugin_member_type plugin_method); + void register_function(const std::string& name, plugin_function_type plugin_function); + + // Helper methods + void debug(const std::string& message); + void error(const std::string& message); + + template + T required_arg(IDAM_PLUGIN_INTERFACE* plugin_interface, const std::string& name); + + template <> + std::string required_arg(IDAM_PLUGIN_INTERFACE* plugin_interface, const std::string& name) + { + const char* value; + if (!findStringValue(&plugin_interface->request_data->nameValueList, &value, name.c_str())) { + auto message = (boost::format("Required argument '%1%' not given") % name).str(); + error(message); + } + return value; + } + + // Default method implementations + int help(IDAM_PLUGIN_INTERFACE* plugin_interface); + int version(IDAM_PLUGIN_INTERFACE* plugin_interface); + int build_date(IDAM_PLUGIN_INTERFACE* plugin_interface); + int default_method(IDAM_PLUGIN_INTERFACE* plugin_interface); + int max_interface_version(IDAM_PLUGIN_INTERFACE* plugin_interface); + +private: + int do_init(IDAM_PLUGIN_INTERFACE* plugin_interface); + int do_reset(); + static std::string get_function(IDAM_PLUGIN_INTERFACE* plugin_interface); + + bool m_init; + std::string m_name; + int m_version; + int m_interface_version; + std::string m_default_method; + std::string m_help_file; + std::unordered_map m_method_map; + std::unordered_map m_function_map; +}; + +#endif //UDA_UDA_PLUGIN_H