Skip to content

Commit

Permalink
Adding C++ plugin base class to reduce boilerplate in C++ plugins
Browse files Browse the repository at this point in the history
  • Loading branch information
jholloc committed Dec 5, 2023
1 parent 09e479e commit 1930950
Show file tree
Hide file tree
Showing 11 changed files with 318 additions and 351 deletions.
9 changes: 8 additions & 1 deletion source/plugins/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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 )
Expand Down Expand Up @@ -67,19 +68,25 @@ endif()
set( SOURCE_FILES
managePluginFiles.cpp
udaPlugin.cpp
uda_plugin_base.cpp
)

set( HEADER_FILES
managePluginFiles.h
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_OBJECTS:plugins-objects> )
target_link_libraries( plugins-static PUBLIC Boost::filesystem )
if( BUILD_SHARED_LIBS )
add_library( plugins-shared SHARED $<TARGET_OBJECTS:plugins-objects> )
target_link_libraries( plugins-shared PUBLIC Boost::filesystem )
endif()

set( LINK_LIB ${LIBXML2_LIBRARIES} fmt::fmt )
Expand Down
6 changes: 3 additions & 3 deletions source/plugins/bytes/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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" )
Expand All @@ -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
)
170 changes: 29 additions & 141 deletions source/plugins/bytes/bytesPlugin.cpp
Original file line number Diff line number Diff line change
@@ -1,160 +1,48 @@
#include "bytesPlugin.h"

#include <plugins/uda_plugin_base.hpp>
#include <clientserver/stringUtils.h>
#include <clientserver/makeRequestBlock.h>

#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 <boost/filesystem.hpp>

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<UDAPluginBase::plugin_member_type>(&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<std::string>(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);
}
9 changes: 9 additions & 0 deletions source/plugins/bytes/help.txt
Original file line number Diff line number Diff line change
@@ -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)
44 changes: 17 additions & 27 deletions source/plugins/bytes/readBytesNonOptimally.cpp
Original file line number Diff line number Diff line change
@@ -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 <cerrno>
Expand All @@ -31,30 +10,41 @@
#include <clientserver/udaTypes.h>
#include <clientserver/initStructs.h>

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;
}

Expand All @@ -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
Expand All @@ -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;

Expand Down
23 changes: 3 additions & 20 deletions source/plugins/bytes/readBytesNonOptimally.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,10 @@
#include <clientserver/udaStructs.h>
#include <clientserver/export.h>

#ifdef __cplusplus
extern "C" {
#endif
#include <string>
#include <plugins/pluginStructs.h>

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

6 changes: 3 additions & 3 deletions source/plugins/hdf5/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading

0 comments on commit 1930950

Please sign in to comment.