From 3daf95b398546f0e087e94467038f97077560406 Mon Sep 17 00:00:00 2001
From: Ramin Yaghoubzadeh <ryaghoubzadeh@uni-bielefeld.de>
Date: Sat, 14 Feb 2015 00:55:58 +0100
Subject: [PATCH] Proxy read access halfway OK

---
 ipaacalib/cpp/CMakeLists.txt                  |  27 +-
 .../cpp/include/ipaaca/ipaaca-definitions.h   |   8 +
 .../cpp/include/ipaaca/ipaaca-forwards.h      |   2 +-
 ipaacalib/cpp/include/ipaaca/ipaaca-ius.h     |  28 ++
 ipaacalib/cpp/include/ipaaca/ipaaca-payload.h |  57 ++--
 ipaacalib/cpp/include/ipaaca/ipaaca.h         |  21 +-
 ipaacalib/cpp/src/ipaaca-buffers.cc           |  61 -----
 ipaacalib/cpp/src/ipaaca-fake.cc              |  61 +++++
 ipaacalib/cpp/src/ipaaca-internal.cc          |  10 +-
 ipaacalib/cpp/src/ipaaca-iuinterface.cc       | 156 +++++++++++
 ipaacalib/cpp/src/ipaaca-ius.cc               | 113 --------
 ipaacalib/cpp/src/ipaaca-json.cc              |  25 +-
 ipaacalib/cpp/src/ipaaca-links.cc             | 106 ++++++++
 ipaacalib/cpp/src/ipaaca-payload.cc           | 249 ++++++++++++++----
 14 files changed, 662 insertions(+), 262 deletions(-)
 create mode 100644 ipaacalib/cpp/src/ipaaca-fake.cc
 create mode 100644 ipaacalib/cpp/src/ipaaca-iuinterface.cc
 create mode 100644 ipaacalib/cpp/src/ipaaca-links.cc

diff --git a/ipaacalib/cpp/CMakeLists.txt b/ipaacalib/cpp/CMakeLists.txt
index 285676a..326c3f9 100644
--- a/ipaacalib/cpp/CMakeLists.txt
+++ b/ipaacalib/cpp/CMakeLists.txt
@@ -94,7 +94,7 @@ else()
 	# Setup section for Linux or OS X (using 'rsb' soa project)
 	#
 	#
-	find_package(Boost COMPONENTS system filesystem thread regex REQUIRED)
+	find_package(Boost COMPONENTS system filesystem thread regex signals REQUIRED)
 	link_directories(${Boost_LIBRARY_DIRS})
 	include_directories(${Boost_INCLUDE_DIRS})
 	#set(BOOSTLIBS boost_regex-mt boost_date_time-mt boost_program_options-mt boost_thread-mt boost_filesystem-mt boost_signals-mt boost_system-mt)
@@ -105,9 +105,9 @@ else()
 
 	# change for each new rsb version
 	if (DEFINED APPLE)
-		set(RSBLIBS rsc0.10 rsb.0.10)
+		set(RSBLIBS rsc0.11 rsb0.11)
 	else(DEFINED APPLE)
-		set(RSBLIBS ${PROJECT_SOURCE_DIR}/../../deps/lib/librsc0.10.so ${PROJECT_SOURCE_DIR}/../../deps/lib/librsb.so.0.10 )
+		set(RSBLIBS ${PROJECT_SOURCE_DIR}/../../deps/lib/librsc0.11.so ${PROJECT_SOURCE_DIR}/../../deps/lib/librsb0.11.so )
 		set(LIBS ${LIBS} uuid)
 	endif(DEFINED APPLE)
 	# enhance the default search paths (headers, libs ...)
@@ -124,15 +124,18 @@ endif(WIN32)
 
 set(LIBS ${LIBS} ${PROTOBUF_LIBRARY} ${Boost_LIBRARIES} ${RSBLIBS})
 
+# Hide the rsb-induced boost-signals warning (FOR NOW)
+set(IPAACA_CXX_DEFINES "${IPAACA_CXX_DEFINES} -DBOOST_SIGNALS_NO_DEPRECATION_WARNING")
+
 # Compiler defines copied from the old build system
-set(CXX_DEFINES "-D_BSD_SOURCE -DUSE_AV -DMGC_USE_DOUBLE -DLEDA_PREFIX -D__NO_CAST_TO_LOCAL_TYPE__ -DDBGLVL=0")
+set(IPAACA_CXX_DEFINES "${IPAACA_CXX_DEFINES} -D_BSD_SOURCE -DUSE_AV -DMGC_USE_DOUBLE -DLEDA_PREFIX -D__NO_CAST_TO_LOCAL_TYPE__ -DDBGLVL=0")
 
 # Combine the extra compiler flags
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX_OLD_CODE_CONVENIENCE_FLAGS} ${CXX_DEFINES}")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX_OLD_CODE_CONVENIENCE_FLAGS} ${IPAACA_CXX_DEFINES}")
 
 # add for for each new rsb version
-include_directories( ${PROJECT_SOURCE_DIR}/../../deps/include/rsc0.10 )
-include_directories( ${PROJECT_SOURCE_DIR}/../../deps/include/rsb0.10 )
+include_directories( ${PROJECT_SOURCE_DIR}/../../deps/include/rsc0.11 )
+include_directories( ${PROJECT_SOURCE_DIR}/../../deps/include/rsb0.11 )
 
 # add include dir for auto-generated headers placed in build/
 include_directories( ${PROJECT_SOURCE_DIR}/build )
@@ -149,7 +152,9 @@ set (SOURCE
 	src/ipaaca.cc
 	src/ipaaca-buffers.cc
 	src/ipaaca-internal.cc
+	src/ipaaca-iuinterface.cc
 	src/ipaaca-ius.cc
+	src/ipaaca-links.cc
 	src/ipaaca-locking.cc
 	src/ipaaca-payload.cc
 	src/ipaaca-cmdline-parser.cc
@@ -159,7 +164,13 @@ set (SOURCE
 	)
 
 set (JSON_TEST_SOURCE
-	src/ipaaca-json.cc
+	src/ipaaca-fake.cc
+	src/ipaaca-iuinterface.cc
+	src/ipaaca-json.cc    # main
+	src/ipaaca-locking.cc
+	src/ipaaca-links.cc
+	src/ipaaca-payload.cc
+	src/ipaaca-string-utils.cc
 	)
 
 
diff --git a/ipaacalib/cpp/include/ipaaca/ipaaca-definitions.h b/ipaacalib/cpp/include/ipaaca/ipaaca-definitions.h
index 856464a..cf0ebe2 100644
--- a/ipaacalib/cpp/include/ipaaca/ipaaca-definitions.h
+++ b/ipaacalib/cpp/include/ipaaca/ipaaca-definitions.h
@@ -218,6 +218,14 @@ IPAACA_HEADER_EXPORT class JsonParsingError: public Exception//{{{
 			_description = "JsonParsingError";
 		}
 };//}}}
+IPAACA_HEADER_EXPORT class PayloadEntryProxyInvalidatedError: public Exception//{{{
+{
+	public:
+		IPAACA_HEADER_EXPORT inline ~PayloadEntryProxyInvalidatedError() throw() { }
+		IPAACA_HEADER_EXPORT inline PayloadEntryProxyInvalidatedError() { //boost::shared_ptr<IU> iu) {
+			_description = "PayloadEntryProxyInvalidatedError";
+		}
+};//}}}
 
 /// Static library initialization
 IPAACA_HEADER_EXPORT class Initializer
diff --git a/ipaacalib/cpp/include/ipaaca/ipaaca-forwards.h b/ipaacalib/cpp/include/ipaaca/ipaaca-forwards.h
index 5d64840..3eab622 100644
--- a/ipaacalib/cpp/include/ipaaca/ipaaca-forwards.h
+++ b/ipaacalib/cpp/include/ipaaca/ipaaca-forwards.h
@@ -42,7 +42,7 @@
  *  forward declarations
  */
 class PayloadDocumentEntry;
-class PayloadDocumentStore;
+//class PayloadDocumentStore;
 
 class PayloadEntryProxy;
 class Payload;
diff --git a/ipaacalib/cpp/include/ipaaca/ipaaca-ius.h b/ipaacalib/cpp/include/ipaaca/ipaaca-ius.h
index 75e22d7..0fc9e80 100644
--- a/ipaacalib/cpp/include/ipaaca/ipaaca-ius.h
+++ b/ipaacalib/cpp/include/ipaaca/ipaaca-ius.h
@@ -223,4 +223,32 @@ IPAACA_HEADER_EXPORT class RemoteMessage: public IUInterface {//{{{
 	typedef boost::shared_ptr<RemoteMessage> ptr;
 };//}}}
 
+IPAACA_HEADER_EXPORT class FakeIU: public IUInterface {//{{{
+	friend class Buffer;
+	friend class InputBuffer;
+	friend class OutputBuffer;
+	friend class IUConverter;
+	friend class MessageConverter;
+	protected:
+		IPAACA_MEMBER_VAR_EXPORT Payload _payload;
+		IPAACA_HEADER_EXPORT FakeIU();
+	public:
+		IPAACA_HEADER_EXPORT static boost::shared_ptr<FakeIU> create();
+		IPAACA_HEADER_EXPORT ~FakeIU();
+		IPAACA_HEADER_EXPORT Payload& payload();
+		IPAACA_HEADER_EXPORT const Payload& const_payload() const;
+		IPAACA_HEADER_EXPORT void commit();
+		IPAACA_HEADER_EXPORT void add_fake_payload_item(const std::string& key, PayloadDocumentEntry::ptr entry);
+	protected:
+		IPAACA_HEADER_EXPORT void _modify_links(bool is_delta, const LinkMap& new_links, const LinkMap& links_to_remove, const std::string& writer_name = "");
+		IPAACA_HEADER_EXPORT void _modify_payload(bool is_delta, const std::map<std::string, PayloadDocumentEntry::ptr>& new_items, const std::vector<std::string>& keys_to_remove, const std::string& writer_name = "");
+	protected:
+		IPAACA_HEADER_EXPORT void _apply_update(IUPayloadUpdate::ptr update);
+		IPAACA_HEADER_EXPORT void _apply_link_update(IULinkUpdate::ptr update);
+		IPAACA_HEADER_EXPORT void _apply_commission();
+		IPAACA_HEADER_EXPORT void _apply_retraction();
+	public:
+	typedef boost::shared_ptr<FakeIU> ptr;
+};//}}}
+
 #endif
diff --git a/ipaacalib/cpp/include/ipaaca/ipaaca-payload.h b/ipaacalib/cpp/include/ipaaca/ipaaca-payload.h
index f41d4cf..6cbd1bb 100644
--- a/ipaacalib/cpp/include/ipaaca/ipaaca-payload.h
+++ b/ipaacalib/cpp/include/ipaaca/ipaaca-payload.h
@@ -38,15 +38,30 @@
 #error "Please do not include this file directly, use ipaaca.h instead"
 #endif
 
+IPAACA_HEADER_EXPORT template<typename T> T json_value_cast(const rapidjson::Value&);
+IPAACA_HEADER_EXPORT template<typename T> T json_value_cast(const rapidjson::Value* value) { if (!value) return T(); return json_value_cast<T>(*value); }
+IPAACA_HEADER_EXPORT template<> long json_value_cast(const rapidjson::Value&);
+IPAACA_HEADER_EXPORT template<> double json_value_cast(const rapidjson::Value&);
+IPAACA_HEADER_EXPORT template<> bool json_value_cast(const rapidjson::Value&);
+IPAACA_HEADER_EXPORT template<> std::string json_value_cast(const rapidjson::Value&);
+IPAACA_HEADER_EXPORT template<> std::vector<std::string> json_value_cast(const rapidjson::Value&);
+IPAACA_HEADER_EXPORT template<> std::list<std::string> json_value_cast(const rapidjson::Value&);
+IPAACA_HEADER_EXPORT template<> std::map<std::string, std::string> json_value_cast(const rapidjson::Value&);
+
+// FIXME TODO locking / invalidating proxy on first write of a payload entry
 IPAACA_HEADER_EXPORT class PayloadDocumentEntry//{{{
 {
 	public:
 		IPAACA_MEMBER_VAR_EXPORT ipaaca::Lock lock;
+		IPAACA_MEMBER_VAR_EXPORT bool modified;
+		IPAACA_MEMBER_VAR_EXPORT std::string json_source;
 		IPAACA_MEMBER_VAR_EXPORT rapidjson::Document document;
-		IPAACA_HEADER_EXPORT PayloadDocumentEntry(rapidjson::Document&& doc): document(std::move(doc)) {};
-		IPAACA_HEADER_EXPORT PayloadDocumentEntry() {};
+		IPAACA_HEADER_EXPORT inline PayloadDocumentEntry(): modified(false) { IPAACA_INFO("") }
+		IPAACA_HEADER_EXPORT inline ~PayloadDocumentEntry() { IPAACA_INFO("") }
+		//IPAACA_HEADER_EXPORT PayloadDocumentEntry(const std::string& source): modified(false), json_source(source), {};
 		IPAACA_HEADER_EXPORT std::string to_json_string_representation();
 		static std::shared_ptr<PayloadDocumentEntry> from_json_string_representation(const std::string& input);
+		static std::shared_ptr<PayloadDocumentEntry> create_null();
 	typedef std::shared_ptr<PayloadDocumentEntry> ptr;
 };
 //}}}
@@ -62,24 +77,26 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{
 		//
 		PayloadEntryProxy* parent; // parent (up to document root -> then null)
 		PayloadDocumentEntry::ptr document_entry; // contains lock and json Doc
-		bool existant; // whether Value exist already (or blindly navigated)
+		bool existent; // whether Value exists already (or blindly navigated)
 		bool addressed_as_array; // whether long or string navigation used
 		long addressed_index;
 		std::string addressed_key;
 		/// currently navigated value in json tree (or a new Null value)
-		rapidjson::Value& json_value;
-	public:
-		IPAACA_HEADER_EXPORT PayloadEntryProxy& operator[](long index); // array-style navigation
-		IPAACA_HEADER_EXPORT PayloadEntryProxy& operator[](const std::string& key);
+		rapidjson::Value* json_value;
 	protected:
 		IPAACA_HEADER_EXPORT void connect_to_existing_parents();
 	protected:
 		IPAACA_HEADER_EXPORT template<typename T> void pack_into_json_value(T t); //specializations below
 	public:
-		IPAACA_HEADER_EXPORT PayloadEntryProxy(Payload* payload, const std::string& key, PayloadDocumentEntry::ptr entry);
+		// constructor to create a new top-most parent proxy (from a payload key)
+		IPAACA_HEADER_EXPORT PayloadEntryProxy(Payload* payload, const std::string& key);
+		// constructors for navigation through objects
 		IPAACA_HEADER_EXPORT PayloadEntryProxy(PayloadEntryProxy* parent, const std::string& addressed_key);
-		IPAACA_HEADER_EXPORT PayloadEntryProxy(PayloadEntryProxy* parent, long addressed_index);
-		//
+		IPAACA_HEADER_EXPORT PayloadEntryProxy(PayloadEntryProxy* parent, size_t addressed_index);
+	public:
+		IPAACA_HEADER_EXPORT PayloadEntryProxy operator[](size_t index); // array-style navigation
+		IPAACA_HEADER_EXPORT PayloadEntryProxy operator[](const std::string& key);
+		//                   
 		IPAACA_HEADER_EXPORT PayloadEntryProxy& operator=(const std::string& value);
 		IPAACA_HEADER_EXPORT PayloadEntryProxy& operator=(const char* value);
 		IPAACA_HEADER_EXPORT PayloadEntryProxy& operator=(double value);
@@ -94,7 +111,7 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{
 		IPAACA_HEADER_EXPORT double to_float();
 		IPAACA_HEADER_EXPORT bool to_bool();
 		// getters
-		IPAACA_HEADER_EXPORT template<typename T> T get(); // specializations below
+		IPAACA_HEADER_EXPORT template<typename T> T get() { return json_value_cast<T>(json_value); } // specializations below
 		// setters
 		IPAACA_HEADER_EXPORT template<typename T> PayloadEntryProxy& set(T t);
 		/*{
@@ -106,6 +123,7 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{
 // Available interpretations of payload entries (or children thereof) below.
 //  Usage of standard complex data structures (vector etc.) currently entails
 //  casting all entries to a uniform type (a-priori choice: std::string).
+/*
 IPAACA_HEADER_EXPORT template<> long PayloadEntryProxy::get();
 IPAACA_HEADER_EXPORT template<> double PayloadEntryProxy::get();
 IPAACA_HEADER_EXPORT template<> bool PayloadEntryProxy::get();
@@ -113,6 +131,8 @@ IPAACA_HEADER_EXPORT template<> std::string PayloadEntryProxy::get();
 IPAACA_HEADER_EXPORT template<> std::vector<std::string> PayloadEntryProxy::get();
 IPAACA_HEADER_EXPORT template<> std::list<std::string> PayloadEntryProxy::get();
 IPAACA_HEADER_EXPORT template<> std::map<std::string, std::string> PayloadEntryProxy::get();
+*/
+
 // value converters
 IPAACA_HEADER_EXPORT template<> void PayloadEntryProxy::pack_into_json_value(long);
 IPAACA_HEADER_EXPORT template<> void PayloadEntryProxy::pack_into_json_value(double);
@@ -162,8 +182,9 @@ IPAACA_HEADER_EXPORT template<> std::map<std::string, std::string> PayloadEntryP
 //}}}
 */
 
-// shared_ptrs stored for shared read access, ref must be held
-// even if the key for the entry is overwritten remotely
+typedef std::map<std::string, PayloadDocumentEntry::ptr> PayloadDocumentStore;
+
+/*
 IPAACA_HEADER_EXPORT class PayloadDocumentStore//{{{
 : public std::map<std::string, PayloadDocumentEntry::ptr>
 {
@@ -171,7 +192,7 @@ IPAACA_HEADER_EXPORT class PayloadDocumentStore//{{{
 	typedef std::shared_ptr<PayloadDocumentStore> ptr;
 };
 //}}}
-
+*/
 IPAACA_HEADER_EXPORT class Payload//{{{
 {
 	friend std::ostream& operator<<(std::ostream& os, const Payload& obj);
@@ -183,6 +204,8 @@ IPAACA_HEADER_EXPORT class Payload//{{{
 	friend class IUConverter;
 	friend class MessageConverter;
 	friend class CallbackIUPayloadUpdate;
+	friend class PayloadEntryProxy;
+	friend class FakeIU;
 	protected:
 		IPAACA_MEMBER_VAR_EXPORT std::string _owner_name;
 		//IPAACA_MEMBER_VAR_EXPORT rapidjson::Document _json_document;
@@ -195,6 +218,7 @@ IPAACA_HEADER_EXPORT class Payload//{{{
 		IPAACA_HEADER_EXPORT void _remotely_enforced_wipe();
 		IPAACA_HEADER_EXPORT void _remotely_enforced_delitem(const std::string& k);
 		IPAACA_HEADER_EXPORT void _remotely_enforced_setitem(const std::string& k, PayloadDocumentEntry::ptr entry);
+		//IPAACA_HEADER_EXPORT void _internal_replace_all(const std::map<std::string, PayloadDocumentEntry::ptr>& new_contents, const std::string& writer_name="");
 		IPAACA_HEADER_EXPORT void _internal_replace_all(const std::map<std::string, PayloadDocumentEntry::ptr>& new_contents, const std::string& writer_name="");
 		IPAACA_HEADER_EXPORT void _internal_merge(const std::map<std::string, PayloadDocumentEntry::ptr>& contents_to_merge, const std::string& writer_name="");
 		IPAACA_HEADER_EXPORT void _internal_set(const std::string& k, PayloadDocumentEntry::ptr v, const std::string& writer_name="");
@@ -210,7 +234,10 @@ IPAACA_HEADER_EXPORT class Payload//{{{
 		//  to be more precise: types of map<string, T> with T several interesting things (string, list<string>, etc.)
 		//IPAACA_HEADER_EXPORT inline void set(const std::map<std::string, const rapidjson::Document&>& all_elems) { _internal_replace_all(all_elems); }
 		//IPAACA_HEADER_EXPORT inline void merge(const std::map<std::string, const rapidjson::Document&>& elems_to_merge) { _internal_merge(elems_to_merge); }
-		IPAACA_HEADER_EXPORT PayloadEntryProxy get(const std::string& k); // json, changed str to proxy here, too
+	protected:
+		IPAACA_HEADER_EXPORT PayloadDocumentEntry::ptr get_entry(const std::string& k); // json, changed str to proxy here, too
+	public:
+		IPAACA_HEADER_EXPORT std::string get(const std::string& k); // DEPRECATED
 	typedef boost::shared_ptr<Payload> ptr;
 };//}}}
 
diff --git a/ipaacalib/cpp/include/ipaaca/ipaaca.h b/ipaacalib/cpp/include/ipaaca/ipaaca.h
index 95cc0f0..f79e092 100644
--- a/ipaacalib/cpp/include/ipaaca/ipaaca.h
+++ b/ipaacalib/cpp/include/ipaaca/ipaaca.h
@@ -99,6 +99,7 @@
 #endif
 
 // new json-based payload API, used in several classes
+#define RAPIDJSON_HAS_STDSTRING 1
 #include "rapidjson/document.h"
 #include "rapidjson/prettywriter.h"
 #include "rapidjson/filestream.h"
@@ -161,15 +162,6 @@ namespace ipaaca {
 #include <ipaaca/ipaaca-forwards.h>
 
 #include <ipaaca/ipaaca-locking.h>
-#include <ipaaca/ipaaca-buffers.h>
-#include <ipaaca/ipaaca-payload.h>
-#include <ipaaca/ipaaca-ius.h>
-
-/// Full API (including RSB transport) is only exposed during
-///  ipaaca compilation, user programs should use abstract API.
-#ifdef IPAACA_EXPOSE_FULL_RSB_API
-#include <ipaaca/ipaaca-internal.h>
-#endif
 
 
 IPAACA_MEMBER_VAR_EXPORT Lock& logger_lock();
@@ -181,6 +173,17 @@ IPAACA_MEMBER_VAR_EXPORT Lock& logger_lock();
 #define LOG_IPAACA_CONSOLE(msg) { ipaaca::Locker logging_locker(ipaaca::logger_lock()); timeval logging_tim; gettimeofday(&logging_tim, NULL); double logging_t1=logging_tim.tv_sec+(logging_tim.tv_usec/1000000.0); std::cout << "[LOG] " << std::setprecision(15) << logging_t1 << " : " << msg << std::endl; }
 #endif
 
+#include <ipaaca/ipaaca-payload.h>
+#include <ipaaca/ipaaca-buffers.h>
+#include <ipaaca/ipaaca-ius.h>
+
+/// Full API (including RSB transport) is only exposed during
+///  ipaaca compilation, user programs should use abstract API.
+#ifdef IPAACA_EXPOSE_FULL_RSB_API
+#include <ipaaca/ipaaca-internal.h>
+#endif
+
+
 
 } // of namespace ipaaca
 
diff --git a/ipaacalib/cpp/src/ipaaca-buffers.cc b/ipaacalib/cpp/src/ipaaca-buffers.cc
index 9d7208c..3600772 100644
--- a/ipaacalib/cpp/src/ipaaca-buffers.cc
+++ b/ipaacalib/cpp/src/ipaaca-buffers.cc
@@ -42,24 +42,6 @@ using namespace rsb::filter;
 using namespace rsb::converter;
 using namespace rsb::patterns;
 
-IPAACA_EXPORT std::ostream& operator<<(std::ostream& os, const SmartLinkMap& obj)//{{{
-{
-	os << "{";
-	bool first = true;
-	for (LinkMap::const_iterator it=obj._links.begin(); it!=obj._links.end(); ++it) {
-		if (first) { first=false; } else { os << ", "; }
-		os << "'" << it->first << "': [";
-		bool firstinner = true;
-		for (LinkSet::const_iterator it2=it->second.begin(); it2!=it->second.end(); ++it2) {
-			if (firstinner) { firstinner=false; } else { os << ", "; }
-			os << "'" << *it2 << "'";
-		}
-		os << "]";
-	}
-	os << "}";
-	return os;
-}
-//}}}
 IPAACA_EXPORT std::ostream& operator<<(std::ostream& os, const IUPayloadUpdate& obj)//{{{
 {
 	os << "PayloadUpdate(uid=" << obj.uid << ", revision=" << obj.revision;
@@ -114,49 +96,6 @@ IPAACA_EXPORT std::ostream& operator<<(std::ostream& os, const IULinkUpdate& obj
 }
 //}}}
 
-// SmartLinkMap//{{{
-
-IPAACA_EXPORT LinkSet SmartLinkMap::empty_link_set;
-IPAACA_EXPORT void SmartLinkMap::_add_and_remove_links(const LinkMap& add, const LinkMap& remove)
-{
-	// remove specified links
-	for (LinkMap::const_iterator it = remove.begin(); it != remove.end(); ++it ) {
-		// if link type exists
-		if (_links.count(it->first) > 0) {
-			// remove one by one
-			for (LinkSet::const_iterator it2=it->second.begin(); it2!=it->second.end(); ++it2) {
-				_links[it->first].erase(*it2);
-			}
-			// wipe the type key if no more links are left
-			if (_links[it->first].size() == 0) {
-				_links.erase(it->first);
-			}
-		}
-	}
-	// add specified links
-	for (LinkMap::const_iterator it = add.begin(); it != add.end(); ++it ) {
-		for (LinkSet::const_iterator it2=it->second.begin(); it2!=it->second.end(); ++it2) {
-			_links[it->first].insert(*it2);
-		}
-	}
-}
-IPAACA_EXPORT void SmartLinkMap::_replace_links(const LinkMap& links)
-{
-	//_links.clear();
-	_links=links;
-}
-IPAACA_EXPORT const LinkSet& SmartLinkMap::get_links(const std::string& key)
-{
-	LinkMap::const_iterator it = _links.find(key);
-	if (it==_links.end()) return empty_link_set;
-	return it->second;
-}
-IPAACA_EXPORT const LinkMap& SmartLinkMap::get_all_links()
-{
-	return _links;
-}
-//}}}
-
 // IUEventHandler//{{{
 IPAACA_EXPORT IUEventHandler::IUEventHandler(IUEventHandlerFunction function, IUEventType event_mask, const std::string& category)
 : _function(function), _event_mask(event_mask), _for_all_categories(false)
diff --git a/ipaacalib/cpp/src/ipaaca-fake.cc b/ipaacalib/cpp/src/ipaaca-fake.cc
new file mode 100644
index 0000000..0cb444b
--- /dev/null
+++ b/ipaacalib/cpp/src/ipaaca-fake.cc
@@ -0,0 +1,61 @@
+/*
+ * This file is part of IPAACA, the
+ *  "Incremental Processing Architecture
+ *   for Artificial Conversational Agents".
+ *
+ * Copyright (c) 2009-2015 Social Cognitive Systems Group
+ *                         (formerly the Sociable Agents Group)
+ *                         CITEC, Bielefeld University
+ *
+ * http://opensource.cit-ec.de/projects/ipaaca/
+ * http://purl.org/net/ipaaca
+ *
+ * This file may be licensed under the terms of of the
+ * GNU Lesser General Public License Version 3 (the ``LGPL''),
+ * or (at your option) any later version.
+ *
+ * Software distributed under the License is distributed
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
+ * express or implied. See the LGPL for the specific language
+ * governing rights and limitations.
+ *
+ * You should have received a copy of the LGPL along with this
+ * program. If not, go to http://www.gnu.org/licenses/lgpl.html
+ * or write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The development of this software was supported by the
+ * Excellence Cluster EXC 277 Cognitive Interaction Technology.
+ * The Excellence Cluster EXC 277 is a grant of the Deutsche
+ * Forschungsgemeinschaft (DFG) in the context of the German
+ * Excellence Initiative.
+ */
+
+#include <ipaaca/ipaaca.h>
+
+namespace ipaaca {
+
+IPAACA_EXPORT inline FakeIU::FakeIU() { IPAACA_INFO("") }
+IPAACA_EXPORT boost::shared_ptr<FakeIU> FakeIU::create()
+{
+	IPAACA_INFO("");
+	return boost::shared_ptr<FakeIU>(new FakeIU());
+}
+IPAACA_EXPORT void FakeIU::add_fake_payload_item(const std::string& key, PayloadDocumentEntry::ptr entry)
+{
+	_payload._remotely_enforced_setitem(key, entry);
+}
+IPAACA_EXPORT inline FakeIU::~FakeIU() { IPAACA_INFO("") }
+IPAACA_EXPORT inline Payload& FakeIU::payload() { return _payload; }
+IPAACA_EXPORT inline const Payload& FakeIU::const_payload() const { return _payload; }
+IPAACA_EXPORT inline void FakeIU::commit() { IPAACA_INFO("") }
+IPAACA_EXPORT inline void FakeIU::_modify_links(bool is_delta, const LinkMap& new_links, const LinkMap& links_to_remove, const std::string& writer_name) { IPAACA_INFO("") }
+IPAACA_EXPORT inline void FakeIU::_modify_payload(bool is_delta, const std::map<std::string, PayloadDocumentEntry::ptr>& new_items, const std::vector<std::string>& keys_to_remove, const std::string& writer_name) { IPAACA_INFO("")}
+IPAACA_EXPORT inline void FakeIU::_apply_update(IUPayloadUpdate::ptr update) { IPAACA_INFO("") }
+IPAACA_EXPORT inline void FakeIU::_apply_link_update(IULinkUpdate::ptr update) { IPAACA_INFO("") }
+IPAACA_EXPORT inline void FakeIU::_apply_commission() { IPAACA_INFO("") }
+IPAACA_EXPORT inline void FakeIU::_apply_retraction() { IPAACA_INFO("") }
+
+} // of namespace ipaaca
+
+
diff --git a/ipaacalib/cpp/src/ipaaca-internal.cc b/ipaacalib/cpp/src/ipaaca-internal.cc
index e8defae..6b3e4c8 100644
--- a/ipaacalib/cpp/src/ipaaca-internal.cc
+++ b/ipaacalib/cpp/src/ipaaca-internal.cc
@@ -223,7 +223,7 @@ IPAACA_EXPORT AnnotatedData IUConverter::deserialize(const std::string& wireSche
 					// fully parse json text
 					entry = PayloadDocumentEntry::from_json_string_representation( it.value() )
 				} else {
-					// implying legacy "str" -> just copy value to raw string in document
+					// assuming legacy "str" -> just copy value to raw string in document
 					entry = std::make_shared<PayloadDocumentEntry>();
 					entry->document.SetString(it.value(), entry->document.GetAllocator());
 				}
@@ -261,7 +261,7 @@ IPAACA_EXPORT AnnotatedData IUConverter::deserialize(const std::string& wireSche
 					// fully parse json text
 					entry = PayloadDocumentEntry::from_json_string_representation( it.value() )
 				} else {
-					// implying legacy "str" -> just copy value to raw string in document
+					// assuming legacy "str" -> just copy value to raw string in document
 					entry = std::make_shared<PayloadDocumentEntry>();
 					entry->document.SetString(it.value(), entry->document.GetAllocator());
 				}
@@ -372,7 +372,7 @@ IPAACA_EXPORT AnnotatedData MessageConverter::deserialize(const std::string& wir
 					// fully parse json text
 					entry = PayloadDocumentEntry::from_json_string_representation( it.value() )
 				} else {
-					// implying legacy "str" -> just copy value to raw string in document
+					// assuming legacy "str" -> just copy value to raw string in document
 					entry = std::make_shared<PayloadDocumentEntry>();
 					entry->document.SetString(it.value(), entry->document.GetAllocator());
 				}
@@ -409,7 +409,7 @@ IPAACA_EXPORT AnnotatedData MessageConverter::deserialize(const std::string& wir
 					// fully parse json text
 					entry = PayloadDocumentEntry::from_json_string_representation( it.value() )
 				} else {
-					// implying legacy "str" -> just copy value to raw string in document
+					// assuming legacy "str" -> just copy value to raw string in document
 					entry = std::make_shared<PayloadDocumentEntry>();
 					entry->document.SetString(it.value(), entry->document.GetAllocator());
 				}
@@ -481,7 +481,7 @@ AnnotatedData IUPayloadUpdateConverter::deserialize(const std::string& wireSchem
 			// fully parse json text
 			entry = PayloadDocumentEntry::from_json_string_representation( it.value() )
 		} else {
-			// implying legacy "str" -> just copy value to raw string in document
+			// assuming legacy "str" -> just copy value to raw string in document
 			entry = std::make_shared<PayloadDocumentEntry>();
 			entry->document.SetString(it.value(), entry->document.GetAllocator());
 		}
diff --git a/ipaacalib/cpp/src/ipaaca-iuinterface.cc b/ipaacalib/cpp/src/ipaaca-iuinterface.cc
new file mode 100644
index 0000000..2c36848
--- /dev/null
+++ b/ipaacalib/cpp/src/ipaaca-iuinterface.cc
@@ -0,0 +1,156 @@
+/*
+ * This file is part of IPAACA, the
+ *  "Incremental Processing Architecture
+ *   for Artificial Conversational Agents".
+ *
+ * Copyright (c) 2009-2015 Social Cognitive Systems Group
+ *                         (formerly the Sociable Agents Group)
+ *                         CITEC, Bielefeld University
+ *
+ * http://opensource.cit-ec.de/projects/ipaaca/
+ * http://purl.org/net/ipaaca
+ *
+ * This file may be licensed under the terms of of the
+ * GNU Lesser General Public License Version 3 (the ``LGPL''),
+ * or (at your option) any later version.
+ *
+ * Software distributed under the License is distributed
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
+ * express or implied. See the LGPL for the specific language
+ * governing rights and limitations.
+ *
+ * You should have received a copy of the LGPL along with this
+ * program. If not, go to http://www.gnu.org/licenses/lgpl.html
+ * or write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The development of this software was supported by the
+ * Excellence Cluster EXC 277 Cognitive Interaction Technology.
+ * The Excellence Cluster EXC 277 is a grant of the Deutsche
+ * Forschungsgemeinschaft (DFG) in the context of the German
+ * Excellence Initiative.
+ */
+
+#include <ipaaca/ipaaca.h>
+
+namespace ipaaca {
+
+using namespace rsb;
+using namespace rsb::filter;
+using namespace rsb::converter;
+using namespace rsb::patterns;
+
+IPAACA_EXPORT std::ostream& operator<<(std::ostream& os, const IUInterface& obj)//{{{
+{
+	os << "IUInterface(uid='" << obj.uid() << "'";
+	os << ", category='" << obj.category() << "'";
+	os << ", revision=" << obj.revision();
+	os << ", committed=" << (obj.committed()?"True":"False");
+	os << ", owner_name='" << obj.owner_name() << "'";
+	os << ", payload=";
+	os << obj.const_payload();
+	os << ", links=";
+	os << obj._links;
+	os << ")";
+	return os;
+}
+//}}}
+
+// IUInterface//{{{
+
+IPAACA_EXPORT IUInterface::IUInterface()
+: _buffer(NULL), _committed(false), _retracted(false)
+{
+}
+
+IPAACA_EXPORT void IUInterface::_set_uid(const std::string& uid) {
+	if (_uid != "") {
+		throw IUAlreadyHasAnUIDError();
+	}
+	_uid = uid;
+}
+
+IPAACA_EXPORT void IUInterface::_set_buffer(Buffer* buffer) { //boost::shared_ptr<Buffer> buffer) {
+	if (_buffer) {
+		throw IUAlreadyInABufferError();
+	}
+	_buffer = buffer;
+
+}
+
+IPAACA_EXPORT void IUInterface::_set_owner_name(const std::string& owner_name) {
+	if (_owner_name != "") {
+		throw IUAlreadyHasAnOwnerNameError();
+	}
+	_owner_name = owner_name;
+}
+
+/// set the buffer pointer and the owner names of IU and Payload
+IPAACA_EXPORT void IUInterface::_associate_with_buffer(Buffer* buffer) { //boost::shared_ptr<Buffer> buffer) {
+	_set_buffer(buffer); // will throw if already set
+	_set_owner_name(buffer->unique_name());
+	payload()._set_owner_name(buffer->unique_name());
+}
+
+/// C++-specific convenience function to add one single link
+IPAACA_EXPORT void IUInterface::add_link(const std::string& type, const std::string& target, const std::string& writer_name)
+{
+	LinkMap none;
+	LinkMap add;
+	add[type].insert(target);
+	_modify_links(true, add, none, writer_name);
+	_add_and_remove_links(add, none);
+}
+/// C++-specific convenience function to remove one single link
+IPAACA_EXPORT void IUInterface::remove_link(const std::string& type, const std::string& target, const std::string& writer_name)
+{
+	LinkMap none;
+	LinkMap remove;
+	remove[type].insert(target);
+	_modify_links(true, none, remove, writer_name);
+	_add_and_remove_links(none, remove);
+}
+
+IPAACA_EXPORT void IUInterface::add_links(const std::string& type, const LinkSet& targets, const std::string& writer_name)
+{
+	LinkMap none;
+	LinkMap add;
+	add[type] = targets;
+	_modify_links(true, add, none, writer_name);
+	_add_and_remove_links(add, none);
+}
+
+IPAACA_EXPORT void IUInterface::remove_links(const std::string& type, const LinkSet& targets, const std::string& writer_name)
+{
+	LinkMap none;
+	LinkMap remove;
+	remove[type] = targets;
+	_modify_links(true, none, remove, writer_name);
+	_add_and_remove_links(none, remove);
+}
+
+IPAACA_EXPORT void IUInterface::modify_links(const LinkMap& add, const LinkMap& remove, const std::string& writer_name)
+{
+	_modify_links(true, add, remove, writer_name);
+	_add_and_remove_links(add, remove);
+}
+
+IPAACA_EXPORT void IUInterface::set_links(const LinkMap& links, const std::string& writer_name)
+{
+	LinkMap none;
+	_modify_links(false, links, none, writer_name);
+	_replace_links(links);
+}
+
+IPAACA_HEADER_EXPORT const std::string& IUInterface::channel()
+{
+	if (_buffer == NULL)
+		throw IUUnpublishedError();
+	else
+		return _buffer->channel();
+
+}
+
+//}}}
+
+} // of namespace ipaaca
diff --git a/ipaacalib/cpp/src/ipaaca-ius.cc b/ipaacalib/cpp/src/ipaaca-ius.cc
index 27a2f4c..0d5c920 100644
--- a/ipaacalib/cpp/src/ipaaca-ius.cc
+++ b/ipaacalib/cpp/src/ipaaca-ius.cc
@@ -40,119 +40,6 @@ using namespace rsb::filter;
 using namespace rsb::converter;
 using namespace rsb::patterns;
 
-IPAACA_EXPORT std::ostream& operator<<(std::ostream& os, const IUInterface& obj)//{{{
-{
-	os << "IUInterface(uid='" << obj.uid() << "'";
-	os << ", category='" << obj.category() << "'";
-	os << ", revision=" << obj.revision();
-	os << ", committed=" << (obj.committed()?"True":"False");
-	os << ", owner_name='" << obj.owner_name() << "'";
-	os << ", payload=";
-	os << obj.const_payload();
-	os << ", links=";
-	os << obj._links;
-	os << ")";
-	return os;
-}
-//}}}
-
-// IUInterface//{{{
-
-IPAACA_EXPORT IUInterface::IUInterface()
-: _buffer(NULL), _committed(false), _retracted(false)
-{
-}
-
-IPAACA_EXPORT void IUInterface::_set_uid(const std::string& uid) {
-	if (_uid != "") {
-		throw IUAlreadyHasAnUIDError();
-	}
-	_uid = uid;
-}
-
-IPAACA_EXPORT void IUInterface::_set_buffer(Buffer* buffer) { //boost::shared_ptr<Buffer> buffer) {
-	if (_buffer) {
-		throw IUAlreadyInABufferError();
-	}
-	_buffer = buffer;
-
-}
-
-IPAACA_EXPORT void IUInterface::_set_owner_name(const std::string& owner_name) {
-	if (_owner_name != "") {
-		throw IUAlreadyHasAnOwnerNameError();
-	}
-	_owner_name = owner_name;
-}
-
-/// set the buffer pointer and the owner names of IU and Payload
-IPAACA_EXPORT void IUInterface::_associate_with_buffer(Buffer* buffer) { //boost::shared_ptr<Buffer> buffer) {
-	_set_buffer(buffer); // will throw if already set
-	_set_owner_name(buffer->unique_name());
-	payload()._set_owner_name(buffer->unique_name());
-}
-
-/// C++-specific convenience function to add one single link
-IPAACA_EXPORT void IUInterface::add_link(const std::string& type, const std::string& target, const std::string& writer_name)
-{
-	LinkMap none;
-	LinkMap add;
-	add[type].insert(target);
-	_modify_links(true, add, none, writer_name);
-	_add_and_remove_links(add, none);
-}
-/// C++-specific convenience function to remove one single link
-IPAACA_EXPORT void IUInterface::remove_link(const std::string& type, const std::string& target, const std::string& writer_name)
-{
-	LinkMap none;
-	LinkMap remove;
-	remove[type].insert(target);
-	_modify_links(true, none, remove, writer_name);
-	_add_and_remove_links(none, remove);
-}
-
-IPAACA_EXPORT void IUInterface::add_links(const std::string& type, const LinkSet& targets, const std::string& writer_name)
-{
-	LinkMap none;
-	LinkMap add;
-	add[type] = targets;
-	_modify_links(true, add, none, writer_name);
-	_add_and_remove_links(add, none);
-}
-
-IPAACA_EXPORT void IUInterface::remove_links(const std::string& type, const LinkSet& targets, const std::string& writer_name)
-{
-	LinkMap none;
-	LinkMap remove;
-	remove[type] = targets;
-	_modify_links(true, none, remove, writer_name);
-	_add_and_remove_links(none, remove);
-}
-
-IPAACA_EXPORT void IUInterface::modify_links(const LinkMap& add, const LinkMap& remove, const std::string& writer_name)
-{
-	_modify_links(true, add, remove, writer_name);
-	_add_and_remove_links(add, remove);
-}
-
-IPAACA_EXPORT void IUInterface::set_links(const LinkMap& links, const std::string& writer_name)
-{
-	LinkMap none;
-	_modify_links(false, links, none, writer_name);
-	_replace_links(links);
-}
-
-IPAACA_HEADER_EXPORT const std::string& IUInterface::channel()
-{
-	if (_buffer == NULL)
-		throw IUUnpublishedError();
-	else
-		return _buffer->channel();
-
-}
-
-//}}}
-
 // IU//{{{
 IPAACA_EXPORT IU::ptr IU::create(const std::string& category, IUAccessMode access_mode, bool read_only, const std::string& payload_type)
 {
diff --git a/ipaacalib/cpp/src/ipaaca-json.cc b/ipaacalib/cpp/src/ipaaca-json.cc
index 5908926..bb7acfe 100644
--- a/ipaacalib/cpp/src/ipaaca-json.cc
+++ b/ipaacalib/cpp/src/ipaaca-json.cc
@@ -37,7 +37,30 @@
 using namespace rapidjson;
 using namespace std;
 
-int main(int, char*[]) {
+int main(int argc, char** argv) {
+
+	if (argc<2) {
+		std::cout << "Please provide json content as the first argument." << std::endl;
+		return 0;
+	}
+	std::string json_source(argv[1]);
+	ipaaca::PayloadDocumentEntry::ptr entry = ipaaca::PayloadDocumentEntry::from_json_string_representation(json_source);
+	
+	ipaaca::FakeIU::ptr iu = ipaaca::FakeIU::create();
+	iu->add_fake_payload_item("a", entry);
+
+	auto a = iu->payload()["a"];
+	//auto a0 = a[0];
+	std::cout << "entry as string:       " << (std::string) a << std::endl;
+	std::cout << "entry as long:         " << (long) a << std::endl;
+	std::cout << "entry as double:       " << (double) a << std::endl;
+	std::cout << "entry as bool:         " << ((bool) a?"true":"false") << std::endl;
+	std::cout << "entry as list<string>: ";
+	try {
+	} catch {
+		std::cout << "(Error)" << std::endl;
+	}
+	return 0;
 
 	////////////////////////////////////////////////////////////////////////////
 	// 1. Parse a JSON text string to a document.
diff --git a/ipaacalib/cpp/src/ipaaca-links.cc b/ipaacalib/cpp/src/ipaaca-links.cc
new file mode 100644
index 0000000..e0a6229
--- /dev/null
+++ b/ipaacalib/cpp/src/ipaaca-links.cc
@@ -0,0 +1,106 @@
+/*
+ * This file is part of IPAACA, the
+ *  "Incremental Processing Architecture
+ *   for Artificial Conversational Agents".
+ *
+ * Copyright (c) 2009-2015 Social Cognitive Systems Group
+ *                         (formerly the Sociable Agents Group)
+ *                         CITEC, Bielefeld University
+ *
+ * http://opensource.cit-ec.de/projects/ipaaca/
+ * http://purl.org/net/ipaaca
+ *
+ * This file may be licensed under the terms of of the
+ * GNU Lesser General Public License Version 3 (the ``LGPL''),
+ * or (at your option) any later version.
+ *
+ * Software distributed under the License is distributed
+ * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
+ * express or implied. See the LGPL for the specific language
+ * governing rights and limitations.
+ *
+ * You should have received a copy of the LGPL along with this
+ * program. If not, go to http://www.gnu.org/licenses/lgpl.html
+ * or write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The development of this software was supported by the
+ * Excellence Cluster EXC 277 Cognitive Interaction Technology.
+ * The Excellence Cluster EXC 277 is a grant of the Deutsche
+ * Forschungsgemeinschaft (DFG) in the context of the German
+ * Excellence Initiative.
+ */
+
+#include <ipaaca/ipaaca.h>
+
+namespace ipaaca {
+
+using namespace rsb;
+using namespace rsb::filter;
+using namespace rsb::converter;
+using namespace rsb::patterns;
+
+IPAACA_EXPORT std::ostream& operator<<(std::ostream& os, const SmartLinkMap& obj)//{{{
+{
+	os << "{";
+	bool first = true;
+	for (LinkMap::const_iterator it=obj._links.begin(); it!=obj._links.end(); ++it) {
+		if (first) { first=false; } else { os << ", "; }
+		os << "'" << it->first << "': [";
+		bool firstinner = true;
+		for (LinkSet::const_iterator it2=it->second.begin(); it2!=it->second.end(); ++it2) {
+			if (firstinner) { firstinner=false; } else { os << ", "; }
+			os << "'" << *it2 << "'";
+		}
+		os << "]";
+	}
+	os << "}";
+	return os;
+}
+//}}}
+
+// SmartLinkMap//{{{
+
+IPAACA_EXPORT LinkSet SmartLinkMap::empty_link_set;
+IPAACA_EXPORT void SmartLinkMap::_add_and_remove_links(const LinkMap& add, const LinkMap& remove)
+{
+	// remove specified links
+	for (LinkMap::const_iterator it = remove.begin(); it != remove.end(); ++it ) {
+		// if link type exists
+		if (_links.count(it->first) > 0) {
+			// remove one by one
+			for (LinkSet::const_iterator it2=it->second.begin(); it2!=it->second.end(); ++it2) {
+				_links[it->first].erase(*it2);
+			}
+			// wipe the type key if no more links are left
+			if (_links[it->first].size() == 0) {
+				_links.erase(it->first);
+			}
+		}
+	}
+	// add specified links
+	for (LinkMap::const_iterator it = add.begin(); it != add.end(); ++it ) {
+		for (LinkSet::const_iterator it2=it->second.begin(); it2!=it->second.end(); ++it2) {
+			_links[it->first].insert(*it2);
+		}
+	}
+}
+IPAACA_EXPORT void SmartLinkMap::_replace_links(const LinkMap& links)
+{
+	//_links.clear();
+	_links=links;
+}
+IPAACA_EXPORT const LinkSet& SmartLinkMap::get_links(const std::string& key)
+{
+	LinkMap::const_iterator it = _links.find(key);
+	if (it==_links.end()) return empty_link_set;
+	return it->second;
+}
+IPAACA_EXPORT const LinkMap& SmartLinkMap::get_all_links()
+{
+	return _links;
+}
+//}}}
+
+} // of namespace ipaaca
+
diff --git a/ipaacalib/cpp/src/ipaaca-payload.cc b/ipaacalib/cpp/src/ipaaca-payload.cc
index 00674e1..a502226 100644
--- a/ipaacalib/cpp/src/ipaaca-payload.cc
+++ b/ipaacalib/cpp/src/ipaaca-payload.cc
@@ -35,6 +35,8 @@
 
 namespace ipaaca {
 
+using namespace rapidjson;
+
 using namespace rsb;
 using namespace rsb::filter;
 using namespace rsb::converter;
@@ -44,15 +46,86 @@ IPAACA_EXPORT std::ostream& operator<<(std::ostream& os, const Payload& obj)//{{
 {
 	os << "{";
 	bool first = true;
-	for (std::map<std::string, std::string>::const_iterator it=obj._document_store.begin(); it!=obj._document_store.end(); ++it) {
+	for (auto& kv: obj._document_store) {
 		if (first) { first=false; } else { os << ", "; }
-		os << "'" << it->first << "':'" << it->second << "'";
+		os << "'" << kv.first << "':'" << kv.second->json_source << "'";
 	}
 	os << "}";
 	return os;
 }
 //}}}
 
+// json_value_cast//{{{
+IPAACA_HEADER_EXPORT template<> std::string json_value_cast(const rapidjson::Value& v)
+{
+	if (v.IsString()) return v.GetString();
+	if (v.IsNull()) return "";
+	rapidjson::StringBuffer buffer;
+	rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
+	v.Accept(writer);
+	return buffer.GetString();
+}
+IPAACA_HEADER_EXPORT template<> long json_value_cast(const rapidjson::Value& v)
+{
+	if (v.IsString()) return atol(std::string(v.GetString()).c_str());
+	if (v.IsInt()) return v.GetInt();
+	if (v.IsUint()) return v.GetUint();
+	if (v.IsInt64()) return v.GetInt64();
+	if (v.IsUint64()) return v.GetUint64();
+	if (v.IsDouble()) return (long) v.GetDouble();
+	if (v.IsBool()) return v.GetBool() ? 1l : 0l;
+	if (v.IsNull()) return 0l;
+	// default: return parse of string version (should always be 0 though?)
+	rapidjson::StringBuffer buffer;
+	rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
+	v.Accept(writer);
+	return atol(std::string(buffer.GetString()).c_str());
+}
+IPAACA_HEADER_EXPORT template<> double json_value_cast(const rapidjson::Value& v)
+{
+	if (v.IsString()) return atof(std::string(v.GetString()).c_str());
+	if (v.IsDouble()) return v.GetDouble();
+	if (v.IsInt()) return (double) v.GetInt();
+	if (v.IsUint()) return (double) v.GetUint();
+	if (v.IsInt64()) return (double) v.GetInt64();
+	if (v.IsUint64()) return (double) v.GetUint64();
+	if (v.IsBool()) return v.GetBool() ? 1.0 : 0.0;
+	if (v.IsNull()) return 0.0;
+	// default: return parse of string version (should always be 0.0 though?)
+	rapidjson::StringBuffer buffer;
+	rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
+	v.Accept(writer);
+	return atof(std::string(buffer.GetString()).c_str());
+}
+IPAACA_HEADER_EXPORT template<> bool json_value_cast(const rapidjson::Value& v)
+{
+	if (v.IsString()) {
+		std::string s = v.GetString();
+		return !((s=="")||(s=="false")||(s=="False")||(s=="0"));
+		//return ((s=="1")||(s=="true")||(s=="True"));
+	}
+	if (v.IsBool()) return v.GetBool();
+	if (v.IsNull()) return false;
+	if (v.IsInt()) return v.GetInt() != 0;
+	if (v.IsUint()) return v.GetUint() != 0;
+	if (v.IsInt64()) return v.GetInt64() != 0;
+	if (v.IsUint64()) return v.GetUint64() != 0;
+	if (v.IsDouble()) return v.GetDouble() != 0.0;
+	// default: return parse of string version (should always be 0.0 though?)
+	rapidjson::StringBuffer buffer;
+	rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
+	v.Accept(writer);
+	std::string s = buffer.GetString();
+	return !((s=="")||(s=="false")||(s=="False")||(s=="0"));
+}
+/*
+ * std::map<std::string, std::string> result;
+	std::for_each(_document_store.begin(), _document_store.end(), [&result](std::pair<std::string, PayloadDocumentEntry::ptr> pair) {
+			result[pair.first] =  pair.second->document.GetString();
+			});
+			*/
+//}}}
+
 // PayloadDocumentEntry//{{{
 IPAACA_HEADER_EXPORT inline std::string PayloadDocumentEntry::to_json_string_representation()
 {
@@ -61,12 +134,19 @@ IPAACA_HEADER_EXPORT inline std::string PayloadDocumentEntry::to_json_string_rep
 	document.Accept(writer);
 	return buffer.GetString();
 }
-IPAACA_HEADER_EXPORT inline PayloadDocumentEntry::ptr PayloadDocumentEntry::from_json_string_representation(const std::string& json)
+IPAACA_HEADER_EXPORT PayloadDocumentEntry::ptr PayloadDocumentEntry::from_json_string_representation(const std::string& json_str)
 {
 	PayloadDocumentEntry::ptr entry = std::make_shared<ipaaca::PayloadDocumentEntry>();
-	if (entry->document.Parse(json).HasParseError()) {
+	if (entry->document.Parse(json_str.c_str()).HasParseError()) {
 		throw JsonParsingError();
 	}
+	entry->json_source = json_str;
+	return entry;
+}
+IPAACA_HEADER_EXPORT inline PayloadDocumentEntry::ptr PayloadDocumentEntry::create_null()
+{
+	PayloadDocumentEntry::ptr entry = std::make_shared<ipaaca::PayloadDocumentEntry>();
+	entry->json_source = "null";
 	return entry;
 }
 //}}}
@@ -78,16 +158,16 @@ IPAACA_EXPORT void PayloadEntryProxy::connect_to_existing_parents()
 {
 	rapidjson::Document::AllocatorType& allocator = document_entry->document.GetAllocator();
 	PayloadEntryProxy* pep = this;
-	while (!(pep->existant) && pep->parent) { // only if not top-level
+	while (!(pep->existent) && pep->parent) { // only if not top-level
 		if (pep->addressed_as_array) {
-			Value& parent_value = pep->parent->json_value;
+			rapidjson::Value& parent_value = *(pep->parent->json_value);
 			if (! parent_value.IsArray()) {
 				throw PayloadAddressingError();
 			} else {
 				long idx = pep->addressed_index;
 				long s = parent_value.Size();
 				if (idx<s) {
-					parent_value[idx] = json_value;
+					parent_value[idx] = *json_value;
 				} else {
 					throw PayloadAddressingError();
 				}
@@ -101,7 +181,7 @@ IPAACA_EXPORT void PayloadEntryProxy::connect_to_existing_parents()
 				long s = parent_value.Size();
 				if (idx<s) {
 					// existing element modified
-					parent_value[idx] = json_value;
+					parent_value[idx] = *json_value;
 				} else {
 					// implicitly initialize missing elements to null values
 					if (idx>s) {
@@ -117,11 +197,13 @@ IPAACA_EXPORT void PayloadEntryProxy::connect_to_existing_parents()
 			}*/
 		} else {
 			// addressed as object (dict)
-			Value& parent_value = pep->parent->json_value;
+			rapidjson::Value& parent_value = *(pep->parent->json_value);
 			if (! parent_value.IsObject()) {
 				throw PayloadAddressingError();
 			} else {
-				parent_value.AddMember(pep->addressed_key, json_value, allocator);
+				Value key;
+				key.SetString(pep->addressed_key, allocator);
+				parent_value.AddMember(key, *json_value, allocator);
 			}
 		}
 		// repeat for next parent in the tree
@@ -129,42 +211,80 @@ IPAACA_EXPORT void PayloadEntryProxy::connect_to_existing_parents()
 	}
 }
 
-IPAACA_EXPORT PayloadEntryProxy::PayloadEntryProxy(Payload* payload, const std::string& key, PayloadDocumentEntry::ptr entry)
-: _payload(payload), _key(key), parent(nullptr), document_entry(entry)
-{
-	PayloadEntryProxy* parent; // parent (up to document root -> then null)
-	PayloadDocumentEntry::ptr document_entry; // contains lock and json Doc
-	bool existant; // whether Value exist already (or blindly navigated)
-	bool addressed_as_array; // whether long or string navigation used
-	long addressed_index;
-	std::string addressed_key;
-	/// currently navigated value in json tree (or a new Null value)
-	rapidjson::Value& json_value;
-	
+
+
+IPAACA_EXPORT PayloadEntryProxy::PayloadEntryProxy(Payload* payload, const std::string& key)
+: _payload(payload), _key(key), parent(nullptr)
+{
+	document_entry = _payload->get_entry(key);
+	json_value = &(document_entry->document);
+}
+IPAACA_EXPORT PayloadEntryProxy::PayloadEntryProxy(PayloadEntryProxy* parent_, const std::string& addr_key_)
+: parent(parent_), addressed_key(addr_key_), addressed_as_array(false)
+{
+	_payload = parent->_payload;
+	_key = parent->_key;
+	document_entry = parent->document_entry;
+	auto it = parent->json_value->FindMember(addr_key_.c_str());
+	if (it != json_value->MemberEnd()) {
+		json_value = &(parent->json_value->operator[](addr_key_.c_str()));
+		existent = true;
+	} else {
+		json_value = nullptr; // avoid heap construction here
+		existent = false;
+	}
+}
+IPAACA_EXPORT PayloadEntryProxy::PayloadEntryProxy(PayloadEntryProxy* parent_, size_t addr_idx_)
+: parent(parent_), addressed_index(addr_idx_), addressed_as_array(true)
+{
+	_payload = parent->_payload;
+	_key = parent->_key;
+	document_entry = parent->document_entry;
+	json_value = &(parent->json_value->operator[](addr_idx_));
+	existent = true;
+}
+
+IPAACA_EXPORT PayloadEntryProxy PayloadEntryProxy::operator[](const std::string& addr_key_)
+{
+	if (!json_value) throw PayloadAddressingError();
+	if (! json_value->IsObject()) throw PayloadAddressingError();
+	return PayloadEntryProxy(this, addr_key_);
+}
+IPAACA_EXPORT PayloadEntryProxy PayloadEntryProxy::operator[](size_t addr_idx_)
+{
+	if (!json_value) throw PayloadAddressingError();
+	if (! json_value->IsArray()) throw PayloadAddressingError();
+	long s = json_value->Size();
+	if (addr_idx_>=s) throw PayloadAddressingError();
+	return PayloadEntryProxy(this, addr_idx_);
 }
 
 IPAACA_EXPORT PayloadEntryProxy& PayloadEntryProxy::operator=(const std::string& value)
 {
 	//std::cout << "operator=(string)" << std::endl;
-	_payload->set(_key, value);
+	IPAACA_IMPLEMENT_ME
+	//_payload->set(_key, value);
 	return *this;
 }
 IPAACA_EXPORT PayloadEntryProxy& PayloadEntryProxy::operator=(const char* value)
 {
 	//std::cout << "operator=(const char*)" << std::endl;
-	_payload->set(_key, value);
+	IPAACA_IMPLEMENT_ME
+	//_payload->set(_key, value);
 	return *this;
 }
 IPAACA_EXPORT PayloadEntryProxy& PayloadEntryProxy::operator=(double value)
 {
 	//std::cout << "operator=(double)" << std::endl;
-	_payload->set(_key, boost::lexical_cast<std::string>(value));
+	IPAACA_IMPLEMENT_ME
+	//_payload->set(_key, boost::lexical_cast<std::string>(value));
 	return *this;
 }
 IPAACA_EXPORT PayloadEntryProxy& PayloadEntryProxy::operator=(bool value)
 {
 	//std::cout << "operator=(bool)" << std::endl;
-	_payload->set(_key, boost::lexical_cast<std::string>(value));
+	IPAACA_IMPLEMENT_ME
+	//_payload->set(_key, boost::lexical_cast<std::string>(value));
 	return *this;
 }
 
@@ -172,42 +292,66 @@ IPAACA_EXPORT PayloadEntryProxy::operator std::string()
 {
 	return PayloadEntryProxy::get<std::string>();
 }
-IPAACA_EXPORT inline PayloadEntryProxy::operator long()
+IPAACA_EXPORT PayloadEntryProxy::operator long()
 {
 	return PayloadEntryProxy::get<long>();
 }
-IPAACA_EXPORT inline PayloadEntryProxy::operator double()
+IPAACA_EXPORT PayloadEntryProxy::operator double()
 {
 	return PayloadEntryProxy::get<double>();
 }
-IPAACA_EXPORT inline PayloadEntryProxy::operator bool()
+IPAACA_EXPORT PayloadEntryProxy::operator bool()
 {
 	return PayloadEntryProxy::get<bool>();
 }
-IPAACA_EXPORT inline std::string PayloadEntryProxy::to_str()
+IPAACA_EXPORT std::string PayloadEntryProxy::to_str()
 {
 	return PayloadEntryProxy::get<std::string>(); 
 }
-IPAACA_EXPORT inline long PayloadEntryProxy::to_long()
+IPAACA_EXPORT long PayloadEntryProxy::to_long()
 {
 	return PayloadEntryProxy::get<long>();
 }
-IPAACA_EXPORT inline double PayloadEntryProxy::to_float()
+IPAACA_EXPORT double PayloadEntryProxy::to_float()
 {
 	return PayloadEntryProxy::get<double>();
 }
-IPAACA_EXPORT inline bool PayloadEntryProxy::to_bool()
+IPAACA_EXPORT bool PayloadEntryProxy::to_bool()
 {
 	return PayloadEntryProxy::get<bool>();
 }
 
 
+std::string value_diagnosis(rapidjson::Value* val)
+{
+	if (!val) return "nullptr";
+	if (val->IsNull()) return "null";
+	if (val->IsString()) return "string";
+	if (val->IsNumber()) return "number";
+	if (val->IsBool()) return "bool";
+	if (val->IsArray()) return "array";
+	if (val->IsObject()) return "object";
+	return "other";
+
+}
+
 //
 // new stuff for protocol v2
 //
+
+/*
 IPAACA_HEADER_EXPORT template<> std::string PayloadEntryProxy::get<std::string>()
 {
-	return _payload->get(_key);
+	if (!json_value) return "";
+	//IPAACA_INFO( value_diagnosis(json_value) )
+	if (json_value->IsString()) return json_value->GetString();
+	if (json_value->IsNull()) return "";
+	rapidjson::StringBuffer buffer;
+	rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
+	json_value->Accept(writer);
+	return buffer.GetString();
+	
+	//return _payload->get(_key);
 }
 IPAACA_HEADER_EXPORT template<> long PayloadEntryProxy::get<long>()
 {
@@ -241,6 +385,8 @@ IPAACA_HEADER_EXPORT template<> std::map<std::string, std::string> PayloadEntryP
 	m["__automatic__"] = PayloadEntryProxy::get<std::string>();
 	return m;
 }
+*/
+
 //}}}
 
 // Payload//{{{
@@ -252,39 +398,40 @@ IPAACA_EXPORT void Payload::initialize(boost::shared_ptr<IUInterface> iu)
 
 IPAACA_EXPORT PayloadEntryProxy Payload::operator[](const std::string& key)
 {
+	// TODO atomicize
 	//boost::shared_ptr<PayloadEntryProxy> p(new PayloadEntryProxy(this, key));
-	return PayloadEntryProxy(this, key, get(key));
+	return PayloadEntryProxy(this, key);
 }
 IPAACA_EXPORT Payload::operator std::map<std::string, std::string>()
 {
 	std::map<std::string, std::string> result;
-	std::foreach(_document_store.begin(), _document_store.end(), [&result](auto pair) {
-			result[pair.first] =  pair.second.GetString();
+	std::for_each(_document_store.begin(), _document_store.end(), [&result](std::pair<std::string, PayloadDocumentEntry::ptr> pair) {
+			result[pair.first] =  pair.second->document.GetString();
 			});
 	return result;
 }
 
-IPAACA_EXPORT void Payload::_internal_set(const std::string& k, const rapidjson::Document& v, const std::string& writer_name) {
-	std::map<std::string, const rapidjson::Document&> _new;
+IPAACA_EXPORT void Payload::_internal_set(const std::string& k, PayloadDocumentEntry::ptr v, const std::string& writer_name) {
+	std::map<std::string, PayloadDocumentEntry::ptr> _new;
 	std::vector<std::string> _remove;
-	_new[k]=v;
+	_new[k] = v;
 	_iu.lock()->_modify_payload(true, _new, _remove, writer_name );
 	_document_store[k] = v;
 }
 IPAACA_EXPORT void Payload::_internal_remove(const std::string& k, const std::string& writer_name) {
-	std::map<std::string, const rapidjson::Document&> _new;
+	std::map<std::string, PayloadDocumentEntry::ptr> _new;
 	std::vector<std::string> _remove;
 	_remove.push_back(k);
 	_iu.lock()->_modify_payload(true, _new, _remove, writer_name );
-	_store.erase(k);
+	_document_store.erase(k);
 }
-IPAACA_EXPORT void Payload::_internal_replace_all(const std::map<std::string, const rapidjson::Document&>& new_contents, const std::string& writer_name)
+IPAACA_EXPORT void Payload::_internal_replace_all(const std::map<std::string, PayloadDocumentEntry::ptr>& new_contents, const std::string& writer_name)
 {
 	std::vector<std::string> _remove;
 	_iu.lock()->_modify_payload(false, new_contents, _remove, writer_name );
-	_store = new_contents;
+	_document_store = new_contents;
 }
-IPAACA_EXPORT void Payload::_internal_merge(const std::map<std::string, const rapidjson::Document&>& contents_to_merge, const std::string& writer_name)
+IPAACA_EXPORT void Payload::_internal_merge(const std::map<std::string, PayloadDocumentEntry::ptr>& contents_to_merge, const std::string& writer_name)
 {
 	std::vector<std::string> _remove;
 	_iu.lock()->_modify_payload(true, contents_to_merge, _remove, writer_name );
@@ -293,9 +440,13 @@ IPAACA_EXPORT void Payload::_internal_merge(const std::map<std::string, const ra
 	//	_store[it->first] = it->second;
 	//}
 }
-IPAACA_EXPORT inline PayloadDocumentEntry::ptr Payload::get(const std::string& k) {
+IPAACA_EXPORT inline PayloadDocumentEntry::ptr Payload::get_entry(const std::string& k) {
 	if (_document_store.count(k)>0) return _document_store[k];
-	else return make_shared<PayloadDocumentEntry>();  // contains Document with 'null' value
+	else return PayloadDocumentEntry::create_null();  // contains Document with 'null' value
+}
+IPAACA_EXPORT inline std::string Payload::get(const std::string& k) { // DEPRECATED
+	if (_document_store.count(k)>0) return _document_store[k]->document.GetString();
+	return "";
 }
 IPAACA_EXPORT void Payload::_remotely_enforced_wipe()
 {
@@ -305,9 +456,9 @@ IPAACA_EXPORT void Payload::_remotely_enforced_delitem(const std::string& k)
 {
 	_document_store.erase(k);
 }
-IPAACA_EXPORT void Payload::_remotely_enforced_setitem(const std::string& k, rapidjson::Document&& received_json_doc)
+IPAACA_EXPORT void Payload::_remotely_enforced_setitem(const std::string& k, PayloadDocumentEntry::ptr entry)
 {
-	_document_store[k] = make_shared<PayloadDocumentEntry>(std::move(received_json_doc));
+	_document_store[k] = entry;
 }
 
 //}}}
-- 
GitLab