Elektra
0.9.0
|
Elektra plugin framework. More...
Macros | |
#define | ELEKTRA_PLUGIN_FUNCTION(function) ELEKTRA_PLUGIN_FUNCTION2 (ELEKTRA_PLUGIN_NAME_C, function) |
Declare a plugin's function name suitable for compilation variants (see doc/tutorials). More... | |
#define | ELEKTRA_README ELEKTRA_README2 (ELEKTRA_PLUGIN_NAME_C) |
The filename for inclusion of the readme for compilation variants (see doc/tutorials). More... | |
#define | ELEKTRA_SET_ERROR(number, key, text) |
Sets the error in the keys metadata. More... | |
#define | ELEKTRA_SET_ERRORF(number, key, formatstring, ...) |
Sets the error in the keys metadata. More... | |
#define | ELEKTRA_ADD_WARNINGF(number, key, formatstring, ...) |
Adds a warning in the keys metadata. More... | |
#define | ELEKTRA_ADD_WARNING(number, key, text) |
Adds a warning in the keys metadata. More... | |
#define | ELEKTRA_SET_ERROR_GET(parentKey) |
Set error in kdbGet() when opening the file failed. More... | |
#define | ELEKTRA_SET_ERROR_SET(parentKey) |
Set error in kdbSet() when opening the file failed. More... | |
Functions | |
Plugin * | elektraPluginExport (const char *pluginName,...) |
Allows one to Export Methods for a Plugin. More... | |
KeySet * | elektraPluginGetConfig (Plugin *handle) |
Returns the configuration of that plugin. More... | |
void | elektraPluginSetData (Plugin *plugin, void *data) |
Store a pointer to any plugin related data. More... | |
void * | elektraPluginGetData (Plugin *plugin) |
Get a pointer to any plugin related data stored before. More... | |
KeySet * | elektraPluginGetGlobalKeySet (Plugin *plugin) |
Get a pointer to the global keyset. More... | |
int | elektraDocOpen (Plugin *handle, Key *warningsKey) |
Initialize data for the plugin. More... | |
int | elektraDocClose (Plugin *handle, Key *warningsKey) |
Finalize the plugin. More... | |
int | elektraDocGet (Plugin *handle, KeySet *returned, Key *parentKey) |
Get data from storage to application. More... | |
int | elektraDocSet (Plugin *handle, KeySet *returned, Key *parentKey) |
Set data from application to storage. More... | |
int | elektraDocError (Plugin *handle, KeySet *returned, Key *parentKey) |
Rollback in case of errors. More... | |
int | elektraDocCheckConf (Key *errorKey, KeySet *conf) |
Validate plugin configuration at mount time. More... | |
Elektra plugin framework.
To get started with writing plugins, first read our Plugin Tutorial.
A plugin can implement any functionality related to configuration. There are 6 possible entry points for a plugin.
Additionally, make sure that you write a contract in the README.md. It is used by the build system and the mounting tools.
Plugins should not change the keyname of the key that is passed to the entry points (warningsKey and parentKey in this documentation). These keys might be members in keysets.
The names described here contain "Doc" within the method's name just because the plugin described in this document is called doc (the doxygen source was generated from src/plugins/doc/doc.h). Always replace Doc with the name of the plugin you are going to implement or use ELEKTRA_PLUGIN_FUNCTION.
Use following include to have the functions that are not implemented by you available:
Use following include to have the macros for setting the error and adding the warnings available:
and then you can use:
Note that you also need to return -1 in the case of error. See individual description of entry points to implement below.
This keyset allows plugins to exchange information with other plugins.
The keyset is initialized by the KDB for all plugins, except for manually created plugins with elektraPluginOpen()
. The global keyset is tied to a KDB handle, initialized on kdbOpen()
and deleted on kdbClose()
.
Obtain a handle to the global keyset and work with it:
Clean up keys which you do not need any more, to keep the global keyset compact:
#define ELEKTRA_ADD_WARNING | ( | number, | |
key, | |||
text | |||
) |
Adds a warning in the keys metadata.
Include kdberrors.h to make it work:
number | the warning number from src/error/specification |
key | to write the error to |
text | additional text for the user |
#define ELEKTRA_ADD_WARNINGF | ( | number, | |
key, | |||
formatstring, | |||
... | |||
) |
Adds a warning in the keys metadata.
Include kdberrors.h to make it work:
number | the warning number from src/error/specification |
key | to write the error to |
formatstring | a format string as in printf |
... | further arguments as in printf |
#define ELEKTRA_PLUGIN_FUNCTION | ( | function | ) | ELEKTRA_PLUGIN_FUNCTION2 (ELEKTRA_PLUGIN_NAME_C, function) |
Declare a plugin's function name suitable for compilation variants (see doc/tutorials).
It can be used in the same way as elektraPluginExport().
plugin | the name of the plugin |
function | which function it is (open, close, get, set, error) |
#define ELEKTRA_README ELEKTRA_README2 (ELEKTRA_PLUGIN_NAME_C) |
The filename for inclusion of the readme for compilation variants (see doc/tutorials).
plugin | the name of the plugin |
#define ELEKTRA_SET_ERROR | ( | number, | |
key, | |||
text | |||
) |
Sets the error in the keys metadata.
Include kdberrors.h to make it work. Only a single error can be written to the key.
number | the error number from src/error/specification |
key | to write the error to |
text | additional text for the user |
#define ELEKTRA_SET_ERROR_GET | ( | parentKey | ) |
Set error in kdbGet() when opening the file failed.
Assumes that error reason is in errno
.
parentKey | key to append error to |
To use it include:
#define ELEKTRA_SET_ERROR_SET | ( | parentKey | ) |
Set error in kdbSet() when opening the file failed.
Assumes that error reason is in errno
.
parentKey | key to append error to |
To use it include:
#define ELEKTRA_SET_ERRORF | ( | number, | |
key, | |||
formatstring, | |||
... | |||
) |
Sets the error in the keys metadata.
Include kdberrors.h to make it work. Only a single error can be written to the key.
number | the error number from src/error/specification |
key | to write the error to |
formatstring | a format string as in printf |
... | further arguments as in printf |
int elektraDocCheckConf | ( | Key * | errorKey, |
KeySet * | conf | ||
) |
Validate plugin configuration at mount time.
During the mount phase the BackendBuilder calls this method, if it is provided by the plugin.
In this method the plugin configuration can be checked for validity or integrity. Missing items can be added to complete the configuration.
errorKey | is used to propagate error messages to the caller |
conf | contains the plugin configuration to be validated |
0 | on success: the configuration was OK and has not been changed. |
1 | on success: the configuration has been changed and now it is OK. |
-1 | on failure: the configuration was not OK and could not be fixed. Set an error using ELEKTRA_SET_ERROR to inform the user what went wrong. Additionally you can add any number of warnings with ELEKTRA_ADD_WARNING. |
int elektraDocClose | ( | Plugin * | handle, |
Key * | warningsKey | ||
) |
Finalize the plugin.
Called prior to unloading the plugin dynamic module. After this function is called, it is ensured that no functions from your plugin will ever be accessed again.
Make sure to free all memory that your plugin requested at runtime. Also make sure to free what you stored by elektraPluginSetData() before.
So for the Doc plugin we need to:
After this call, libelektra.so will unload the plugin library, so this is the point to shutdown any affairs with the storage.
handle | contains internal information of the plugin |
warningsKey | can be used to to add warnings using ELEKTRA_ADD_WARNING (Do not add errors!) |
1 | on success (no other return value currently allowed) |
-1 | on problems (only use ELEKTRA_ADD_WARNING, but never set an error). |
int elektraDocError | ( | Plugin * | handle, |
KeySet * | returned, | ||
Key * | parentKey | ||
) |
Rollback in case of errors.
First for all plugins elektraDocSet() will be called. If any plugin had problems before the commit (done by the resolver plugin), we can safely rollback our changes.
This method is rarely used by plugins, it is mainly used for resolvers (to implement rollback) or by logging plugins. It is not needed for storage plugins, because they only operate on temporary files created by the resolver.
handle | contains internal information of the plugin |
returned | contains a keyset with relevant keys |
parentKey | contains the information where to set the keys. can be used to add warnings with the macro ELEKTRA_ADD_WARNING, but do not add errors! |
1 | on success |
0 | on success with no action |
-1 | on failure (you can add warnings, but we are already in an error state, so do not set the error). |
int elektraDocGet | ( | Plugin * | handle, |
KeySet * | returned, | ||
Key * | parentKey | ||
) |
Get data from storage to application.
Retrieve information from a permanent storage to construct a keyset.
The elektraDocGet() function handle everything related to receiving keys.
The contract is a keyset that needs to be returned if the parentKey is system/elektra/modules/yourpluginname.
Which keys and their meaning is specified in doc/CONTRACT.ini
Here is an example for our doc plugin:
Some clauses of the contract, especially the description of the plugin can be done more conveniently directly in a README.md that is included by ELEKTRA_README.
For storage plugins the filename is written in the value of the parentKey. So the first task of the plugin is to open that file. Then it should parse its content and construct a keyset with all information of that file.
You need to be able to reconstruct the same file with the information of the keyset. So be sure to copy all comments, whitespaces and so on into some metadata of the keys. Otherwise the information is lost after writing the file the next time.
Now lets look at an example how the typical elektraDocGet() might be implemented. To explain we introduce some pseudo functions which do all the work with the storage (which is of course 90% of the work for a real plugin):
The typical loop for a storage plugin will be like:
When opening files, make sure to use the macros ELEKTRA_SET_ERROR_SET and ELEKTRA_SET_ERROR_GET for errors, as shown here:
For filter plugins the actual task is rather unspecified. You basically can do anything with the keyset. To get roundtrip properties you might want to undo any changes you did in elektraDocSet().
The pseudo functions (which do the real work) are:
all
keys related to your plugin.returned
has the parentKey
and all keys below (keyIsBelow()) with all information from the storage. Make sure to return all keys, all directories and also all hidden keys. If some of them are not wished, the caller kdbGet() will drop these keys with additional plugins.handle | contains internal information of opened key database |
returned | contains a keyset where the function need to append the keys got from the storage. There might be also some keys inside it, see conditions. You may use them to support efficient updating of keys, see updating. |
parentKey | contains the information below which key the keys should be gotten. |
1 | on success |
0 | when nothing was to do |
-1 | on failure, the current key in returned shows the position. use ELEKTRA_SET_ERROR of kdberrors.h to define the error code. You additionally can add as many warnings as you would like to add. |
int elektraDocOpen | ( | Plugin * | handle, |
Key * | warningsKey | ||
) |
Initialize data for the plugin.
This is the first method called after dynamically loading this plugin. It is guaranteed, that this method will be called before any other method.
This method is responsible for:
You may also read the configuration you can get with elektraPluginGetConfig() and transform it into other structures used by your plugin.
Instead of global variables the methods elektraPluginGetData() and elektraPluginSetData() exist to store and get any information related to your plugin.
The correct substitute for global variables will be:
and then initialize it using:
Make sure to free everything you allocate within elektraDocClose().
If your plugin has no useful way to startup without config, the module loader would not be able to load the module. We need, however, to still load the plugin to get the contract.
To solve that problem the module loader adds the configuration key /module. Even if your plugin is basically not able to startup successfully, it should still provide a fallback when /module is present, so that elektraDocGet() on system/elektra/modules can be called successfully later on.
Note that for plugins where the contract will be altered based on configuration this specific configuration should be considered. In fact the idea of /module is to get the correct contract.
-1 | on error, your plugin will be removed then and the missing plugin added instead. Use ELEKTRA_ADD_WARNING to indicate the problem. The system will automatically add the information that the plugin was removed, so you do not need the user give that information. |
1 | on success |
handle | contains internal information of the plugin |
warningsKey | can be used to add warnings with the macro ELEKTRA_ADD_WARNING (Do not add errors!) |
int elektraDocSet | ( | Plugin * | handle, |
KeySet * | returned, | ||
Key * | parentKey | ||
) |
Set data from application to storage.
This function does everything related to set and remove keys in a plugin. There is only one function for that purpose to make implementation of file based plugins much easier.
The keyset returned
was filled in with information from the application using elektra and the task of this function is to store it in a permanent way so that a subsequent call of elektraPluginGet() can rebuild the keyset as it was before. See the live cycle to understand:
Of course all information of every key in the keyset returned
need to be stored permanently. So this specification needs to give an exhaustive list of information present in a key.
returned
holds all keys which must be saved permanently for this keyset. The keyset is sorted and rewinded.parentKey
is the key which is the ancestor for all other keys in the keyset. The first key of the keyset returned
has the same keyname. The name of the parentKey marks the mountpoint. The string of the parentKey is the filename to write to.Make sure to set all keys, all directories and also all hidden keys. If some of them are not wished, the caller kdbSet() and plugins will sort them out.
returned
is stored permanently.handle | contains internal information of the plugin |
returned | contains a keyset with relevant keys |
parentKey | contains the information where to set the keys (name is mountpoint your plugin is mounted, string is the file to write to) |
1 | on success |
0 | on success with no changed key in database |
-1 | on failure. The cause of the error needs to be added in parentKey You also have to make sure that ksGetCursor() shows to the position where the error appeared. Set an error using ELEKTRA_SET_ERROR to inform the user what went wrong. Additionally you can add any number of warnings with ELEKTRA_ADD_WARNING. |
Plugin* elektraPluginExport | ( | const char * | pluginName, |
... | |||
) |
Allows one to Export Methods for a Plugin.
This function must be called within ELEKTRA_PLUGIN_EXPORT. It define the plugin's methods that will be exported.
All KDB methods implemented by the plugin basically could have random names (convention is elektraName*), except ELEKTRA_PLUGIN_EXPORT.
This is the single symbol that will be looked up when loading the plugin, and the first method of the backend implementation that will be called.
You need to use a macro so that both dynamic and static loading of the plugin works. For example for the doc plugin:
The first parameter is the name of the plugin. Then every plugin should have: ELEKTRA_PLUGIN_OPEN
, ELEKTRA_PLUGIN_CLOSE
, ELEKTRA_PLUGIN_GET
, ELEKTRA_PLUGIN_SET
and optionally ELEKTRA_PLUGIN_ERROR
.
The list is terminated with ELEKTRA_PLUGIN_END
.
You must use static "char arrays" in a read only segment. Don't allocate storage, it won't be freed.
pluginName | the name of this plugin |
KeySet* elektraPluginGetConfig | ( | Plugin * | handle | ) |
Returns the configuration of that plugin.
So prefer cascading lookups to honor both.
handle | a pointer to the plugin |
void* elektraPluginGetData | ( | Plugin * | plugin | ) |
Get a pointer to any plugin related data stored before.
If elektraPluginSetData() was not called earlier, NULL will be returned.
plugin | a pointer to the plugin |
KeySet* elektraPluginGetGlobalKeySet | ( | Plugin * | plugin | ) |
Get a pointer to the global keyset.
Initialized for all plugins by the KDB, except for manually created plugins with elektraPluginOpen()
. The global keyset is tied to a KDB handle, initialized on kdbOpen()
and deleted on kdbClose()
.
Plugins using this keyset are responsible for cleaning up their parts of the keyset which they do not need any more.
plugin | a pointer to the plugin |
void elektraPluginSetData | ( | Plugin * | plugin, |
void * | data | ||
) |
Store a pointer to any plugin related data.
plugin | a pointer to the plugin |
data | the pointer to the data |