/* Copyright 2012. Bloomberg Finance L.P.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions: The above
* copyright notice and this permission notice shall be included in all copies
* or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
// blpapi_message.h -*-C++-*-
#ifndef INCLUDED_BLPAPI_MESSAGE
#define INCLUDED_BLPAPI_MESSAGE
//@PURPOSE: Defines a message containing elements.
//
//@CLASSES:
// blpapi::Message: individual message inside an event.
//
//@SEE_ALSO: blpapi_event
//
//@DESCRIPTION: This file defines a 'Message'. A 'Message' is contained in an
// 'Event' and contains 'Element's.
#ifndef INCLUDED_BLPAPI_CALL
#include <blpapi_call.h>
#endif
#ifndef INCLUDED_BLPAPI_CORRELATIONID
#include <blpapi_correlationid.h>
#endif
#ifndef INCLUDED_BLPAPI_DEFS
#include <blpapi_defs.h>
#endif
#ifndef INCLUDED_BLPAPI_ELEMENT
#include <blpapi_element.h>
#endif
#ifndef INCLUDED_BLPAPI_SERVICE
#include <blpapi_service.h>
#endif
#ifndef INCLUDED_BLPAPI_TIMEPOINT
#include <blpapi_timepoint.h>
#endif
struct blpapi_Message;
typedef struct blpapi_Message blpapi_Message_t;
#ifdef __cplusplus
extern "C" {
#endif
BLPAPI_EXPORT
blpapi_Name_t* blpapi_Message_messageType(
const blpapi_Message_t *message);
BLPAPI_EXPORT
const char* blpapi_Message_typeString(
const blpapi_Message_t *message);
BLPAPI_EXPORT
const char* blpapi_Message_topicName(
const blpapi_Message_t *message);
BLPAPI_EXPORT
blpapi_Service_t* blpapi_Message_service(
const blpapi_Message_t *message);
BLPAPI_EXPORT
int blpapi_Message_numCorrelationIds(
const blpapi_Message_t *message);
BLPAPI_EXPORT
blpapi_CorrelationId_t blpapi_Message_correlationId(
const blpapi_Message_t *message,
size_t index);
BLPAPI_EXPORT
blpapi_Element_t* blpapi_Message_elements(
const blpapi_Message_t *message);
BLPAPI_EXPORT
const char *blpapi_Message_privateData(
const blpapi_Message_t *message,
size_t *size);
BLPAPI_EXPORT
int blpapi_Message_fragmentType(
const blpapi_Message_t *message);
BLPAPI_EXPORT
int blpapi_Message_addRef(const blpapi_Message_t *message);
BLPAPI_EXPORT
int blpapi_Message_release(const blpapi_Message_t *message);
BLPAPI_EXPORT
int blpapi_Message_timeReceived(
const blpapi_Message_t *message,
blpapi_TimePoint_t *timeReceived);
#ifdef __cplusplus
}
namespace BloombergLP {
namespace blpapi {
// =============
// class Message
// =============
class Message {
// A handle to a single message.
//
// Message objects are obtained from a MessageIterator. Each
// Message is associated with a Service and with one or more
// CorrelationId values. The Message contents are represented as
// an Element and some convenient shortcuts are supplied to the
// Element accessors.
//
// A Message is a handle to a single underlying protocol
// message. The underlying messages are reference counted - the
// underlying Message object is freed when the last Message object
// which references it is destroyed.
blpapi_Message_t *d_handle;
Element d_elements;
bool d_isCloned;
public:
enum Fragment {
// A message could be split into more than one fragments to reduce
// each message size. This enum is used to indicate whether a message
// is a fragmented message and the position in the fragmented messages.
FRAGMENT_NONE = 0, // message is not fragmented
FRAGMENT_START, // the first fragmented message
FRAGMENT_INTERMEDIATE, // intermediate fragmented messages
FRAGMENT_END // the last fragmented message
};
public:
// CREATORS
Message(blpapi_Message_t *handle, bool clonable = false);
// Construct the Message with the specified 'handle' and set the
// isCloned flag with the specified value of 'clonable'. This flag
// will used to release reference on message handle when the
// destructor is called.
Message(const Message& original);
// Construct the message using the handle of the original. This will
// add a reference to the handle and set the d_isCloned flag to true,
// to ensure that release reference is called when destructor is
// invoked.
~Message();
// Destroy this message. Call release reference on handle if the
// d_isCloned is set.
// MANIUPLATORS
Message& operator=(const Message& rhs);
// Copies the message specified by 'rhs' into the current message and
// set the d_isCloned flag with the specified value of 'true'. This
// flag will used to release reference on message handle when the
// destructor is called.
// ACCESSORS
Name messageType() const;
// Returns the type of this message.
const char* topicName() const;
// Returns a pointer to a null-terminated string containing
// the topic string associated with this message. If there is
// no topic associated with this message then an empty string
// is returned. The pointer returned remains valid until the
// Message is destroyed.
Service service() const;
// Returns the service which sent this Message.
int numCorrelationIds() const;
// Returns the number of CorrelationIds associated with this
// message.
//
// Note: A Message will have exactly one CorrelationId unless
// 'allowMultipleCorrelatorsPerMsg' option was enabled for the
// Session this Message came from. When
// 'allowMultipleCorrelatorsPerMsg' is disabled (the default)
// and more than one active subscription would result in the
// same Message the Message is delivered multiple times
// (without making physical copied). Each Message is
// accompanied by a single CorrelationId. When
// 'allowMultipleCorrelatorsPerMsg' is enabled and more than
// one active subscription would result in the same Message
// the Message is delivered once with a list of corresponding
// CorrelationId values.
CorrelationId correlationId(size_t index=0) const;
// Returns the specified 'index'th CorrelationId associated
// with this message. If 'index'>=numCorrelationIds()
// then an exception is thrown.
bool hasElement(const Name& name, bool excludeNullElements=false) const;
bool hasElement(const char* name, bool excludeNullElements=false) const;
// Equivalent to asElement().hasElement(name).
size_t numElements() const;
// Equivalent to asElement().numElements().
const Element getElement(const Name& name) const;
// Equivalent to asElement().getElement(name).
const Element getElement(const char* name) const;
// Equivalent to asElement().getElement(name).
bool getElementAsBool(const Name& name) const;
bool getElementAsBool(const char* name) const;
// Equivalent to asElement().getElementAsBool(name).
char getElementAsChar(const Name& name) const;
char getElementAsChar(const char* name) const;
// Equivalent to asElement().getElementAsChar(name).
Int32 getElementAsInt32(const Name& name) const;
Int32 getElementAsInt32(const char* name) const;
// Equivalent to asElement().getElementAsInt32(name).
Int64 getElementAsInt64(const Name& name) const;
Int64 getElementAsInt64(const char* name) const;
// Equivalent to asElement().getElementAsInt64(name).
Float32 getElementAsFloat32(const Name& name) const;
Float32 getElementAsFloat32(const char* name) const;
// Equivalent to asElement().getElementAsFloat32(name).
Float64 getElementAsFloat64(const Name& name) const;
Float64 getElementAsFloat64(const char* name) const;
// Equivalent to asElement().getElementAsFloat64(name).
Datetime getElementAsDatetime(const Name& name) const;
Datetime getElementAsDatetime(const char* name) const;
// Equivalent to asElement().getElementAsDatetime(name).
const char* getElementAsString(const Name& name) const;
const char* getElementAsString(const char* name) const;
// Equivalent to asElement().getElementAsString(name).
const Element asElement() const;
// Returns the contents of this Message as a read-only
// Element. The Element returned remains valid until this
// Message is destroyed.
const char *getPrivateData(size_t *size) const;
// Return a raw pointer to the message private data if it had any. If
// 'size' is a valid pointer (not 0), it will be filled with the size
// of the private data. If the message has no private data attached to
// it the return value is 0 and the 'size' pointer (if valid) is set to
// 0.
Fragment fragmentType() const;
// Return fragment type of this message. The return value is a value
// of enum Fragment to indicate whether it is a fragmented message of a
// big message and its positions in fragmentation if it is.
int timeReceived(TimePoint *timestamp) const;
// Load into the specified 'timestamp', the time when the message was
// received by the sdk. This method will fail if there is no timestamp
// associated with Message. On failure, the 'timestamp' is not
// modified. Return 0 on success and a non-zero value otherwise.
// Note that by default the subscription data messages are not
// timestamped (but all the other messages are). To enable recording
// receive time for subscription data, set
// 'SessionOptions::recordSubscriptionDataReceiveTimes'.
std::ostream& print(std::ostream& stream,
int level=0,
int spacesPerLevel=4) const;
// Format this Message to the specified output 'stream' at the
// (absolute value of) the optionally specified indentation
// 'level' and return a reference to 'stream'. If 'level' is
// specified, optionally specify 'spacesPerLevel', the number
// of spaces per indentation level for this and all of its
// nested objects. If 'level' is negative, suppress indentation
// of the first line. If 'spacesPerLevel' is negative, format
// the entire output on one line, suppressing all but the
// initial indentation (as governed by 'level').
const blpapi_Message_t* impl() const;
// Returns the internal implementation.
blpapi_Message_t* impl();
// Returns the internal implementation.
};
// FREE OPERATORS
std::ostream& operator<<(std::ostream& stream, const Message &message);
// Write the value of the specified 'message' object to the specified
// output 'stream' in a single-line format, and return a reference to
// 'stream'. If 'stream' is not valid on entry, this operation has no
// effect. Note that this human-readable format is not fully specified,
// can change without notice, and is logically equivalent to:
//..
// print(stream, 0, -1);
//..
// ============================================================================
// INLINE AND TEMPLATE FUNCTION IMPLEMENTATIONS
// ============================================================================
// -------------
// class Message
// -------------
// CREATORS
inline
Message::Message(blpapi_Message_t *handle, bool clonable)
: d_handle(handle)
, d_isCloned(clonable)
{
if (handle) {
d_elements = Element(blpapi_Message_elements(handle));
}
}
inline
Message::Message(const Message& original)
: d_handle(original.d_handle)
, d_elements(original.d_elements)
, d_isCloned(true)
{
if (d_handle) {
BLPAPI_CALL_MESSAGE_ADDREF(d_handle);
}
}
inline
Message::~Message()
{
if (d_isCloned && d_handle) {
BLPAPI_CALL_MESSAGE_RELEASE(d_handle);
}
}
// MANIPULATORS
inline
Message& Message::operator=(const Message& rhs)
{
if (this == &rhs) {
return *this;
}
if (d_isCloned && (d_handle == rhs.d_handle)) {
return *this;
}
if (d_isCloned && d_handle) {
BLPAPI_CALL_MESSAGE_RELEASE(d_handle);
}
d_handle = rhs.d_handle;
d_elements = rhs.d_elements;
d_isCloned = true;
if (d_handle) {
BLPAPI_CALL_MESSAGE_ADDREF(d_handle);
}
return *this;
}
// ACCESSORS
inline
Name Message::messageType() const
{
return Name(blpapi_Message_messageType(d_handle));
}
inline
const char* Message::topicName() const
{
return blpapi_Message_topicName(d_handle);
}
inline
Service Message::service() const
{
return Service(blpapi_Message_service(d_handle));
}
inline
int Message::numCorrelationIds() const
{
return blpapi_Message_numCorrelationIds(d_handle);
}
inline
CorrelationId Message::correlationId(size_t index) const
{
if (index >= (size_t)numCorrelationIds())
throw IndexOutOfRangeException("index >= numCorrelationIds");
return CorrelationId(blpapi_Message_correlationId(d_handle, index));
}
inline
bool Message::hasElement(const char* name,
bool excludeNullElements) const
{
return d_elements.hasElement(name, excludeNullElements);
}
inline
bool Message::hasElement(const Name& name,
bool excludeNullElements) const
{
return d_elements.hasElement(name, excludeNullElements);
}
inline
size_t Message::numElements() const
{
return d_elements.numElements();
}
inline
const Element Message::getElement(const Name& name) const
{
return d_elements.getElement(name);
}
inline
const Element Message::getElement(const char* nameString) const
{
return d_elements.getElement(nameString);
}
inline
bool Message::getElementAsBool(const Name& name) const
{
return d_elements.getElementAsBool(name);
}
inline
bool Message::getElementAsBool(const char* name) const
{
return d_elements.getElementAsBool(name);
}
inline
char Message::getElementAsChar(const Name& name) const
{
return d_elements.getElementAsChar(name);
}
inline
char Message::getElementAsChar(const char* name) const
{
return d_elements.getElementAsChar(name);
}
inline
Int32 Message::getElementAsInt32(const Name& name) const
{
return d_elements.getElementAsInt32(name);
}
inline
Int32 Message::getElementAsInt32(const char* name) const
{
return d_elements.getElementAsInt32(name);
}
inline
Int64 Message::getElementAsInt64(const Name& name) const
{
return d_elements.getElementAsInt64(name);
}
inline
Int64 Message::getElementAsInt64(const char* name) const
{
return d_elements.getElementAsInt64(name);
}
inline
Float32 Message::getElementAsFloat32(const Name& name) const
{
return d_elements.getElementAsFloat32(name);
}
inline
Float32 Message::getElementAsFloat32(const char* name) const
{
return d_elements.getElementAsFloat32(name);
}
inline
Float64 Message::getElementAsFloat64(const Name& name) const
{
return d_elements.getElementAsFloat64(name);
}
inline
Float64 Message::getElementAsFloat64(const char* name) const
{
return d_elements.getElementAsFloat64(name);
}
inline
Datetime Message::getElementAsDatetime(const Name& name) const
{
return d_elements.getElementAsDatetime(name);
}
inline
Datetime Message::getElementAsDatetime(const char* name) const
{
return d_elements.getElementAsDatetime(name);
}
inline
const char* Message::getElementAsString(const Name& name) const
{
return d_elements.getElementAsString(name);
}
inline
const char* Message::getElementAsString(const char* name) const
{
return d_elements.getElementAsString(name);
}
inline
const Element Message::asElement() const
{
return d_elements;
}
inline
const char *Message::getPrivateData(size_t *size) const
{
return blpapi_Message_privateData(d_handle, size);
}
inline
Message::Fragment Message::fragmentType() const
{
return (Message::Fragment) BLPAPI_CALL_MESSAGE_FRAGMENTTYPE(d_handle);
}
inline
int Message::timeReceived(TimePoint *timestamp) const
{
return BLPAPI_CALL_MESSAGE_TIMERECEIVED(
d_handle,
timestamp);
}
inline
std::ostream& Message::print(
std::ostream& stream,
int level,
int spacesPerLevel) const
{
return d_elements.print(stream, level, spacesPerLevel);
}
inline
std::ostream& operator<<(std::ostream& stream, const Message &message)
{
return message.print(stream, 0,-1);
}
inline
const blpapi_Message_t* Message::impl() const
{
return d_handle;
}
inline
blpapi_Message_t* Message::impl()
{
return d_handle;
}
} // close namespace blpapi
} // close namespace BloombergLP
#endif // #ifdef __cplusplus
#endif // #ifndef INCLUDED_BLPAPI_MESSAGE