Apama 10.15.0 | Connecting Apama Applications to External Components | Working with Connectivity Plug-ins | Developing Connectivity Plug-ins | Requirements of a plug-in class
 
Requirements of a plug-in class
Java and C++ plug-ins are identified in the connectivityPlugins section of the configuration file for the connectivity plug-ins. See Configuration file for connectivity plug-ins for detailed information.
The named class must be a descendent of either AbstractCodec or AbstractTransport, unless it is a transport with a dynamic chain manager in which case the class must subclass AbstractChainManager (see Requirements of a transport chain manager plug-in class for more information about developing chain managers).
In most cases, the easiest way to write codec and transport classes is by subclassing AbstractSimpleCodec or AbstractSimpleTransport. However, in some cases, a plug-in can achieve better performance by directly subclassing the base class AbstractCodec or AbstractTransport; these classes support handling a batch of multiple messages in a single call.
The classes are summarized in the following table. They are all in the com.softwareag.connectivity package (Java) or in the com::softwareag::connectivity namespace (C++). See the API Reference for Java (Javadoc) and API Reference for C++ (Doxygen) for more information.
Base class
Subclasses deal in
Minimum methods subclasses need to implement
AbstractCodec
Batches of messages
sendBatchTowardsTransport, sendBatchTowardsHost
AbstractTransport
Batches of messages
sendBatchTowardsTransport
AbstractSimpleCodec
Individual messages
transformMessageTowardsHost, transformMessageTowardsTransport
Note that every message results in at most one message out.
AbstractSimpleTransport
Individual messages
deliverMessageTowardsTransport
All of the above classes also provide members or default implementations of:
*Member chainId
*Member config
*Member logger for logging (see below)
*Member hostSide - the next component in the chain towards the host
*Member transportSide - the next component in the chain towards the transport (for codecs only)
*start
*hostReady
*shutdown
The start, hostReady and shutdown methods can be overridden if required. See also Lifetime of connectivity plug-ins.
Plug-in class constructor
Subclasses should provide a constructor like the following, for Java:
public <ClassName>(org.slf4j.Logger logger,
TransportConstructorParameters params) throws Exception,
IllegalArgumentException {
super(logger, params);
...
}
or for C++:
public:
<ClassName>(const TransportConstructorParameters &params)
: AbstractSimpleTransport(params)
{
...
}
The constructors for codecs follow the same pattern as for transports. The TransportConstructorParameters or CodecConstructorParameters object provides access to the plug-in's configuration and other useful information and capabilities, some of which are also made available as member fields for convenience.
Note that transports with an associated dynamic chain manager are created by the chain manager's createTransport method (for Java) or must have a public constructor with signature (const ManagedTransportConstructorParameters &, ...) where ... are any extra parameters passed in the createChain call (for C++).
In both Java and C++, there is a logger available using the logger field (for Java, this is also passed into the constructor). Note that all messages logged using the logger will include the chainId and pluginName, so there is no need to explicitly add that information to each message. See the API Reference for Java (Javadoc) and API Reference for C++ (Doxygen) for detailed information.
Using AbstractSimpleCodec and AbstractSimpleTransport
The AbstractSimpleCodec and AbstractSimpleTransport classes handle batches by iterating through each message within a batch and calling one of the methods listed above for each message. For Java codecs, the result of the transform method replaces that message in the batch. For C++ codecs, the transform method passes a reference to a message which can be mutated or the message discarded if the method returns false. By default, messages with a null payload are ignored by the AbstractSimpleCodec and AbstractSimpleTransport classes, but subclasses may override methods to handle them (see the API Reference for Java (Javadoc) and API Reference for C++ (Doxygen) for details).
Exceptions from processing one message are logged by default (this behavior can be overridden by implementing handleException) and the next message is then processed.
To deliver events to the correlator, transports call the sendBatchTowardsHost method on the hostSide member of AbstractSimpleTransport, passing a batch of messages as a List<Message> (they can use Collections.singletonList() if needed).
Using AbstractCodec and AbstractTransport
Chains are bidirectional, passing events to and from the correlator. The order of plug-ins within a chain is defined by the configuration file: first the host plug-in, then codecs, and finally a transport. Plug-ins are connected such that the hostSide and transportSide members of AbstractCodec point to the previous and next plug-in in the chain; and for AbstractTransport, hostSide points to the last codec (or the host plug-in if there are no codecs).
Events from the correlator are sent to the first codec (or transport if there are no codecs). Each codec should pass the message through to the next component, invoking the sendBatchTowardsTransport method on the transportSide member.
Events to the correlator originate from the transport and are delivered by invoking the sendBatchTowardsHost method on the hostSide member which delivers the events to the last codec. The last codec should invoke the sendBatchTowardsHost method on its hostSide object, thus traversing plug-ins in the reverse order. For Java, transports must always provide hostSide a batch of messages as a List<Message> (they can use Collections.singletonList() if needed). For C++ plug-ins, the batches are passed as a pair of start and end pointers to Message. The batch is defined as starting from the message pointed to by start and up to just before the message pointed to by end - similar to begin() and end() iterators on C++ containers. Thus, the messages in a batch can be iterated with a loop such as:
for (Message *it = start; it != end; ++it) {
handleMessage(*it);
}
Plug-ins are provided with a HostSide and (for codecs only) TransportSide interface view of the next component in the chain (as members of AbstractTransport or AbstractCodec).
Codecs are not required to maintain a one-to-one mapping of events going in and out. They may choose to discard or merge multiple messages or split a message into separate messages.
Exporting the required symbols from C++ plug-ins
C++ plug-ins also require a macro which exports the symbols that the correlator needs to create and manage the plug-in object. The macro has one of the following names:
*SAG_DECLARE_CONNECTIVITY_TRANSPORT_CLASS(class-name)
This macro should not be used for transports with a chain manager.
*SAG_DECLARE_CONNECTIVITY_CODEC_CLASS(class-name)
*SAG_DECLARE_CONNECTIVITY_TRANSPORT_CHAIN_MANAGER_CLASS(class-name)
This macro is used for exporting a chain manager class.
The macro takes the base name of the class - the class's name excluding any package. Software AG recommends declaring codecs and transports in a package to avoid name collisions, and using the macro within the namespace declaration, or where a using statement applies. For example:
#include <sag_connectivity_plugins.hpp>
using namespace com::softwareag::connectivity;
 
namespace my_namespace {
 
class MyTransport: public AbstractSimpleTransport
{
public:
MyTransport(const TransportConstructorParameters &params)
: AbstractSimpleTransport(params)
{
...
}
virtual void deliverMessageTowardsTransport(Message &m)
{
logger.info("deliverMessageTowardsTransport()");
}
...
};
 
SAG_DECLARE_CONNECTIVITY_TRANSPORT_CLASS(MyTransport)
} // end my_namespace
Note: 
For a chain manager, you should include the header file sag_connectivity_chain_managers.hpp instead of sag_connectivity_plugins.hpp which is used in the above example.