/* 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_abstractsession.h -*-C++-*- #ifndef INCLUDED_BLPAPI_ABSTRACTSESSION #define INCLUDED_BLPAPI_ABSTRACTSESSION //@PURPOSE: A common interface shared between publish and consumer sessions. // //@CLASSES: // blpapi::AbstractSession: shared interface between different session types. // //@SEE_ALSO: blpapi_session, blpapi_providersession // //@DESCRIPTION: This file defines an abstract class 'AbstractSession' - an // interfaces which are shared between its concrete implementations 'Session' // and 'ProviderSession'. // // SERVICE IDENTIFIER // ------------------ // A service identifier is the fully qualified service name which uniquely // identifies the service in the API infrastructure. // A service must be of the form "//<namespace>/<local-name>" where // '<namespace>' and '<local-name>' are non-empty strings of characters from // the set '[-_.a-zA-Z0-9]'. Service identifiers are case-insensitive, but // clients are encouraged to prefer identifiers without upper-case characters. // Note that the <namespace> and <local-name> cannot contain the character // '/'. #ifndef INCLUDED_BLPAPI_CORRELATIONID #include <blpapi_correlationid.h> #endif #ifndef INCLUDED_BLPAPI_DEFS #include <blpapi_defs.h> #endif #ifndef INCLUDED_BLPAPI_EVENT #include <blpapi_event.h> #endif #ifndef INCLUDED_BLPAPI_EVENTDISPATCHER #include <blpapi_eventdispatcher.h> #endif #ifndef INCLUDED_BLPAPI_IDENTITY #include <blpapi_identity.h> #endif #ifndef INCLUDED_BLPAPI_REQUEST #include <blpapi_request.h> #endif #ifndef INCLUDED_BLPAPI_SERVICE #include <blpapi_service.h> #endif #ifndef INCLUDED_BLPAPI_TYPES #include <blpapi_types.h> #endif #ifdef __cplusplus extern "C" { #endif // All of the blpapi_UserHandle_* functions have been deprecated. Please use // blpapi_Identity_* versions of these functions instead. BLPAPI_EXPORT void blpapi_UserHandle_release(blpapi_UserHandle_t *handle); BLPAPI_EXPORT int blpapi_UserHandle_addRef(blpapi_UserHandle_t *handle); BLPAPI_EXPORT int blpapi_UserHandle_hasEntitlements( const blpapi_UserHandle_t *handle, const blpapi_Service_t *service, const blpapi_Element_t *eidElement, const int *entitlementIds, size_t numEntitlements, int *failedEntitlements, int *failedEntitlementsCount); BLPAPI_EXPORT int blpapi_AbstractSession_cancel( blpapi_AbstractSession_t *session, const blpapi_CorrelationId_t *correlationIds, size_t numCorrelationIds, const char *requestLabel, int requestLabelLen); BLPAPI_EXPORT int blpapi_AbstractSession_sendAuthorizationRequest( blpapi_AbstractSession_t *session, const blpapi_Request_t *request, blpapi_Identity_t *identity, blpapi_CorrelationId_t *correlationId, blpapi_EventQueue_t *eventQueue, const char *requestLabel, int requestLabelLen); BLPAPI_EXPORT int blpapi_AbstractSession_openService( blpapi_AbstractSession_t *session, const char *serviceIdentifier); BLPAPI_EXPORT int blpapi_AbstractSession_openServiceAsync( blpapi_AbstractSession_t *session, const char *serviceIdentifier, blpapi_CorrelationId_t *correlationId); BLPAPI_EXPORT int blpapi_AbstractSession_generateToken( blpapi_AbstractSession_t *session, blpapi_CorrelationId_t *correlationId, blpapi_EventQueue_t *eventQueue); BLPAPI_EXPORT int blpapi_AbstractSession_getService( blpapi_AbstractSession_t *session, blpapi_Service_t **service, const char *serviceIdentifier); BLPAPI_EXPORT blpapi_Identity_t *blpapi_AbstractSession_createIdentity( blpapi_AbstractSession_t *session); #ifdef __cplusplus } #ifndef INCLUDED_VECTOR #include <vector> #define INCLUDED_VECTOR #endif namespace BloombergLP { namespace blpapi { typedef Identity UserHandle; // ===================== // class AbstractSession // ===================== class AbstractSession { // This class provides an abstract session which defines shared interface // between publish and consumer requests for Bloomberg // // Sessions manage access to services either by requests and // responses or subscriptions. A Session can dispatch events and // replies in either a synchronous or asynchronous mode. The mode // of a Session is determined when it is constructed and cannot be // changed subsequently. // // A Session is asynchronous if an EventHandler object is // supplied when it is constructed. The setEventHandler() method // may be called to adjust the way events are handled subsequently // and the nextEvent() method may not be called. All incoming // events are delivered to the EventHandler(s) supplied on // construction or subsequently using setEventHandler(). // // A Session is synchronous if an EventHandler object is not // supplied when it is constructed. The nextEvent() method must be // called to read incoming events and the setEventHandler() method // may not be called. // // Several methods in Session take a CorrelationId parameter. The // application may choose to supply its own CorrelationId values // or allow the Session to create values. If the application // supplies its own CorrelationId values it must manage their // lifetime such that the same value is not reused for more than // one operation at a time. The lifetime of a CorrelationId begins // when it is supplied in a method invoked on a Session and ends // either when it is explicitly cancelled using cancel() or // unsubscribe(), when a RESPONSE Event (not a PARTIAL_RESPONSE) // containing it is received or when a SUBSCRIPTION_STATUS Event // which indicates that the subscription it refers to has been // terminated is received. // // When using an asynchronous Session the application must be // aware that because the callbacks are generated from another // thread they may be processed before the call which generates // them has returned. For example, the SESSION_STATUS Event // generated by a startAsync() may be processed before // startAsync() has returned (even though startAsync() itself will // not block). // // This becomes more significant when Session generated // CorrelationIds are in use. For example, if a call to // subscribe() which returns a Session generated CorrelationId has // not completed before the first Events which contain that // CorrelationId arrive the application may not be able to // interpret those events correctly. For this reason, it is // preferable to use user generated CorrelationIds when using // asynchronous Sessions. This issue does not arise when using a // synchronous Session as long as the calls to subscribe() etc are // made on the same thread as the calls to nextEvent(). blpapi_AbstractSession_t *d_handle_p; private: // NOT IMPLEMENTED AbstractSession(const AbstractSession&); AbstractSession& operator=(const AbstractSession&); protected: AbstractSession(); // Create an abstract session object. void initAbstractSessionHandle(blpapi_AbstractSession_t *handle); // Initialize the handle of this abstract session. public: virtual ~AbstractSession(); // Destructor. // MANIPULATORS virtual bool start() = 0; // Attempt to start this Session and blocks until the Session // has started or failed to start. If the Session is started // successfully 'true' is returned, otherwise 'false' is // returned. Before start() returns a SESSION_STATUS Event is // generated. If this is an asynchronous Session then the // SESSION_STATUS may be processed by the registered // EventHandler before start() has returned. A Session may // only be started once. virtual bool startAsync() = 0; // Attempt to begin the process to start this Session and // return 'true' if successful, otherwise return 'false'. The // application must monitor events for a SESSION_STATUS Event // which will be generated once the Session has started or if // it fails to start. If this is an asynchronous Session then // the SESSION_STATUS Event may be processed by the registered // EventHandler before startAsync() has returned. A Session may // only be started once. virtual void stop() = 0; // Stop operation of this session and block until all callbacks to // EventHandler objects relating to this Session which are currently in // progress have completed (including the callback to handle the // SESSION_STATUS Event with SessionTerminated message this call // generates). Once this returns no further callbacks to EventHandlers // will occur. If stop() is called from within an EventHandler callback // the behavior is undefined and may result in a deadlock. Once a // Session has been stopped it can only be destroyed. virtual void stopAsync() = 0; // Begin the process to stop this Session and return immediately. The // application must monitor events for a SESSION_STATUS Event with // SessionTerminated message which will be generated once the // Session has been stopped. After this SESSION_STATUS Event no further // callbacks to EventHandlers will occur. This method can be called // from within an EventHandler callback to stop Sessions using // non-default (external) EventDispatcher. Once a Session has been // stopped it can only be destroyed. virtual Event nextEvent(int timeout=0) = 0; // Return the next available Event for this session. If there // is no event available this will block for up to the // specified 'timeoutMillis' milliseconds for an Event to // arrive. A value of 0 for 'timeoutMillis' (the default) // indicates nextEvent() should not timeout and will not // return until the next Event is available. // // If nextEvent() returns due to a timeout it will return an // event of type 'EventType::TIMEOUT'. // // If this is invoked on a Session which was created in // asynchronous mode an InvalidStateException is thrown. virtual int tryNextEvent(Event *event) = 0; // If there are Events available for the session, load the next Event // into event and return 0 indicating success. If there is no event // available for the session, return a non-zero value with no effect // on event. This method never blocks. bool openService(const char *serviceIdentifier); // Attempt to open the service identified by the specified // 'serviceIdentifier' and block until the service is either opened // successfully or has failed to be opened. Return 'true' if // the service is opened successfully and 'false' if the // service cannot be successfully opened. // // The 'serviceIdentifier' must contain a fully qualified service name. // That is, it must be of the form "//<namespace>/<local-name>". // // Before openService() returns a SERVICE_STATUS Event is // generated. If this is an asynchronous Session then this // Event may be processed by the registered EventHandler // before openService() has returned. CorrelationId openServiceAsync( const char *serviceIdentifier, const CorrelationId& correlationId = CorrelationId()); // Begin the process to open the service identified by the // specified 'serviceIdentifier' and return immediately. The optional // specified 'correlationId' is used to track Events generated // as a result of this call. The actual correlationId which // will identify Events generated as a result of this call is // returned. // // The 'serviceIdentifier' must contain a fully qualified service name. // That is, it must be of the form "//<namespace>/<local-name>". // // The application must monitor events for a SERVICE_STATUS // Event which will be generated once the service has been // successfully opened or the opening has failed. CorrelationId sendAuthorizationRequest( const Request& authorizationRequest, Identity *identity, const CorrelationId& correlationId=CorrelationId(), EventQueue *eventQueue=0); // Send the specified 'authorizationRequest' and update the // specified 'identity' with the results. If the optionally // specified 'correlationId' is supplied, it is used; otherwise // create a CorrelationId. The actual CorrelationId used is // returned. If the optionally specified 'eventQueue' is // supplied all Events relating to this Request will arrive on // that EventQueue. // // The underlying user information must remain valid until the // Request has completed successfully or failed. // // A successful request will generate zero or more // PARTIAL_RESPONSE Messages followed by exactly one RESPONSE // Message. Once the final RESPONSE Message has been received // the specified 'identity' will have been updated to contain // the users entitlement information and the CorrelationId // associated with the request may be re-used. If the request // fails at any stage a REQUEST_STATUS will be generated, the // specified 'identity' will not be modified and the // CorrelationId may be re-used. // // The 'identity' supplied must have been returned from this // Session's createIdentity() method. For example //.. // Identity handle(session.createIdentity()); // session.sendAuthorizationRequest(authRequest, &handle, ...) //.. void cancel(const CorrelationId& correlationId); // If the specified 'correlationId' identifies a current // request then cancel that request. // // Once this call returns the specified 'correlationId' will // not be seen in any subsequent Message obtained from a // MessageIterator by calling next(). However, any Message // currently pointed to by a MessageIterator when // cancel() is called is not affected even if it has the // specified 'correlationId'. Also any Message where a // reference has been retained by the application may still // contain the 'correlationId'. For these reasons, although // technically an application is free to re-use // 'correlationId' as soon as this method returns it is // preferable not to aggressively re-use correlation IDs, // particularly with an asynchronous Session. void cancel(const std::vector<CorrelationId>& correlationIds); // For each value in the specified 'correlationIds' which // identifies a current request then cancel that request. Any // values in the specified 'correlationIds' which do not // identify a current request are ignored. // // Once this call returns the specified 'correlationIds' will // not be seen in any subsequent Message obtained from a // MessageIterator by calling next(). However, any Message // currently pointed to by a MessageIterator when // cancel() is called is not affected even if it has one // of the specified 'correlationIds'. Also any Message where a // reference has been retained by the application may still // contain one of the 'correlationIds'. For these reasons, // although technically an application is free to re-use any // of the 'correlationIds' as soon as this method returns it // is preferable not to aggressively re-use correlation IDs, // particularly with an asynchronous Session. void cancel(const CorrelationId *correlationIds, size_t numCorrelationIds); // For each value specified 'correlationIds' and // 'numCorrelationIds' which identifies a current request then // cancel that request. Any specified CorrelationId's which do // not identify a current request are ignored. // // Once this call returns the specified 'correlationIds' will // not be seen in any subsequent Message obtained from a // MessageIterator by calling next(). However, any Message // currently pointed to by a MessageIterator when // cancel() is called is not affected even if it has one // of the specified 'correlationIds'. Also any Message where a // reference has been retained by the application may still // contain one of the 'correlationIds'. For these reasons, // although technically an application is free to re-use any // of the 'correlationIds' as soon as this method returns it // is preferable not to aggressively re-use correlation IDs, // particularly with an asynchronous Session. CorrelationId generateToken( const CorrelationId& correlationId = CorrelationId(), EventQueue *eventQueue = 0); // Generate a token to be used for authorization. // If invalid authentication option is specified in session option or // there is failure to get authentication information based on // authentication option, then an InvalidArgumentException is thrown. // ACCESSORS Service getService(const char *serviceIdentifier) const; // Return a Service object representing the service // identified by the specified 'serviceIdentifier' // // The 'serviceIdentifier' must contain a fully qualified service name. // That is, it must be of the form "//<namespace>/<local-name>". // // If the service identified by 'serviceIdentifier' is not open or // registered already then a 'NotFoundException' is thrown. UserHandle createUserHandle(); // Deprecated: Use createIdentity() instead. TODO: doxy // Return a UserHandle which is valid but has not been // authorized. Identity createIdentity(); // Return a Identity which is valid but has not been // authorized. blpapi_AbstractSession_t *abstractSessionHandle() const; // Return the handle of this abstract session. }; //============================================================================= // INLINE FUNCTION DEFINITIONS //============================================================================= // --------------------- // class AbstractSession // --------------------- inline AbstractSession::AbstractSession() : d_handle_p(0) { } inline AbstractSession::~AbstractSession() { } inline void AbstractSession::initAbstractSessionHandle(blpapi_AbstractSession_t *handle) { d_handle_p = handle; } inline Service AbstractSession::getService(const char *serviceIdentifier) const { blpapi_Service_t *service; ExceptionUtil::throwOnError( blpapi_AbstractSession_getService(d_handle_p, &service, serviceIdentifier)); return service; } inline CorrelationId AbstractSession::sendAuthorizationRequest( const Request& authorizationRequest, Identity *identity, const CorrelationId& correlationId, EventQueue *eventQueue) { CorrelationId retCorrelationId(correlationId); ExceptionUtil::throwOnError( blpapi_AbstractSession_sendAuthorizationRequest( d_handle_p, authorizationRequest.handle(), identity->handle(), const_cast<blpapi_CorrelationId_t *>(&retCorrelationId.impl()), eventQueue ? eventQueue->handle() : 0, 0, 0)); return retCorrelationId; } inline void AbstractSession::cancel(const CorrelationId& correlationId) { blpapi_AbstractSession_cancel(d_handle_p, &correlationId.impl(), 1, 0, 0); } inline void AbstractSession::cancel(const std::vector<CorrelationId>& correlationIds) { if (!correlationIds.size()) { return; } cancel(&correlationIds[0], correlationIds.size()); } inline void AbstractSession::cancel(const CorrelationId *correlationIds, size_t numCorrelationIds) { blpapi_AbstractSession_cancel( d_handle_p, reinterpret_cast<const blpapi_CorrelationId_t*>(correlationIds), numCorrelationIds, 0, 0); } inline CorrelationId AbstractSession::generateToken( const CorrelationId& correlationId, EventQueue *eventQueue) { CorrelationId retCorrelationId(correlationId); ExceptionUtil::throwOnError(blpapi_AbstractSession_generateToken( d_handle_p, const_cast<blpapi_CorrelationId_t *>(&retCorrelationId.impl()), eventQueue ? eventQueue->handle() : 0)); return retCorrelationId; } inline bool AbstractSession::openService(const char *serviceIdentifier) { return blpapi_AbstractSession_openService(d_handle_p, serviceIdentifier) ? false : true; } inline CorrelationId AbstractSession::openServiceAsync( const char *serviceIdentifier, const CorrelationId& correlationId) { blpapi_CorrelationId_t retv = correlationId.impl(); ExceptionUtil::throwOnError( blpapi_AbstractSession_openServiceAsync( d_handle_p, serviceIdentifier, &retv)); return retv; } inline UserHandle AbstractSession::createUserHandle() { return blpapi_AbstractSession_createIdentity(d_handle_p); } inline Identity AbstractSession::createIdentity() { return blpapi_AbstractSession_createIdentity(d_handle_p); } inline blpapi_AbstractSession_t *AbstractSession::abstractSessionHandle() const { return d_handle_p; } } // close namespace blpapi } // close namespace BloombergLP #endif // #ifdef __cplusplus #endif // #ifndef INCLUDED_BLPAPI_ABSTRACTSESSION