OnixS C++ FIX Engine  4.3.0
API Documentation
Decoding Data using SBE Event-based decoder

This section describes the usage of the OnixS::FIX::SBE::EventBasedDecoder class together with OnixS::FIX::SBE::IDecodeListener interface.

General considerations

SBE decoder could be used in a callback mode, which called 'event based' one. Within this mode, decoder does not create FIX message by itself, but instead of this, it notifies a user about different stages of the decoding process. These notification are sent using special interface (OnixS::FIX::SBE::IDecodeListener), which should be passed to the decoder as parameter of OnixS::FIX::SBE::EventBasedDecoder::decodeSingleMessage method.

See the table below to consult about decoding process stages and callbacks.

Decoder positionListener callback
Message decode beginning

Decoder just got template identifier from input SBE stream and appropriate FIX message type identifier was detected. Both identifiers are passed to the callback through appropriate parameters.
OnixS::FIX::SBE::IDecodeListener::onBeginMessage
Simple
field


Field value decoded

Decoder just decoded a simple field; it means that appropriate input data was read from the input data stream.

The "simple" term means a field of elementary or composite SBE type. The order of a field decoding corresponds exactly to order of these fields in the SBE template.

Note: When decoding results in NULL value, there is no callback performed.
OnixS::FIX::SBE::IDecodeListener::onValue

(depends on the actual field type)
Sequence
Sequence beginning

Decoder just desired that input data contains non-empty sequence (length of the sequence is not zero). No any entries were decoded yet. Note, that there are no separate call for the length field: length of the sequence is passed to the callback through appropriate parameter.

See SBE specification about <group> instruction for details about sequence tag detection scheme.
OnixS::FIX::SBE::IDecodeListener::onBeginSequence
Sequence entry
(steps repeated for each one entry of the sequence)
Entry beginning

Decoder just desired index of the current entry. This index is passed through appropriate parameter of the callback.
OnixS::FIX::SBE::IDecodeListener::onBeginSequenceEntry
Entry body

The sequence entry could be of any type allowed by SBE specification: a simple field or embedded sequence. Therefore, the decoder will generate callback(s) here in accordance to the template specification.
Depend on a type of the entry.
Entry ended

Decoder just finished decoding of the entry.
OnixS::FIX::SBE::IDecodeListener::onEndSequenceEntry
Sequence ended

Decoder finished sequence decoding.
OnixS::FIX::SBE::IDecodeListener::onEndSequence
Message decode ended

Message decoding was successfully completed.
OnixS::FIX::SBE::IDecodeListener::onEndMessage

Error handling

Whenever decoder meets data or another error occurs, it just throws C++ exception of the OnixS::FIX::Exception type. Decoding process becomes broken, and no more callback will be performed.

Sample of the listener implementation

class MyDecodeListener : public OnixS::FIX::SBE::IDecodeListener
{
public:
MyDecodeListener()
: beginMessageCount_(0), endMessageCount_(0),
valueCount_(0),
beginSequenceCount_(0), endSequenceCount_(0),
beginSequenceEntryCount_(0), endSequenceEntryCount_(0)
{}
/////////////////////////////////////////////////////////////////////////////////////////////////
// Implementations of IDecodeListener methods
void onBeginMessage(const char * /*messageType*/, size_t /*messageTypeLength*/) ONIXS_FIXENGINE_OVERRIDE
{
++beginMessageCount_;
}
void onEndMessage() ONIXS_FIXENGINE_OVERRIDE
{
++endMessageCount_;
}
void onValue(int /*tag*/, char /*value*/) ONIXS_FIXENGINE_OVERRIDE { ++valueCount_; }
void onValue(int /*tag*/, short /*value*/) ONIXS_FIXENGINE_OVERRIDE { ++valueCount_; }
void onValue(int /*tag*/, unsigned short /*value*/) ONIXS_FIXENGINE_OVERRIDE { ++valueCount_; }
void onValue(int /*tag*/, int /*value*/) ONIXS_FIXENGINE_OVERRIDE { ++valueCount_; }
void onValue(int /*tag*/, unsigned /*value*/) ONIXS_FIXENGINE_OVERRIDE { ++valueCount_; }
void onValue(int /*tag*/, long long /*value*/) ONIXS_FIXENGINE_OVERRIDE { ++valueCount_; }
void onValue(int /*tag*/, unsigned long long /*value*/) ONIXS_FIXENGINE_OVERRIDE { ++valueCount_; }
void onValue(int /*tag*/, long long /*mantissa*/, int /*exponent*/) ONIXS_FIXENGINE_OVERRIDE { ++valueCount_; }
void onValue(int /*tag*/, float /*value*/) ONIXS_FIXENGINE_OVERRIDE { ++valueCount_; }
void onValue(int /*tag*/, double /*value*/) ONIXS_FIXENGINE_OVERRIDE { ++valueCount_; }
void onValue(int /*tag*/, const char * /*value*/, size_t /*valueLength*/) ONIXS_FIXENGINE_OVERRIDE { ++valueCount_; }
void onBeginSequence(int /*tag*/, size_t /*itemCount*/) ONIXS_FIXENGINE_OVERRIDE { ++beginSequenceCount_; }
void onEndSequence() ONIXS_FIXENGINE_OVERRIDE { ++endSequenceCount_; }
void onBeginSequenceEntry(size_t /*index*/) ONIXS_FIXENGINE_OVERRIDE { ++beginSequenceEntryCount_; }
void onEndSequenceEntry() ONIXS_FIXENGINE_OVERRIDE { ++endSequenceEntryCount_; }
/////////////////////////////////////////////////////////////////////////////////////////////////
// Other methods
void printStatistics()
{
assert(beginMessageCount_ == endMessageCount_);
assert(beginSequenceCount_ == endSequenceCount_);
assert(beginSequenceEntryCount_ == endSequenceEntryCount_);
std::cout << "Messages: " << endMessageCount_ << std::endl
<< "Fields: " << valueCount_ << std::endl
<< "Sequences: " << endSequenceCount_ << std::endl;
}
private:
unsigned beginMessageCount_;
unsigned endMessageCount_;
unsigned valueCount_;
unsigned beginSequenceCount_;
unsigned endSequenceCount_;
unsigned beginSequenceEntryCount_;
unsigned endSequenceEntryCount_;
};

Usage of event based decoder

void sbeEventBasedDecoding()
{
EngineSettings settings;
settings.listenPort(-1);
Engine::init(settings);
std::ifstream templatesStream("templates/SbeTemplates.xml");
assert(templatesStream);
const std::string XmlSbeTemplates((std::istreambuf_iterator<char>(templatesStream)), std::istreambuf_iterator<char>());
assert(!XmlSbeTemplates.empty());
Dictionary dictionary("DICT1");
SBE::EventBasedDecoder decoder(XmlSbeTemplates);
std::ifstream dataStream("data/sbeChunk.bin", std::ios_base::in | std::ios_base::binary);
assert(dataStream);
const std::string BinaryChunk((std::istreambuf_iterator<char>(dataStream)), std::istreambuf_iterator<char>());
assert(!BinaryChunk.empty());
// Following values declared as constant for illustration purposes only.
// Normally they are obtained from the data stream.
const int TemplateId = 10;
const int Version = schemaVersion();
const size_t RootBlockLength = 28;
try
{
MyDecodeListener myListener;
size_t sbeChunkLength = 0;
bool result = decoder.decodeSingleMessage(TemplateId, Version, RootBlockLength, reinterpret_cast<const unsigned char*>(BinaryChunk.data()), 0, BinaryChunk.length(), &myListener, &sbeChunkLength);
if (result)
{
std::cout << sbeChunkLength << " bytes of " << BinaryChunk.length() << " used." << std::endl;
myListener.printStatistics();
}
else
{
std::cout << "Nothing to decode" << std::endl;
}
}
catch (const OnixS::FIX::Exception &e)
{
std::cerr << e.what();
}
Engine::shutdown();
}