/* 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_event.h -*-C++-*-
#ifndef INCLUDED_BLPAPI_EVENT
#define INCLUDED_BLPAPI_EVENT
//@PURPOSE: A component which defines events related operations
//
//@CLASSES:
// blpapi::Event: an event resulting from a subscription or request.
// blpapi::EventQueue: A construct to handle replies synchronously.
// blpapi::MessageIterator: An iterator over the Messages within an Event.
//
//@DESCRIPTION: This file defines an 'Event'. One or more 'Event's are
// generated as a result of a subscription or a request. Events contain Message
// objects which can be accessed using a 'MessageIterator'. This file also
// defines a 'EventQueue' for handling replies synchronously.
//
///Usage
///-----
// The following code snippet shows a how a 'EventQueue' is used with a
// 'generateToken' request. For any established session 'session' pass an
// 'EventQueue' object 'tokenEventQueue' when calling 'generateToken'.
// All Events in responses to 'generateToken' request will be returned in
// 'tokenEventQueue'.
//..
// //...
// EventQueue tokenEventQueue;
// session->generateToken(CorrelationId(), &tokenEventQueue);
//..
// Synchronously read the response 'event' and parse over messages using 'iter'
//..
// Event event = tokenEventQueue.nextEvent();
// if (event.eventType() == Event::TOKEN_STATUS) {
// MessageIterator iter(event);
// while (iter.next()) {
// Message msg = iter.message();
// //...
//..
#ifndef INCLUDED_BLPAPI_MESSAGE
#include <blpapi_message.h>
#endif
#ifndef INCLUDED_BLPAPI_DEFS
#include <blpapi_defs.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
BLPAPI_EXPORT
int blpapi_Event_eventType(
const blpapi_Event_t *event);
BLPAPI_EXPORT
int blpapi_Event_addRef(
const blpapi_Event_t *event);
BLPAPI_EXPORT
int blpapi_Event_release(
const blpapi_Event_t *event);
BLPAPI_EXPORT
blpapi_EventQueue_t* blpapi_EventQueue_create(void);
BLPAPI_EXPORT
int blpapi_EventQueue_destroy(blpapi_EventQueue_t* eventQueue);
BLPAPI_EXPORT
blpapi_Event_t* blpapi_EventQueue_nextEvent(
blpapi_EventQueue_t *eventQueue,
int timeout);
BLPAPI_EXPORT
int blpapi_EventQueue_purge(blpapi_EventQueue_t *eventQueue);
BLPAPI_EXPORT
int blpapi_EventQueue_tryNextEvent(
blpapi_EventQueue_t *eventQueue,
blpapi_Event_t **eventPointer);
BLPAPI_EXPORT
blpapi_MessageIterator_t* blpapi_MessageIterator_create(
const blpapi_Event_t *event);
BLPAPI_EXPORT
void blpapi_MessageIterator_destroy(
blpapi_MessageIterator_t* iterator);
BLPAPI_EXPORT
int blpapi_MessageIterator_next(
blpapi_MessageIterator_t* iterator,
blpapi_Message_t** result);
#ifdef __cplusplus
}
namespace BloombergLP {
namespace blpapi {
// ===========
// class Event
// ===========
class Event {
// A single event resulting from a subscription or a request.
//
// Event objects are created by the API and passed to the
// application either through a registered EventHandler or
// EventQueue or returned from the Session::nextEvent()
// method. Event objects contain Message objects which can be
// accessed using a MessageIterator.
//
// The Event object is a handle to an event. The event is the
// basic unit of work provided to applications. Each Event object
// consists of an EventType attribute and zero or more Message
// objects. The underlying event data including the messages is
// reference counted - as long as at least one Event object still
// exists then the underlying data will not be freed.
blpapi_Event_t *d_impl_p;
public:
enum EventType {
// The possible types of event
ADMIN = BLPAPI_EVENTTYPE_ADMIN,
// Admin event
SESSION_STATUS = BLPAPI_EVENTTYPE_SESSION_STATUS,
// Status updates for a session.
SUBSCRIPTION_STATUS = BLPAPI_EVENTTYPE_SUBSCRIPTION_STATUS,
// Status updates for a subscription.
REQUEST_STATUS = BLPAPI_EVENTTYPE_REQUEST_STATUS,
// Status updates for a request.
RESPONSE = BLPAPI_EVENTTYPE_RESPONSE,
// The final (possibly only) response to a request.
PARTIAL_RESPONSE = BLPAPI_EVENTTYPE_PARTIAL_RESPONSE,
// A partial response to a request.
SUBSCRIPTION_DATA = BLPAPI_EVENTTYPE_SUBSCRIPTION_DATA,
// Data updates resulting from a subscription.
SERVICE_STATUS = BLPAPI_EVENTTYPE_SERVICE_STATUS,
// Status updates for a service.
TIMEOUT = BLPAPI_EVENTTYPE_TIMEOUT,
// An Event returned from nextEvent() if it timed out.
AUTHORIZATION_STATUS = BLPAPI_EVENTTYPE_AUTHORIZATION_STATUS,
// Status updates for user authorization.
RESOLUTION_STATUS = BLPAPI_EVENTTYPE_RESOLUTION_STATUS,
// Status updates for a resolution operation.
TOPIC_STATUS = BLPAPI_EVENTTYPE_TOPIC_STATUS,
// Status updates about topics for service providers.
TOKEN_STATUS = BLPAPI_EVENTTYPE_TOKEN_STATUS,
// Status updates for a generate token request.
REQUEST = BLPAPI_EVENTTYPE_REQUEST,
// Request event
UNKNOWN = -1
};
Event();
// Construct an uninitialized Event. The only valid operations
// on an uninitialized Event are assignment, isValid() and
// destruction.
Event(blpapi_Event_t *handle);
Event(const Event& original);
// Copy constructor. This performs a shallow copy, increasing
// the reference count on the actual data underlying this
// handle.
~Event();
// Destructor. If this is the last reference to this Event
// then the underlying data (including all Messages associated
// with the Event) are invalidated.
// MANIPULATORS
Event& operator=(const Event& rhs);
// Assignment operator. This performs a shallow assignment,
// increasing the reference count on the actual data
// underlying this handle.
// ACCESSORS
EventType eventType() const;
// Returns the type of messages contained by this Event.
bool isValid() const;
// Returns true if this Event is a valid event.
blpapi_Event_t* impl() const;
};
// ================
// class EventQueue
// ================
class EventQueue {
// A construct used to handle replies to request synchronously.
//
// An EventQueue can be supplied when using Session::sendRequest()
// and Session::sendAuthorizationRequest() methods.
//
// When a request is submitted an application can either handle
// the responses asynchronously as they arrive or use an
// EventQueue to handle all responses for a given request or
// requests synchronously. The EventQueue will only deliver
// responses to the request(s) it is associated with.
blpapi_EventQueue_t *d_handle_p;
public:
EventQueue();
// Construct an empty event queue.
~EventQueue();
// Destroy this event queue and cancel any pending request
// that are linked to this queue.
// MANIPULATORS
Event nextEvent(int timeout=0);
// Returns the next Event available from the EventQueue. If
// the specified 'timeout' is zero this will wait forever for
// the next event. If the specified 'timeout' is non zero then
// if no Event is available within the specified 'timeout' an
// Event with a type() of TIMEOUT will be returned.
int tryNextEvent(Event *event);
// If the EventQueue is non-empty, load the next Event available
// into event and return 0 indicating success. If the EventQueue is
// empty, return a non-zero value with no effect on event or the
// the state of EventQueue. This method never blocks.
void purge();
// Purges any Event objects in this EventQueue which have not
// been processed and cancel any pending requests linked to
// this EventQueue. The EventQueue can subsequently be
// re-used for a subsequent request.
blpapi_EventQueue_t* handle() const;
};
// =====================
// class MessageIterator
// =====================
class MessageIterator {
// An iterator over the Message objects within an Event.
//
// MessageIterator objects are used to process the individual
// Message objects in an Event received in an EventHandler, from
// EventQueue::nextEvent() or from Session::nextEvent().
//
// This class is used to iterate over each message in an
// Event. The user must ensure that the Event this iterator is
// created for is not destroyed before the iterator.
blpapi_MessageIterator_t *d_impl_p;
blpapi_Message_t *d_current_p;
private:
// NOT IMPLEMENTED
MessageIterator(const MessageIterator&);
MessageIterator& operator=(const MessageIterator&);
public:
MessageIterator(const Event& event);
// Construct a forward iterator to iterate over the message in
// the specified 'event' object. The MessageIterator is
// created in a state where next() must be called to advance
// it to the first item.
~MessageIterator();
// Destructor.
// MANIPULATORS
bool next();
// Attempts to advance this MessageIterator to the next
// Message in this Event. Returns 0 on success and non-zero if
// there are no more messages. After next() returns 0
// isValid() returns true, even if called repeatedly until the
// next call to next(). After next() returns non-zero then
// isValid() always returns false.
// ACCESSORS
bool isValid() const;
// Returns true if this iterator is currently positioned on a
// valid Message. Returns false otherwise.
Message message(bool createClonable=false) const;
// Returns the Message at the current position of this iterator. If the
// specified 'createClonable' flag is set, the internal handle of the
// message returned is added a reference and the message can outlive
// the call to next(). If the 'createClonable' flag is set to false,
// the use of message outside the scope of the iterator or after the
// next() call is undefined.
// The behavior is undefined if isValid() returns false.
};
//=============================================================================
// INLINE FUNCTION DEFINITIONS
//=============================================================================
// -----------
// class Event
// -----------
inline
Event::Event()
: d_impl_p(0)
{
}
inline
Event::Event(blpapi_Event_t *handle)
: d_impl_p(handle)
{
}
inline
Event::Event(const Event& original)
: d_impl_p(original.d_impl_p)
{
if (d_impl_p) {
blpapi_Event_addRef(d_impl_p);
}
}
inline
Event::~Event()
{
if (d_impl_p) {
blpapi_Event_release(d_impl_p);
}
}
inline
Event& Event::operator=(const Event& rhs)
{
if (this == &rhs) {
return *this;
}
if (d_impl_p) {
blpapi_Event_release(d_impl_p);
}
d_impl_p = rhs.d_impl_p;
if (d_impl_p) {
blpapi_Event_addRef(d_impl_p);
}
return *this;
}
inline
Event::EventType Event::eventType() const
{
return (EventType) blpapi_Event_eventType(d_impl_p);
}
inline
bool Event::isValid() const
{
return d_impl_p ? true : false;
}
inline
blpapi_Event_t* Event::impl() const
{
return d_impl_p;
}
// ----------------
// class EventQueue
// ----------------
inline
EventQueue::EventQueue()
{
d_handle_p = blpapi_EventQueue_create();
}
inline
EventQueue::~EventQueue()
{
blpapi_EventQueue_destroy(d_handle_p);
}
inline
Event EventQueue::nextEvent(int timeout)
{
return blpapi_EventQueue_nextEvent(d_handle_p, timeout);
}
inline
int EventQueue::tryNextEvent(Event *event)
{
blpapi_Event_t *impl;
int ret = blpapi_EventQueue_tryNextEvent(d_handle_p, &impl);
if(0 == ret) {
*event = Event(impl);
}
return ret;
}
inline
void EventQueue::purge()
{
blpapi_EventQueue_purge(d_handle_p);
}
inline
blpapi_EventQueue_t* EventQueue::handle() const
{
return d_handle_p;
}
// ---------------------
// class MessageIterator
// ---------------------
inline
MessageIterator::MessageIterator(const Event& event)
: d_impl_p(0)
, d_current_p(0)
{
d_impl_p = blpapi_MessageIterator_create(event.impl());
}
inline
MessageIterator::~MessageIterator()
{
blpapi_MessageIterator_destroy(d_impl_p);
}
inline
bool MessageIterator::next()
{
return !blpapi_MessageIterator_next(d_impl_p, &d_current_p);
}
inline
bool MessageIterator::isValid() const
{
return d_current_p ? true : false;
}
inline
Message MessageIterator::message(bool createClonable) const
{
if (createClonable) {
BLPAPI_CALL_MESSAGE_ADDREF(d_current_p);
}
return Message(d_current_p, createClonable);
}
} // close namespace blpapi
} // close namespace BloombergLP
#endif // #ifdef __cplusplus
#endif // #ifndef INCLUDED_BLPAPI_EVENT