#ifndef __IPAACA_H__ #define __IPAACA_H_ /// ipaaca/IU/RSB protocol major version number #define IPAACA_PROTOCOL_VERSION_MAJOR 1 /// ipaaca/IU/RSB protocol minor version number #define IPAACA_PROTOCOL_VERSION_MINOR 0 /// running release number of ipaaca-c++ #define IPAACA_CPP_RELEASE_NUMBER 1 /// date of last release number increment #define IPAACA_CPP_RELEASE_DATE "2012-04-13" #ifdef IPAACA_DEBUG_MESSAGES #define IPAACA_INFO(i) std::cout << __FILE__ << ":" << __LINE__ << ": " << __func__ << "() -- " << i << std::endl; #define IPAACA_WARNING(i) std::cout << __FILE__ << ":" << __LINE__ << ": " << __func__ << "() -- WARNING: " << i << std::endl; #define IPAACA_IMPLEMENT_ME std::cout << __FILE__ << ":" << __LINE__ << ": " << __func__ << "() -- IMPLEMENT ME" << std::endl; #define IPAACA_TODO(i) std::cout << __FILE__ << ":" << __LINE__ << ": " << __func__ << "() -- TODO: " << i << std::endl; #else #define IPAACA_INFO(i) ; #define IPAACA_WARNING(i) ; #define IPAACA_IMPLEMENT_ME ; #define IPAACA_TODO(i) ; #endif /// marking pure virtual functions for extra readability #define _IPAACA_ABSTRACT_ /// value to return when reading nonexistant payload keys #define IPAACA_PAYLOAD_DEFAULT_STRING_VALUE "" #include <iostream> #include <boost/thread.hpp> #include <boost/shared_ptr.hpp> #include <boost/pointer_cast.hpp> #include <rsc/runtime/TypeStringTools.h> #include <rsb/Factory.h> #include <rsb/Handler.h> #include <rsb/Event.h> #include <rsb/converter/Repository.h> #include <rsb/converter/ProtocolBufferConverter.h> #include <rsb/converter/Converter.h> #include <rsb/rsbexports.h> #include <ipaaca.pb.h> #include <pthread.h> #include <uuid/uuid.h> //using namespace boost; using namespace rsb; using namespace rsb::filter; using namespace rsb::converter; using namespace rsb::patterns; namespace ipaaca { typedef uint32_t revision_t; /// Type of the IU event. Realized as an integer to enable bit masks for filters. typedef uint32_t IUEventType; #define IU_ADDED 1 #define IU_COMMITTED 2 #define IU_DELETED 4 #define IU_RETRACTED 8 #define IU_UPDATED 16 #define IU_LINKSUPDATED 32 /// Bit mask for receiving all events #define IU_ALL_EVENTS 63 /// Convert an int event type to a human-readable string inline std::string iu_event_type_to_str(IUEventType type) { switch(type) { case IU_ADDED: return "ADDED"; case IU_COMMITTED: return "COMMITTED"; case IU_DELETED: return "DELETED"; case IU_RETRACTED: return "RETRACTED"; case IU_UPDATED: return "UPDATED"; case IU_LINKSUPDATED: return "LINKSUPDATED"; default: return "(NOT A KNOWN SINGLE IU EVENT TYPE)"; } } /// IU access mode: PUSH means that updates are broadcast; REMOTE means that reads are RPC calls; MESSAGE means a fire-and-forget message enum IUAccessMode { IU_ACCESS_PUSH, IU_ACCESS_REMOTE, IU_ACCESS_MESSAGE }; class PayloadEntryProxy; class Payload; class IUInterface; class IU; class RemotePushIU; class IULinkUpdate; class IULinkUpdateConverter; class IUPayloadUpdate; class IUPayloadUpdateConverter; class IUStore; class FrozenIUStore; class Buffer; class InputBuffer; class OutputBuffer; /// generate a UUID as an ASCII string std::string generate_uuid_string(); /// store for (local) IUs. TODO Stores need to be unified more class IUStore: public std::map<std::string, boost::shared_ptr<IU> > { }; /// store for RemotePushIUs. TODO Stores need to be unified more class RemotePushIUStore: public std::map<std::string, boost::shared_ptr<RemotePushIU> > // TODO genericize to all remote IU types { }; /// a reentrant lock/mutex class Lock { protected: pthread_mutexattr_t _attrs; pthread_mutex_t _mutex; public: inline Lock() { pthread_mutexattr_init(&_attrs); pthread_mutexattr_settype(&_attrs, PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init(&_mutex, &_attrs); } inline ~Lock() { pthread_mutex_destroy(&_mutex); pthread_mutexattr_destroy(&_attrs); } inline void lock() { pthread_mutex_lock(&_mutex); } inline void unlock() { pthread_mutex_unlock(&_mutex); } }; typedef std::set<std::string> LinkSet; typedef std::map<std::string, LinkSet> LinkMap; class SmartLinkMap { friend std::ostream& operator<<(std::ostream& os, const SmartLinkMap& obj); friend class IUInterface; friend class IU; friend class IUConverter; public: const LinkSet& get_links(const std::string& key); const LinkMap& get_all_links(); protected: LinkMap _links; static LinkSet empty_link_set; void _add_and_remove_links(const LinkMap& add, const LinkMap& remove); void _replace_links(const LinkMap& links); }; const LinkSet EMPTY_LINK_SET; //const std::set<std::string> EMPTY_LINK_SET; //typedef boost::function<void (const std::string&, bool, IUEventType, const std::string&)> IUEventHandlerFunction; typedef boost::function<void (boost::shared_ptr<IUInterface>, IUEventType, bool)> IUEventHandlerFunction; class IUEventHandler { protected: IUEventHandlerFunction _function; IUEventType _event_mask; bool _for_all_categories; std::set<std::string> _categories; protected: inline bool _condition_met(IUEventType event_type, const std::string& category) { return ((_event_mask&event_type)!=0) && (_for_all_categories || (_categories.count(category)>0)); } public: IUEventHandler(IUEventHandlerFunction function, IUEventType event_mask, const std::string& category); IUEventHandler(IUEventHandlerFunction function, IUEventType event_mask, const std::set<std::string>& categories); //void call(Buffer* buffer, const std::string& uid, bool local, IUEventType event_type, const std::string& category); void call(Buffer* buffer, boost::shared_ptr<IUInterface> iu, bool local, IUEventType event_type, const std::string& category); typedef boost::shared_ptr<IUEventHandler> ptr; }; class Buffer { //: public boost::enable_shared_from_this<Buffer> {//{{{ friend class IU; friend class RemotePushIU; friend class CallbackIUPayloadUpdate; friend class CallbackIULinkUpdate; friend class CallbackIUCommission; protected: std::string _uuid; std::string _basename; std::string _unique_name; std::string _id_prefix; std::vector<IUEventHandler::ptr> _event_handlers; protected: _IPAACA_ABSTRACT_ virtual void _send_iu_link_update(IUInterface* iu, bool is_delta, revision_t revision, const LinkMap& new_links, const LinkMap& links_to_remove, const std::string& writer_name="undef") = 0; _IPAACA_ABSTRACT_ virtual void _send_iu_payload_update(IUInterface* iu, bool is_delta, revision_t revision, const std::map<std::string, std::string>& new_items, const std::vector<std::string>& keys_to_remove, const std::string& writer_name="undef") = 0; _IPAACA_ABSTRACT_ virtual void _send_iu_commission(IUInterface* iu, revision_t revision, const std::string& writer_name="undef") = 0; void _allocate_unique_name(const std::string& basename, const std::string& function); inline Buffer(const std::string& basename, const std::string& function) { _allocate_unique_name(basename, function); } void call_iu_event_handlers(boost::shared_ptr<IUInterface> iu, bool local, IUEventType event_type, const std::string& category); public: virtual inline ~Buffer() { } inline const std::string& unique_name() { return _unique_name; } void register_handler(IUEventHandlerFunction function, IUEventType event_mask, const std::set<std::string>& categories); void register_handler(IUEventHandlerFunction function, IUEventType event_mask = IU_ALL_EVENTS, const std::string& category=""); //_IPAACA_ABSTRACT_ virtual void add(boost::shared_ptr<IUInterface> iu) = 0; _IPAACA_ABSTRACT_ virtual boost::shared_ptr<IUInterface> get(const std::string& iu_uid) = 0; _IPAACA_ABSTRACT_ virtual std::set<boost::shared_ptr<IUInterface> > get_ius() = 0; }; //}}} class CallbackIUPayloadUpdate: public Server::Callback<IUPayloadUpdate, int> { protected: Buffer* _buffer; public: CallbackIUPayloadUpdate(Buffer* buffer); boost::shared_ptr<int> call(const std::string& methodName, boost::shared_ptr<IUPayloadUpdate> update); }; class CallbackIULinkUpdate: public Server::Callback<IULinkUpdate, int> { protected: Buffer* _buffer; public: CallbackIULinkUpdate(Buffer* buffer); public: boost::shared_ptr<int> call(const std::string& methodName, boost::shared_ptr<IULinkUpdate> update); }; class CallbackIUCommission: public Server::Callback<protobuf::IUCommission, int> { protected: Buffer* _buffer; public: CallbackIUCommission(Buffer* buffer); public: boost::shared_ptr<int> call(const std::string& methodName, boost::shared_ptr<protobuf::IUCommission> update); }; class OutputBuffer: public Buffer { //, public boost::enable_shared_from_this<OutputBuffer> {//{{{ friend class IU; friend class RemotePushIU; protected: protected: std::map<std::string, Informer<AnyType>::Ptr> _informer_store; IUStore _iu_store; Lock _iu_id_counter_lock; ServerPtr _server; protected: // informing functions void _send_iu_link_update(IUInterface* iu, bool is_delta, revision_t revision, const LinkMap& new_links, const LinkMap& links_to_remove, const std::string& writer_name="undef"); void _send_iu_payload_update(IUInterface* iu, bool is_delta, revision_t revision, const std::map<std::string, std::string>& new_items, const std::vector<std::string>& keys_to_remove, const std::string& writer_name="undef"); void _send_iu_commission(IUInterface* iu, revision_t revision, const std::string& writer_name); // remote access functions // _remote_update_links(IULinkUpdate) // _remote_update_payload(IUPayloadUpdate) // _remote_commit(protobuf::IUCommission) protected: void _publish_iu(boost::shared_ptr<IU> iu); void _retract_iu(boost::shared_ptr<IU> iu); Informer<AnyType>::Ptr _get_informer(const std::string& category); protected: OutputBuffer(const std::string& basename); void _initialize_server(); public: static boost::shared_ptr<OutputBuffer> create(const std::string& basename); ~OutputBuffer() { IPAACA_IMPLEMENT_ME } void add(boost::shared_ptr<IU> iu); boost::shared_ptr<IU> remove(const std::string& iu_uid); boost::shared_ptr<IU> remove(boost::shared_ptr<IU> iu); boost::shared_ptr<IUInterface> get(const std::string& iu_uid); std::set<boost::shared_ptr<IUInterface> > get_ius(); typedef boost::shared_ptr<OutputBuffer> ptr; }; //}}} class InputBuffer: public Buffer { //, public boost::enable_shared_from_this<InputBuffer> {//{{{ friend class IU; friend class RemotePushIU; protected: std::map<std::string, ListenerPtr> _listener_store; std::map<std::string, RemoteServerPtr> _remote_server_store; RemotePushIUStore _iu_store; // TODO genericize protected: inline void _send_iu_link_update(IUInterface* iu, bool is_delta, revision_t revision, const LinkMap& new_links, const LinkMap& links_to_remove, const std::string& writer_name="undef") { IPAACA_WARNING("(ERROR) InputBuffer::_send_iu_link_update() should never be invoked") } inline void _send_iu_payload_update(IUInterface* iu, bool is_delta, revision_t revision, const std::map<std::string, std::string>& new_items, const std::vector<std::string>& keys_to_remove, const std::string& writer_name="undef") { IPAACA_WARNING("(ERROR) InputBuffer::_send_iu_payload_update() should never be invoked") } inline void _send_iu_commission(IUInterface* iu, revision_t revision, const std::string& writer_name="undef") { IPAACA_WARNING("(ERROR) InputBuffer::_send_iu_commission() should never be invoked") } protected: RemoteServerPtr _get_remote_server(const std::string& unique_server_name); ListenerPtr _create_category_listener_if_needed(const std::string& category); void _handle_iu_events(EventPtr event); protected: InputBuffer(const std::string& basename, const std::vector<std::string>& category_interests); InputBuffer(const std::string& basename, const std::string& category_interest1); InputBuffer(const std::string& basename, const std::string& category_interest1, const std::string& category_interest2); InputBuffer(const std::string& basename, const std::string& category_interest1, const std::string& category_interest2, const std::string& category_interest3); InputBuffer(const std::string& basename, const std::string& category_interest1, const std::string& category_interest2, const std::string& category_interest3, const std::string& category_interest4); public: static boost::shared_ptr<InputBuffer> create(const std::string& basename, const std::vector<std::string>& category_interests); static boost::shared_ptr<InputBuffer> create(const std::string& basename, const std::string& category_interest1); static boost::shared_ptr<InputBuffer> create(const std::string& basename, const std::string& category_interest1, const std::string& category_interest2); static boost::shared_ptr<InputBuffer> create(const std::string& basename, const std::string& category_interest1, const std::string& category_interest2, const std::string& category_interest3); static boost::shared_ptr<InputBuffer> create(const std::string& basename, const std::string& category_interest1, const std::string& category_interest2, const std::string& category_interest3, const std::string& category_interest4); ~InputBuffer() { IPAACA_IMPLEMENT_ME } boost::shared_ptr<IUInterface> get(const std::string& iu_uid); std::set<boost::shared_ptr<IUInterface> > get_ius(); typedef boost::shared_ptr<InputBuffer> ptr; }; //}}} class IUConverter: public rsb::converter::Converter<std::string> {//{{{ public: IUConverter(); std::string serialize(const rsb::AnnotatedData& data, std::string& wire); rsb::AnnotatedData deserialize(const std::string& wireSchema, const std::string& wire); };//}}} class IUPayloadUpdate {//{{{ public: std::string uid; revision_t revision; std::string writer_name; bool is_delta; std::map<std::string, std::string> new_items; std::vector<std::string> keys_to_remove; friend std::ostream& operator<<(std::ostream& os, const IUPayloadUpdate& obj); typedef boost::shared_ptr<IUPayloadUpdate> ptr; };//}}} class IUPayloadUpdateConverter: public rsb::converter::Converter<std::string> {//{{{ public: IUPayloadUpdateConverter(); std::string serialize(const rsb::AnnotatedData& data, std::string& wire); rsb::AnnotatedData deserialize(const std::string& wireSchema, const std::string& wire); };//}}} class IULinkUpdate {//{{{ public: std::string uid; revision_t revision; std::string writer_name; bool is_delta; std::map<std::string, std::set<std::string> > new_links; std::map<std::string, std::set<std::string> > links_to_remove; friend std::ostream& operator<<(std::ostream& os, const IULinkUpdate& obj); typedef boost::shared_ptr<IULinkUpdate> ptr; };//}}} class IULinkUpdateConverter: public rsb::converter::Converter<std::string> {//{{{ public: IULinkUpdateConverter(); std::string serialize(const rsb::AnnotatedData& data, std::string& wire); rsb::AnnotatedData deserialize(const std::string& wireSchema, const std::string& wire); };//}}} class IntConverter: public rsb::converter::Converter<std::string> {//{{{ public: IntConverter(); std::string serialize(const rsb::AnnotatedData& data, std::string& wire); rsb::AnnotatedData deserialize(const std::string& wireSchema, const std::string& wire); };//}}} class Initializer { public: static void initialize_ipaaca_rsb_if_needed(); static bool initialized(); protected: static bool _initialized; }; class PayloadEntryProxy//{{{ { protected: Payload* _payload; std::string _key; public: PayloadEntryProxy(Payload* payload, const std::string& key); PayloadEntryProxy& operator=(const std::string& value); operator std::string(); operator long(); operator double(); inline std::string to_str() { return operator std::string(); } inline long to_int() { return operator long(); } inline double to_float() { return operator double(); } };//}}} class Payload//{{{ { friend std::ostream& operator<<(std::ostream& os, const Payload& obj); friend class IUInterface; friend class IU; friend class RemotePushIU; friend class IUConverter; friend class CallbackIUPayloadUpdate; protected: std::string _owner_name; std::map<std::string, std::string> _store; boost::shared_ptr<IUInterface> _iu; protected: void initialize(boost::shared_ptr<IUInterface> iu); inline void _set_owner_name(const std::string& name) { _owner_name = name; } void _remotely_enforced_wipe(); void _remotely_enforced_delitem(const std::string& k); void _remotely_enforced_setitem(const std::string& k, const std::string& v); void _internal_replace_all(const std::map<std::string, std::string>& new_contents, const std::string& writer_name=""); void _internal_set(const std::string& k, const std::string& v, const std::string& writer_name=""); void _internal_remove(const std::string& k, const std::string& writer_name=""); public: inline const std::string& owner_name() { return _owner_name; } // access PayloadEntryProxy operator[](const std::string& key); inline void set(const std::string& k, const std::string& v) { _internal_set(k, v); } inline void remove(const std::string& k) { _internal_remove(k); } std::string get(const std::string& k); typedef boost::shared_ptr<Payload> ptr; };//}}} class IUInterface {//{{{ friend class IUConverter; friend std::ostream& operator<<(std::ostream& os, const IUInterface& obj); protected: IUInterface(); public: inline virtual ~IUInterface() { } protected: std::string _uid; revision_t _revision; std::string _category; std::string _payload_type; // default is "MAP" std::string _owner_name; bool _committed; IUAccessMode _access_mode; bool _read_only; //boost::shared_ptr<Buffer> _buffer; Buffer* _buffer; SmartLinkMap _links; protected: friend class Payload; // Internal functions that perform the update logic, // e.g. sending a notification across the network _IPAACA_ABSTRACT_ virtual void _modify_links(bool is_delta, const LinkMap& new_links, const LinkMap& links_to_remove, const std::string& writer_name) = 0; _IPAACA_ABSTRACT_ virtual void _modify_payload(bool is_delta, const std::map<std::string, std::string>& new_items, const std::vector<std::string>& keys_to_remove, const std::string& writer_name) = 0; //void _set_buffer(boost::shared_ptr<Buffer> buffer); void _associate_with_buffer(Buffer* buffer); void _set_buffer(Buffer* buffer); void _set_uid(const std::string& uid); void _set_owner_name(const std::string& owner_name); protected: // internal functions that do not emit update events inline void _add_and_remove_links(const LinkMap& add, const LinkMap& remove) { _links._add_and_remove_links(add, remove); } inline void _replace_links(const LinkMap& links) { _links._replace_links(links); } public: inline bool is_published() { return (_buffer != 0); } inline const std::string& uid() const { return _uid; } inline revision_t revision() const { return _revision; } inline const std::string& category() const { return _category; } inline const std::string& payload_type() const { return _payload_type; } inline const std::string& owner_name() const { return _owner_name; } inline bool committed() const { return _committed; } inline IUAccessMode access_mode() const { return _access_mode; } inline bool read_only() const { return _read_only; } //inline boost::shared_ptr<Buffer> buffer() { return _buffer; } inline Buffer* buffer() const { return _buffer; } inline const LinkSet& get_links(std::string type) { return _links.get_links(type); } inline const LinkMap& get_all_links() { return _links.get_all_links(); } // Payload _IPAACA_ABSTRACT_ virtual Payload& payload() = 0; _IPAACA_ABSTRACT_ virtual const Payload& const_payload() const = 0; // setters _IPAACA_ABSTRACT_ virtual void commit() = 0; // functions to modify and update links: void add_links(const std::string& type, const LinkSet& targets, const std::string& writer_name = ""); void remove_links(const std::string& type, const LinkSet& targets, const std::string& writer_name = ""); void modify_links(const LinkMap& add, const LinkMap& remove, const std::string& writer_name = ""); void set_links(const LinkMap& links, const std::string& writer_name = ""); // (with cpp specific convenience functions:) void add_link(const std::string& type, const std::string& target, const std::string& writer_name = ""); void remove_link(const std::string& type, const std::string& target, const std::string& writer_name = ""); typedef boost::shared_ptr<IUInterface> ptr; };//}}} class IU: public IUInterface {//{{{ friend class Buffer; friend class InputBuffer; friend class OutputBuffer; friend class CallbackIUPayloadUpdate; friend class CallbackIULinkUpdate; friend class CallbackIUCommission; public: Payload _payload; protected: Lock _revision_lock; protected: inline void _increase_revision_number() { _revision++; } IU(const std::string& category, IUAccessMode access_mode=IU_ACCESS_PUSH, bool read_only=false, const std::string& payload_type="MAP" ); public: inline ~IU() { IPAACA_IMPLEMENT_ME } static boost::shared_ptr<IU> create(const std::string& category, IUAccessMode access_mode=IU_ACCESS_PUSH, bool read_only=false, const std::string& payload_type="MAP" ); inline Payload& payload() { return _payload; } inline const Payload& const_payload() const { return _payload; } void commit(); protected: void _modify_links(bool is_delta, const LinkMap& new_links, const LinkMap& links_to_remove, const std::string& writer_name = ""); void _modify_payload(bool is_delta, const std::map<std::string, std::string>& new_items, const std::vector<std::string>& keys_to_remove, const std::string& writer_name = ""); protected: void _internal_commit(const std::string& writer_name = ""); public: typedef boost::shared_ptr<IU> ptr; };//}}} class RemotePushIU: public IUInterface {//{{{ friend class Buffer; friend class InputBuffer; friend class OutputBuffer; friend class IUConverter; public: Payload _payload; protected: RemotePushIU(); static boost::shared_ptr<RemotePushIU> create(); public: inline ~RemotePushIU() { IPAACA_IMPLEMENT_ME } inline Payload& payload() { return _payload; } inline const Payload& const_payload() const { return _payload; } void commit(); protected: void _modify_links(bool is_delta, const LinkMap& new_links, const LinkMap& links_to_remove, const std::string& writer_name = ""); void _modify_payload(bool is_delta, const std::map<std::string, std::string>& new_items, const std::vector<std::string>& keys_to_remove, const std::string& writer_name = ""); protected: void _apply_update(IUPayloadUpdate::ptr update); void _apply_link_update(IULinkUpdate::ptr update); void _apply_commission(); typedef boost::shared_ptr<RemotePushIU> ptr; };//}}} class Exception: public std::exception//{{{ { protected: std::string _description; inline Exception(const std::string& description=""): _description(description) { } public: inline ~Exception() throw() { } const char* what() const throw() { return _description.c_str(); } };//}}} class IUNotFoundError: public Exception//{{{ { public: inline ~IUNotFoundError() throw() { } inline IUNotFoundError() { //boost::shared_ptr<IU> iu) { _description = "IUNotFoundError"; } };//}}} class IUPublishedError: public Exception//{{{ { public: inline ~IUPublishedError() throw() { } inline IUPublishedError() { //boost::shared_ptr<IU> iu) { _description = "IUPublishedError"; } };//}}} class IUCommittedError: public Exception//{{{ { public: inline ~IUCommittedError() throw() { } inline IUCommittedError() { //boost::shared_ptr<IU> iu) { _description = "IUCommittedError"; } };//}}} class IUUpdateFailedError: public Exception//{{{ { public: inline ~IUUpdateFailedError() throw() { } inline IUUpdateFailedError() { //boost::shared_ptr<IU> iu) { _description = "IUUpdateFailedError"; } };//}}} class IUReadOnlyError: public Exception//{{{ { public: inline ~IUReadOnlyError() throw() { } inline IUReadOnlyError() { //boost::shared_ptr<IU> iu) { _description = "IUReadOnlyError"; } };//}}} class IUAlreadyInABufferError: public Exception//{{{ { public: inline ~IUAlreadyInABufferError() throw() { } inline IUAlreadyInABufferError() { //boost::shared_ptr<IU> iu) { _description = "IUAlreadyInABufferError"; } };//}}} class IUAlreadyHasAnUIDError: public Exception//{{{ { public: inline ~IUAlreadyHasAnUIDError() throw() { } inline IUAlreadyHasAnUIDError() { //boost::shared_ptr<IU> iu) { _description = "IUAlreadyHasAnUIDError"; } };//}}} class IUAlreadyHasAnOwnerNameError: public Exception//{{{ { public: inline ~IUAlreadyHasAnOwnerNameError() throw() { } inline IUAlreadyHasAnOwnerNameError() { //boost::shared_ptr<IU> iu) { _description = "IUAlreadyHasAnOwnerNameError"; } };//}}} class NotImplementedError: public Exception//{{{ { public: inline ~NotImplementedError() throw() { } inline NotImplementedError() { //boost::shared_ptr<IU> iu) { _description = "NotImplementedError"; } };//}}} // (snippets) //{{{ /* class IUEventFunctionHandler: public rsb::EventFunctionHandler { protected: Buffer* _buffer; public: inline IUEventFunctionHandler(Buffer* buffer, const EventFunction& function, const std::string& method="") : EventFunctionHandler(function, method), _buffer(buffer) { } }; */ //}}} } // of namespace ipaaca #endif