From 9e761ea6eb78cdd84bc05cbd77185823b010d96f Mon Sep 17 00:00:00 2001
From: Ramin Yaghoubzadeh <ryaghoub@techfak.uni-bielefeld.de>
Date: Fri, 13 Apr 2012 00:20:17 +0200
Subject: [PATCH] C++: user space handlers work fine

---
 cpp/src/ipaaca-test-main.cc | 14 ++++--
 cpp/src/ipaaca.cc           | 98 ++++++++++++++++++++++++++++++++++---
 cpp/src/ipaaca.h            | 62 +++++++++++++++++++++--
 3 files changed, 158 insertions(+), 16 deletions(-)

diff --git a/cpp/src/ipaaca-test-main.cc b/cpp/src/ipaaca-test-main.cc
index 4000a09..c6acfcf 100644
--- a/cpp/src/ipaaca-test-main.cc
+++ b/cpp/src/ipaaca-test-main.cc
@@ -12,12 +12,16 @@
 using namespace ipaaca;
 
 #ifdef MAKE_RECEIVER
+void my_first_iu_handler(IUInterface::ptr iu, IUEventType type, bool local)
+{
+	std::cout << "" << iu_event_type_to_str(type) << "" << std::endl;
+}
 int main() {
 	try{
 		initialize_ipaaca_rsb();
 		
-		InputBuffer ib("Tester", "testcategory");
-		
+		InputBuffer::ptr ib = InputBuffer::create("Tester", "testcategory");
+		ib->register_handler(my_first_iu_handler);
 		
 		while (true) {
 			sleep(1);
@@ -34,11 +38,11 @@ int main() {
 		initialize_ipaaca_rsb();
 		
 		
-		OutputBuffer ob("Tester");
-		std::cout << "Buffer: " << ob.unique_name() << std::endl;
+		OutputBuffer::ptr ob = OutputBuffer::create("Tester");
+		std::cout << "Buffer: " << ob->unique_name() << std::endl;
 		
 		IU::ref iu = IU::create("testcategory");
-		ob.add(iu);
+		ob->add(iu);
 		
 		std::cout << "_payload.get(\"TEST\") = \"" << iu->_payload.get("TEST") << "\"" << std::endl;
 		std::cout << "_payload[\"TEST\"] = \"" << (std::string) iu->_payload["TEST"] << "\"" << std::endl;
diff --git a/cpp/src/ipaaca.cc b/cpp/src/ipaaca.cc
index 10c6cfc..ffc0ddf 100644
--- a/cpp/src/ipaaca.cc
+++ b/cpp/src/ipaaca.cc
@@ -176,6 +176,36 @@ void SmartLinkMap::_replace_links(const LinkMap& links)
 }
 //}}}
 
+// IUEventHandler//{{{
+IUEventHandler::IUEventHandler(IUEventHandlerFunction function, IUEventType event_mask, const std::string& category)
+: _function(function), _event_mask(event_mask), _for_all_categories(false)
+{
+	if (category=="") {
+		_for_all_categories = true;
+	} else {
+		_categories.insert(category);
+	}
+}
+IUEventHandler::IUEventHandler(IUEventHandlerFunction function, IUEventType event_mask, const std::set<std::string>& categories)
+: _function(function), _event_mask(event_mask), _for_all_categories(false)
+{
+	if (categories.size()==0) {
+		_for_all_categories = true;
+	} else {
+		_categories = categories;
+	}
+}
+void IUEventHandler::call(Buffer* buffer, boost::shared_ptr<IUInterface> iu, bool local, IUEventType event_type, const std::string& category)
+{
+	if (_condition_met(event_type, category)) {
+		//IUInterface::ptr iu = buffer->get(uid);
+		//if (iu) {
+			_function(iu, event_type, local);
+		//}
+	}
+}
+//}}}
+
 // Buffer//{{{
 void Buffer::_allocate_unique_name(const std::string& basename, const std::string& function) {
 	std::string uuid = ipaaca::generate_uuid_string();
@@ -183,6 +213,16 @@ void Buffer::_allocate_unique_name(const std::string& basename, const std::strin
 	_uuid = uuid.substr(0,8);
 	_unique_name = basename + "ID" + _uuid + "/" + function;
 }
+void Buffer::register_handler(IUEventHandlerFunction function, IUEventType event_mask, const std::set<std::string>& categories)
+{
+	IUEventHandler::ptr handler = IUEventHandler::ptr(new IUEventHandler(function, event_mask, categories));
+	_event_handlers.push_back(handler);
+}
+void Buffer::register_handler(IUEventHandlerFunction function, IUEventType event_mask, const std::string& category)
+{
+	IUEventHandler::ptr handler = IUEventHandler::ptr(new IUEventHandler(function, event_mask, category));
+	_event_handlers.push_back(handler);
+}
 //}}}
 
 // OutputBuffer//{{{
@@ -192,6 +232,16 @@ OutputBuffer::OutputBuffer(const std::string& basename)
 {
 	_id_prefix = _basename + "-" + _uuid + "-IU-";
 }
+OutputBuffer::ptr OutputBuffer::create(const std::string& basename)
+{
+	return OutputBuffer::ptr(new OutputBuffer(basename));
+}
+IUInterface::ptr OutputBuffer::get(const std::string& iu_uid)
+{
+	IUStore::iterator it = _iu_store.find(iu_uid);
+	if (it==_iu_store.end()) return IUInterface::ptr();
+	return it->second;
+}
 
 void OutputBuffer::_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)
 {
@@ -363,6 +413,36 @@ InputBuffer::InputBuffer(const std::string& basename, const std::string& categor
 	_create_category_listener_if_needed(category_interest4);
 }
 
+
+InputBuffer::ptr InputBuffer::create(const std::string& basename, const std::vector<std::string>& category_interests)
+{
+	return InputBuffer::ptr(new InputBuffer(basename, category_interests));
+}
+InputBuffer::ptr InputBuffer::create(const std::string& basename, const std::string& category_interest1)
+{
+	return InputBuffer::ptr(new InputBuffer(basename, category_interest1));
+}
+InputBuffer::ptr InputBuffer::create(const std::string& basename, const std::string& category_interest1, const std::string& category_interest2)
+{
+	return InputBuffer::ptr(new InputBuffer(basename, category_interest1, category_interest2));
+}
+InputBuffer::ptr InputBuffer::create(const std::string& basename, const std::string& category_interest1, const std::string& category_interest2, const std::string& category_interest3)
+{
+	return InputBuffer::ptr(new InputBuffer(basename, category_interest1, category_interest2, category_interest3));
+}
+InputBuffer::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)
+{
+	return InputBuffer::ptr(new InputBuffer(basename, category_interest1, category_interest2, category_interest3, category_interest4));
+}
+
+IUInterface::ptr InputBuffer::get(const std::string& iu_uid)
+{
+	RemotePushIUStore::iterator it = _iu_store.find(iu_uid); // TODO genericize
+	if (it==_iu_store.end()) return IUInterface::ptr();
+	return it->second;
+}
+
+
 RemoteServerPtr InputBuffer::_get_remote_server(boost::shared_ptr<IU> iu)
 {
 	IPAACA_IMPLEMENT_ME
@@ -397,9 +477,15 @@ ListenerPtr InputBuffer::_create_category_listener_if_needed(const std::string&
 		return cat_listener
 	*/
 }
-void InputBuffer::call_iu_event_handlers(const std::string& uid, bool local, IUEventType event_type, const std::string& category)
+void InputBuffer::call_iu_event_handlers(boost::shared_ptr<IUInterface> iu, bool local, IUEventType event_type, const std::string& category)
 {
-	IPAACA_INFO("handling an event " << ipaaca::iu_event_type_to_str(event_type) << " for IU " << uid)
+	IPAACA_INFO("handling an event " << ipaaca::iu_event_type_to_str(event_type) << " for IU " << iu->uid())
+	//IUInterface::ptr iu = buffer->get(uid);
+	//if (iu) {
+		for (std::vector<IUEventHandler::ptr>::iterator it = _event_handlers.begin(); it != _event_handlers.end(); ++it) {
+			(*it)->call(this, iu, local, event_type, category);
+		}
+	//}
 }
 void InputBuffer::_handle_iu_events(EventPtr event)
 {
@@ -411,7 +497,7 @@ void InputBuffer::_handle_iu_events(EventPtr event)
 		} else {
 			_iu_store[iu->uid()] = iu;
 			iu->_set_buffer(this);
-			call_iu_event_handlers(iu->uid(), false, IU_ADDED, iu->category() );
+			call_iu_event_handlers(iu, false, IU_ADDED, iu->category() );
 		}
 		IPAACA_INFO( "New RemotePushIU state: " << (*iu) )
 	} else {
@@ -429,7 +515,7 @@ void InputBuffer::_handle_iu_events(EventPtr event)
 			}
 			//
 			it->second->_apply_update(update);
-			call_iu_event_handlers(it->second->uid(), false, IU_UPDATED, it->second->category() );
+			call_iu_event_handlers(it->second, false, IU_UPDATED, it->second->category() );
 			//
 			//
 		} else if (type == "ipaaca::IULinkUpdate") {
@@ -445,7 +531,7 @@ void InputBuffer::_handle_iu_events(EventPtr event)
 			}
 			//
 			it->second->_apply_link_update(update);
-			call_iu_event_handlers(it->second->uid(), false, IU_LINKSUPDATED, it->second->category() );
+			call_iu_event_handlers(it->second, false, IU_LINKSUPDATED, it->second->category() );
 			//
 			//
 		} else if (type == "ipaaca::protobuf::IUCommission") {
@@ -462,7 +548,7 @@ void InputBuffer::_handle_iu_events(EventPtr event)
 			//
 			it->second->_apply_commission();
 			it->second->_revision = update->revision();
-			call_iu_event_handlers(it->second->uid(), false, IU_COMMITTED, it->second->category() );
+			call_iu_event_handlers(it->second, false, IU_COMMITTED, it->second->category() );
 			//
 			//
 		} else {
diff --git a/cpp/src/ipaaca.h b/cpp/src/ipaaca.h
index 29dffbe..e49385d 100644
--- a/cpp/src/ipaaca.h
+++ b/cpp/src/ipaaca.h
@@ -46,6 +46,18 @@ namespace ipaaca {
 
 typedef uint32_t revision_t;
 
+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
+//
+#define IU_ALL_EVENTS   63
+
+/*
 enum IUEventType {
 	IU_ADDED,
 	IU_COMMITTED,
@@ -54,6 +66,8 @@ enum IUEventType {
 	IU_UPDATED,
 	IU_LINKSUPDATED
 };
+*/
+
 inline std::string iu_event_type_to_str(IUEventType type)
 {
 	switch(type) {
@@ -63,7 +77,7 @@ inline std::string iu_event_type_to_str(IUEventType type)
 		case IU_RETRACTED: return "RETRACTED";
 		case IU_UPDATED: return "UPDATED";
 		case IU_LINKSUPDATED: return "LINKSUPDATED";
-		default: return "(IU_EVENT_TYPE_UNKNOWN)";
+		default: return "(NOT A KNOWN SINGLE IU EVENT TYPE)";
 	}
 }
 
@@ -90,7 +104,6 @@ class IUPayloadUpdate;
 class IUPayloadUpdateConverter;
 class IUStore;
 class FrozenIUStore;
-class IUEventHandler;
 class Buffer;
 class InputBuffer;
 class OutputBuffer;
@@ -148,6 +161,28 @@ class SmartLinkMap {
 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;
@@ -156,6 +191,7 @@ class Buffer { //: public boost::enable_shared_from_this<Buffer> {//{{{
 		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;
@@ -167,7 +203,10 @@ class Buffer { //: public boost::enable_shared_from_this<Buffer> {//{{{
 	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;
 };
 //}}}
 
@@ -191,14 +230,18 @@ class OutputBuffer: public Buffer { //, public boost::enable_shared_from_this<Ou
 		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);
-	public:
+	protected:
 		OutputBuffer(const std::string& basename);
+	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);
+	typedef boost::shared_ptr<OutputBuffer> ptr;
 };
 //}}}
 
@@ -225,20 +268,28 @@ class InputBuffer: public Buffer { //, public boost::enable_shared_from_this<Inp
 		RemoteServerPtr _get_remote_server(boost::shared_ptr<IU> iu);
 		ListenerPtr _create_category_listener_if_needed(const std::string& category);
 		void _handle_iu_events(EventPtr event);
-		void call_iu_event_handlers(const std::string& uid, bool local, IUEventType event_type, const std::string& category);
-	public:
+		void call_iu_event_handlers(boost::shared_ptr<IUInterface> iu, bool local, IUEventType event_type, const std::string& category);
+	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);
 		//inline void add(boost::shared_ptr<IU> iu)
 		//{
 		//	IPAACA_IMPLEMENT_ME
 		//}
+	typedef boost::shared_ptr<InputBuffer> ptr;
 };
 //}}}
 
@@ -391,6 +442,7 @@ class IUInterface {//{{{
 		//    (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 {//{{{
-- 
GitLab