Developing Apama Applications > Developing Correlator Plug-ins > Advanced Plug-in Functionality in C++ and C > The complete example
The complete example
The following complete listing of complex_plugin.cpp contains the implementation of the ComplexPlugin:: methods and the ExampleChunk class. The implementation of ComplexPlugin::test1 is particularly interesting as it demonstrates how to use the functionality provided by the EPL Plug-in C++ API to examine the type of a parameter and act accordingly.
The equivalent C example is supplied in the installation as complex_plugin.c in the samples/c folder of the Apama installation.
The Plug-in initialization and shutdown methods are as used within simple_plugin.

/**
* complex_plugin.cpp
*
* A more interesting example plugin.
*
* $Copyright(c) 2013 Software AG, Darmstadt, Germany and/or its licensors$
*
* $RCSfile$ $Revision: 188571 $ $Date: 2012-07-17 19:13:07 +0100 (Tue, 17 Jul 2012)$
*/
 
/**
** Please read and understand simple_plugin.cpp before using this file!
**/
 
#include <correlator_plugin.hpp>
#include <iostream>
#include <string>
#include <vector>
#include <math.h>
 
using std::cout;
using std::endl;
 
/**
* Plugin implementation class.
*/
class ComplexPlugin {
 
public:
/**
* Plugin function that dynamically decodes and displays its
* arguments, and modifies them for return to the caller where
* possible.
*/
static void AP_PLUGIN_CALL test1(
const AP_Context& ctx, const AP_TypeList& args,
AP_Type& rval, AP_TypeDiscriminator);
 
/**
* Plugin function that allocates and returns a new ExampleChunk
* opaque object.
*/
static void AP_PLUGIN_CALL test3(
const AP_Context& ctx, const AP_TypeList& args,
AP_Type& rval, AP_TypeDiscriminator);
 
/**
* Plugin function that uses an ExampleChunk created by test3().
*/
static void AP_PLUGIN_CALL test4(
const AP_Context& ctx, const AP_TypeList& args,
AP_Type& rval, AP_TypeDiscriminator);
 
/**
* Helper method to display the contents of an AP_Type and, if it
* is a sequence, modify the elements
*/
static void DumpAP_Type(const AP_Type& arg);
 
/**
* Helper method to modify the contents of an AP_Type
*/
static void ModifyAP_Type(AP_Type& arg);
};
 
/**
* Simple 'chunk' class demonstrating how opaque, plugin-private data
* may be passed between plugin functions by MonitorScript. Note that
* every chunk class must be derived from AP_Chunk.
*/
class ExampleChunk : public AP_Chunk {
public:
/**
* Construct an ExampleChunk containing the specified number of
* floating-point values.
*/
explicit ExampleChunk(size_t size=2048);
 
/**
* Note that we can rely on the default copy constructor and
* destructor
*/
 
/**
* Copy method creates a new ExampleChunk that is an exact duplicate
* of the current object. This method must be provided by every chunk
* class, so that the Engine can assign to and from chunk objects.
*/
AP_Chunk* copy(const AP_Context& ctx) const;
 
/**
* Print out the contents of the chunk
*/
void print() const;
 
/** The contents of this chunk */
std::vector<float64> data;
};
 
/**
* Implementation of test1 and test2 plugin functions.
*/
void AP_PLUGIN_CALL ComplexPlugin::test1(
const AP_Context& ctx, const AP_TypeList& args,
AP_Type& rval, AP_TypeDiscriminator) {
// Display all the input parameters
cout << "test1(): arg list length = " << args.size() << endl;
for (uint32 i = 0; i < args.size(); i++) {
DumpAP_Type(args[i]);
}
 
// Set the return value appropriately for its type. Note the use
// of overloaded assignment operators to store values of various
// types in an AP_Type object.
switch (rval.discriminator()) {
case AP_NULL_TYPE:
// 'void' return; no value needed
break;
case AP_CHUNK_TYPE: {
// Create a new chunk
rval = new ExampleChunk;
break;
}
case AP_INTEGER_TYPE:
// Some compilers require this cast to distinguish between
// integer and boolean assignment.
rval = (int64)42;
break;
case AP_FLOAT_TYPE:
// Make sure that float literals include a decimal point (or use
// scientific notation) so that float, rather than integer or
// boolean, assignment is used here.
rval = 2.71828;
break;
case AP_BOOLEAN_TYPE:
rval = false;
break;
case AP_STRING_TYPE:
// String value will be copied by the assignment
rval = "Hello, World";
break;
case AP_SEQUENCE_TYPE:
// Sequence returns are not yet supported
throw AP_UnimplementedException("test1(): Attempt to return sequence from plugin");
break;
default:
// Unknown return type
throw AP_TypeException("test1(): Unknown return type in plugin");
}
}
 
/**
* Implementation of test3 plugin function.
*/
void AP_PLUGIN_CALL ComplexPlugin::test3(
const AP_Context& ctx, const AP_TypeList& args,
AP_Type& rval, AP_TypeDiscriminator) {
// args[0] contains desired size for chunk.
ExampleChunk* chunk = new ExampleChunk(args[0].integerValue());
 
// Put known values in the chunk data
for (uint32 i = 0; i < chunk->data.size(); i++) {
chunk->data[i] = i;
}
 
// Print chunk contents
chunk->print();
 
// Return the new chunk object
rval = chunk;
}
 
/**
* Implementation of test4 plugin function.
*/
void AP_PLUGIN_CALL ComplexPlugin::test4(
const AP_Context& ctx, const AP_TypeList& args,
AP_Type& rval, AP_TypeDiscriminator) {
// Extract the chunk object from args[0], making sure to cast it to the
// correct derived type (the plugin must know what this should be)
ExampleChunk* chunk = (ExampleChunk*)(args[0].chunkValue());
 
// Do some computation on the chunk data
for (uint32 i = 0; i < chunk->data.size(); i++) {
chunk->data[i] = sqrt(chunk->data[i]);
}
 
// Print chunk contents
chunk->print();
}
 
/**
* Dump the contents of arg to cout. Sequences will be recursively
* expanded and modified.
*/
void ComplexPlugin::DumpAP_Type(const AP_Type& arg) {
cout << "discriminator = " << arg.discriminator() << endl;
switch (arg.discriminator()) {
case AP_NULL_TYPE: {
cout << "null type has no value" << endl;
break;
}
case AP_CHUNK_TYPE: {
cout << "chunk type is opaque" << endl;
break;
}
case AP_INTEGER_TYPE: {
cout << "integer value = " << arg.integerValue() << endl;
break;
}
case AP_FLOAT_TYPE: {
cout << "float value = " << arg.floatValue() << endl;
break;
}
case AP_BOOLEAN_TYPE: {
cout << "boolean value = " << arg.booleanValue() << endl;
break;
}
case AP_STRING_TYPE: {
cout << "string value = " << arg.stringValue() << endl;
break;
}
case AP_SEQUENCE_TYPE: {
cout << "sequence type = " << arg.sequenceType() << endl;
cout << "sequence size = " << arg.sequenceLength() << endl;
for (uint32 i = 0; i < arg.sequenceLength(); i++) {
cout << "sequence element[" << i << "]: ";
DumpAP_Type(arg[i]);
ModifyAP_Type(arg[i]);
}
break;
}
default: {
cout << "unknown discriminator value" << endl;
}
}
}
 
/**
* Modify a value, if possible
*
* Note that if the argument is a sequence, it doesn't modify the
* elements - that's handled by DumpAP_Type.
*/
void ComplexPlugin::ModifyAP_Type(AP_Type& arg) {
switch (arg.discriminator()) {
case AP_INTEGER_TYPE:
arg = arg.integerValue() + 1;
break;
case AP_FLOAT_TYPE:
arg = arg.floatValue() * 2.0;
break;
case AP_BOOLEAN_TYPE:
arg = !arg.booleanValue();
break;
case AP_STRING_TYPE:
arg = "How long is a piece of string?";
break;
default:
break;
}
}
 
 
/**
* ExampleChunk constructor.
*/
ExampleChunk::ExampleChunk(size_t size) : data(size) {
cout << "ExampleChunk constructor called with size = " << size << endl;
}
 
/**
* ExampleChunk copy method. Implements virtual method declared by AP_Chunk
* interface.
*/
AP_Chunk* ExampleChunk::copy(const AP_Context &) const {
return new ExampleChunk(*this);
}
 
/**
* Print the contents of the chunk.
*/
void ExampleChunk::print() const {
cout << "Chunk size = " << data.size() << endl;
for (uint32 i = 0; i < data.size(); i++) {
cout << "Chunk element [" << i << "] = " << data[i] << endl;
}
}
 
/** Parameter types for the plugin functions */
static const char8* test1ParamTypes[4] = { "integer", "float",
"boolean", "string" };
static const char8* test2ParamTypes[4] = { "sequence<integer>",
"sequence<float>", "sequence<boolean>",
"sequence<string>" };
static const char8* test3ParamTypes[1] = { "integer" };
static const char8* test4ParamTypes[1] = { "chunk" };
 
/** Declare functions provided by this plugin */
static AP_Function Functions[4] = {
{ "test1", &ComplexPlugin::test1, 4, &test1ParamTypes[0], "string" },
{ "test2", &ComplexPlugin::test1, 4, &test2ParamTypes[0], "float" },
{ "test3", &ComplexPlugin::test3, 1, &test3ParamTypes[0], "chunk" },
{ "test4", &ComplexPlugin::test4, 1, &test4ParamTypes[0], "void" }
};
 
/**
* Initialisation and shutdown functions. Must be declared extern "C" so that
* the plugin loader can look them up by name. Signatures must match the
* AP_InitFunctionPtr and AP_ShutdownFunctionPtr typedefs, respectively.
* Likewise, the function names must use the AP_INIT_FUNCTION_NAME and
* AP_SHUTDOWN_FUNCTION_NAME macros.
*/
extern "C" {
 
/**
* Plugin initialisation function. Called each time the plugin library is
* loaded, so must expect to be called more than once.
*
* @param ctx Execution context for the function call.
* @param version Active plugin API version. The plugin should verify it
* is compatible with this version (and return AP_VERSION_MISMATCH_ERROR
* if not) and update version to indicate the API version the plugin was
* compiled against.
* @param nFunctions The plugin should set this to the number of functions
* it exports.
* @param functions The plugin should set this to the address of an array
* of AP_Functions structures, of length nFunctions, describing the
* functions exported by the plugin. This data will be read and copied by
* the plugin API.
*
* @return An AP_ErrorCode indicating the success or otherwise of the
* library initialisation.
*/
AP_PLUGIN_DLL_SYM AP_ErrorCode AP_PLUGIN_CALL AP_INIT_FUNCTION_NAME(
const AP_Context& ctx, uint32& version, uint32&
nFunctions, AP_Function*& functions) {
version = AP_PLUGIN_VERSION;
nFunctions = 4;
functions = &Functions[0];
return AP_NO_ERROR;
}
 
/**
* Plugin shutdown function. Called each time the plugin library is
* unloaded, so must expect to be called more than once.
*
* @param ctx Execution context for the function call.
*
* @return An AP_ErrorCode indicating the success or otherwise of the
* library initialisation.
*/
AP_PLUGIN_DLL_SYM AP_ErrorCode AP_PLUGIN_CALL AP_SHUTDOWN_FUNCTION_NAME(
const AP_Context& ctx) {
return AP_NO_ERROR;
}
 
/**
* Plugin library version function.
*
* @param ctx Execution context for the function call.
*
* @param version The plugin should fill this in with the version of the
* API it was compiled against.
*
* @return An AP_ErrorCode indicating the success or otherwise of the
* function call.
*/
AP_PLUGIN_DLL_SYM AP_ErrorCode AP_PLUGIN_CALL AP_LIBRARY_VERSION_FUNCTION_NAME(
const AP_Context& ctx, uint32& version) {
// Just return the version number
version = AP_PLUGIN_VERSION;
return AP_NO_ERROR;
}
 
/**
* Plugin capabilities function.
*
* @param ctx Execution context for the function call.
*
* @return An AP_Capabilities bitset describing the capabilities of this
* plugin.
*/
AP_PLUGIN_DLL_SYM AP_Capabilities AP_PLUGIN_CALL
AP_PLUGIN_GET_CAPABILITIES_FUNCTION_NAME(
const AP_Context& ctx) {
// This plugin promises no special capabilities. But if you wanted to
// declare any, you could return them, or-ed together.
return AP_CAPABILITIES_NONE;
}
 
} // extern "C"
Copyright © 2013-2015 Software AG, Darmstadt, Germany and/or Software AG USA Inc., Reston, VA, USA, and/or its subsidiaries and/or its affiliates and/or their licensors.
Use, reproduction, transfer, publication or disclosure is prohibited except as specifically provided for in your License Agreement with Software AG.