From cef164d47fb24b9d971d912a5fde7f7871cc349b Mon Sep 17 00:00:00 2001 From: Ramin Yaghoubzadeh <ryaghoubzadeh@uni-bielefeld.de> Date: Fri, 30 Jan 2015 16:17:50 +0100 Subject: [PATCH] Modularization complete, barring further tests. --- ipaacalib/cpp/CMakeLists.txt | 5 + ipaacalib/cpp/include/ipaaca/ipaaca-buffers.h | 14 +- .../cpp/include/ipaaca/ipaaca-definitions.h | 2 + ipaacalib/cpp/include/ipaaca/ipaaca-locking.h | 2 - ipaacalib/cpp/include/ipaaca/ipaaca.h | 11 + ipaacalib/cpp/src/ipaaca-buffers.cc | 798 +++++++ ipaacalib/cpp/src/ipaaca-internal.cc | 545 +++++ ipaacalib/cpp/src/ipaaca-ius.cc | 464 ++++ ipaacalib/cpp/src/ipaaca-locking.cc | 43 + ipaacalib/cpp/src/ipaaca-payload.cc | 226 ++ ipaacalib/cpp/src/ipaaca.cc | 1898 +---------------- 11 files changed, 2105 insertions(+), 1903 deletions(-) create mode 100644 ipaacalib/cpp/src/ipaaca-buffers.cc create mode 100644 ipaacalib/cpp/src/ipaaca-internal.cc create mode 100644 ipaacalib/cpp/src/ipaaca-ius.cc create mode 100644 ipaacalib/cpp/src/ipaaca-locking.cc create mode 100644 ipaacalib/cpp/src/ipaaca-payload.cc diff --git a/ipaacalib/cpp/CMakeLists.txt b/ipaacalib/cpp/CMakeLists.txt index cad8997..ed15d94 100644 --- a/ipaacalib/cpp/CMakeLists.txt +++ b/ipaacalib/cpp/CMakeLists.txt @@ -147,6 +147,11 @@ link_directories( ${PROJECT_SOURCE_DIR}/../../deps/lib ) # specify source files for ipaaca (auto-generated ones are in build/ ) set (SOURCE src/ipaaca.cc + src/ipaaca-buffers.cc + src/ipaaca-internal.cc + src/ipaaca-ius.cc + src/ipaaca-locking.cc + src/ipaaca-payload.cc src/ipaaca-cmdline-parser.cc src/ipaaca-string-utils.cc src/util/notifier.cc diff --git a/ipaacalib/cpp/include/ipaaca/ipaaca-buffers.h b/ipaacalib/cpp/include/ipaaca/ipaaca-buffers.h index 35abab9..d62ee0d 100644 --- a/ipaacalib/cpp/include/ipaaca/ipaaca-buffers.h +++ b/ipaacalib/cpp/include/ipaaca/ipaaca-buffers.h @@ -51,7 +51,7 @@ IPAACA_HEADER_EXPORT class RemotePushIUStore: public std::map<std::string, boost typedef std::set<std::string> LinkSet; typedef std::map<std::string, LinkSet> LinkMap; -IPAACA_HEADER_EXPORT class SmartLinkMap { +IPAACA_HEADER_EXPORT class SmartLinkMap {//{{{ friend std::ostream& operator<<(std::ostream& os, const SmartLinkMap& obj); friend class IUInterface; friend class IU; @@ -66,12 +66,11 @@ IPAACA_HEADER_EXPORT class SmartLinkMap { IPAACA_MEMBER_VAR_EXPORT static LinkSet empty_link_set; IPAACA_HEADER_EXPORT void _add_and_remove_links(const LinkMap& add, const LinkMap& remove); IPAACA_HEADER_EXPORT void _replace_links(const LinkMap& links); -}; +};//}}} IPAACA_MEMBER_VAR_EXPORT const LinkSet EMPTY_LINK_SET; -// BufferConfiguration -IPAACA_HEADER_EXPORT class BufferConfiguration +IPAACA_HEADER_EXPORT class BufferConfiguration//{{{ { protected: IPAACA_MEMBER_VAR_EXPORT std::string _basename; @@ -82,10 +81,9 @@ IPAACA_HEADER_EXPORT class BufferConfiguration IPAACA_HEADER_EXPORT const std::string get_basename() const { return _basename; } IPAACA_HEADER_EXPORT const std::vector<std::string> get_category_interests() const { return _category_interests; } IPAACA_HEADER_EXPORT const std::string get_channel() const { return _channel; } -}; +};//}}} -// BufferConfigurationBuilder -IPAACA_HEADER_EXPORT class BufferConfigurationBuilder: private BufferConfiguration +IPAACA_HEADER_EXPORT class BufferConfigurationBuilder: private BufferConfiguration//{{{ { public: IPAACA_HEADER_EXPORT inline BufferConfigurationBuilder(const std::string basename):BufferConfiguration(basename) {} @@ -104,7 +102,7 @@ IPAACA_HEADER_EXPORT class BufferConfigurationBuilder: private BufferConfigurati IPAACA_HEADER_EXPORT const BufferConfiguration& get_buffer_configuration() { return *this; } -}; +};//}}} IPAACA_HEADER_EXPORT typedef boost::function<void (boost::shared_ptr<IUInterface>, IUEventType, bool)> IUEventHandlerFunction; diff --git a/ipaacalib/cpp/include/ipaaca/ipaaca-definitions.h b/ipaacalib/cpp/include/ipaaca/ipaaca-definitions.h index 64652d7..034a918 100644 --- a/ipaacalib/cpp/include/ipaaca/ipaaca-definitions.h +++ b/ipaacalib/cpp/include/ipaaca/ipaaca-definitions.h @@ -214,6 +214,7 @@ IPAACA_HEADER_EXPORT class Initializer IPAACA_MEMBER_VAR_EXPORT static bool _initialized; }; +// in ipaaca-cmdline-parser.cc // additional misc classes ( Command line options )//{{{ IPAACA_HEADER_EXPORT class CommandLineOptions { public: @@ -250,6 +251,7 @@ class CommandLineParser { typedef boost::shared_ptr<CommandLineParser> ptr; }; //}}} +// in ipaaca-string-utils.cc // additional misc functions ( String splitting / joining )//{{{ IPAACA_HEADER_EXPORT std::string str_join(const std::set<std::string>& set,const std::string& sep); IPAACA_HEADER_EXPORT std::string str_join(const std::vector<std::string>& vec,const std::string& sep); diff --git a/ipaacalib/cpp/include/ipaaca/ipaaca-locking.h b/ipaacalib/cpp/include/ipaaca/ipaaca-locking.h index 78b093b..81e0811 100644 --- a/ipaacalib/cpp/include/ipaaca/ipaaca-locking.h +++ b/ipaacalib/cpp/include/ipaaca/ipaaca-locking.h @@ -96,11 +96,9 @@ IPAACA_HEADER_EXPORT class Locker IPAACA_HEADER_EXPORT inline Locker(): _lock(NULL) { } // not available public: IPAACA_HEADER_EXPORT inline Locker(Lock& lock): _lock(&lock) { - //std::cout << "-- Locker: lock" << std::endl; _lock->lock(); } IPAACA_HEADER_EXPORT inline ~Locker() { - //std::cout << "-- Locker: unlock" << std::endl; _lock->unlock(); } }; diff --git a/ipaacalib/cpp/include/ipaaca/ipaaca.h b/ipaacalib/cpp/include/ipaaca/ipaaca.h index f82a0d3..0d05ead 100644 --- a/ipaacalib/cpp/include/ipaaca/ipaaca.h +++ b/ipaacalib/cpp/include/ipaaca/ipaaca.h @@ -122,6 +122,17 @@ #include <sys/time.h> #endif +#include <cstdlib> + + +#ifdef WIN32 +#include <rpc.h> +#else +#include <uuid/uuid.h> +#include <glob.h> +#endif + + #ifndef Q_MOC_RUN #include <boost/bind.hpp> #include <boost/function.hpp> diff --git a/ipaacalib/cpp/src/ipaaca-buffers.cc b/ipaacalib/cpp/src/ipaaca-buffers.cc new file mode 100644 index 0000000..dacb67f --- /dev/null +++ b/ipaacalib/cpp/src/ipaaca-buffers.cc @@ -0,0 +1,798 @@ +/* + * 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> + +#define VERBOSE_HANDLERS 0 // remove later + +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; +} +//}}} +IPAACA_EXPORT std::ostream& operator<<(std::ostream& os, const IUPayloadUpdate& obj)//{{{ +{ + os << "PayloadUpdate(uid=" << obj.uid << ", revision=" << obj.revision; + os << ", writer_name=" << obj.writer_name << ", is_delta=" << (obj.is_delta?"True":"False"); + os << ", new_items = {"; + bool first = true; + for (std::map<std::string, std::string>::const_iterator it=obj.new_items.begin(); it!=obj.new_items.end(); ++it) { + if (first) { first=false; } else { os << ", "; } + os << "'" << it->first << "':'" << it->second << "'"; + } + os << "}, keys_to_remove = ["; + first = true; + for (std::vector<std::string>::const_iterator it=obj.keys_to_remove.begin(); it!=obj.keys_to_remove.end(); ++it) { + if (first) { first=false; } else { os << ", "; } + os << "'" << *it << "'"; + } + os << "])"; + return os; +} +//}}} +IPAACA_EXPORT std::ostream& operator<<(std::ostream& os, const IULinkUpdate& obj)//{{{ +{ + os << "LinkUpdate(uid=" << obj.uid << ", revision=" << obj.revision; + os << ", writer_name=" << obj.writer_name << ", is_delta=" << (obj.is_delta?"True":"False"); + os << ", new_links = {"; + bool first = true; + for (std::map<std::string, std::set<std::string> >::const_iterator it=obj.new_links.begin(); it!=obj.new_links.end(); ++it) { + if (first) { first=false; } else { os << ", "; } + os << "'" << it->first << "': ["; + bool ffirst = true; + for (std::set<std::string>::const_iterator it2=it->second.begin(); it2!=it->second.end(); ++it2) { + if (ffirst) { ffirst=false; } else { os << ", "; } + os << "'" << *it2 << "'"; + } + os << "]"; + } + os << "}, links_to_remove = {"; + first = true; + for (std::map<std::string, std::set<std::string> >::const_iterator it=obj.links_to_remove.begin(); it!=obj.links_to_remove.end(); ++it) { + if (first) { first=false; } else { os << ", "; } + os << "'" << it->first << "': ["; + bool ffirst = true; + for (std::set<std::string>::const_iterator it2=it->second.begin(); it2!=it->second.end(); ++it2) { + if (ffirst) { ffirst=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; +} +//}}} + +// IUEventHandler//{{{ +IPAACA_EXPORT 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); + } +} +IPAACA_EXPORT 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; + } +} +IPAACA_EXPORT 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) { +#if VERBOSE_HANDLERS == 1 + std::cout << "[" << pthread_self() << " handler ENTER]" << std::endl; +#endif + _function(iu, event_type, local); +#if VERBOSE_HANDLERS == 1 + std::cout << "[" << pthread_self() << " handler EXIT]" << std::endl; +#endif + //} + } +} +//}}} + +// Buffer//{{{ +IPAACA_EXPORT void Buffer::_allocate_unique_name(const std::string& basename, const std::string& function) { + std::string uuid = ipaaca::generate_uuid_string(); + _basename = basename; + _uuid = uuid.substr(0,8); + _unique_name = "/ipaaca/component/" + _basename + "ID" + _uuid + "/" + function; +} +IPAACA_EXPORT void Buffer::register_handler(IUEventHandlerFunction function, IUEventType event_mask, const std::set<std::string>& categories) +{ + std::cout << "register_handler " << function << " " << event_mask << " " << categories << std::endl; + IUEventHandler::ptr handler = IUEventHandler::ptr(new IUEventHandler(function, event_mask, categories)); + _event_handlers.push_back(handler); +} +IPAACA_EXPORT void Buffer::register_handler(IUEventHandlerFunction function, IUEventType event_mask, const std::string& category) +{ + std::cout << "register_handler " << function << " " << event_mask << " " << category << std::endl; + IUEventHandler::ptr handler = IUEventHandler::ptr(new IUEventHandler(function, event_mask, category)); + _event_handlers.push_back(handler); +} +IPAACA_EXPORT void Buffer::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 " << iu->uid()) + std::cout << "handling an event " << ipaaca::iu_event_type_to_str(event_type) << " for IU " << iu->uid() << std::endl; + for (std::vector<IUEventHandler::ptr>::iterator it = _event_handlers.begin(); it != _event_handlers.end(); ++it) { + (*it)->call(this, iu, local, event_type, category); + } +} +//}}} + +// Callbacks for OutputBuffer//{{{ +IPAACA_EXPORT CallbackIUPayloadUpdate::CallbackIUPayloadUpdate(Buffer* buffer): _buffer(buffer) { } +IPAACA_EXPORT CallbackIULinkUpdate::CallbackIULinkUpdate(Buffer* buffer): _buffer(buffer) { } +IPAACA_EXPORT CallbackIUCommission::CallbackIUCommission(Buffer* buffer): _buffer(buffer) { } +// dlw +IPAACA_EXPORT CallbackIUResendRequest::CallbackIUResendRequest(Buffer* buffer): _buffer(buffer) { } + +IPAACA_EXPORT boost::shared_ptr<int> CallbackIUPayloadUpdate::call(const std::string& methodName, boost::shared_ptr<IUPayloadUpdate> update) +{ + //std::cout << "-- Received a modify_payload with " << update->new_items.size() << " keys to merge." << std::endl; + IUInterface::ptr iui = _buffer->get(update->uid); + if (! iui) { + IPAACA_WARNING("Remote InBuffer tried to spuriously write non-existent IU " << update->uid) + return boost::shared_ptr<int>(new int(0)); + } + IU::ptr iu = boost::static_pointer_cast<IU>(iui); + iu->_revision_lock.lock(); + if ((update->revision != 0) && (update->revision != iu->_revision)) { + IPAACA_INFO("Remote write operation failed because request was out of date; IU " << update->uid) + iu->_revision_lock.unlock(); + return boost::shared_ptr<int>(new int(0)); + } + if (update->is_delta) { + // FIXME FIXME this is an unsolved problem atm: deletes in a delta update are + // sent individually. We should have something like _internal_merge_and_remove + for (std::vector<std::string>::const_iterator it=update->keys_to_remove.begin(); it!=update->keys_to_remove.end(); ++it) { + iu->payload()._internal_remove(*it, update->writer_name); //_buffer->unique_name()); + } + // but it is solved for pure merges: + iu->payload()._internal_merge(update->new_items, update->writer_name); + } else { + iu->payload()._internal_replace_all(update->new_items, update->writer_name); //_buffer->unique_name()); + } + //std::cout << "-- Calling update handler due to remote write." << std::endl; + _buffer->call_iu_event_handlers(iu, true, IU_UPDATED, iu->category()); + revision_t revision = iu->revision(); + iu->_revision_lock.unlock(); + return boost::shared_ptr<int>(new int(revision)); +} + +IPAACA_EXPORT boost::shared_ptr<int> CallbackIULinkUpdate::call(const std::string& methodName, boost::shared_ptr<IULinkUpdate> update) +{ + IUInterface::ptr iui = _buffer->get(update->uid); + if (! iui) { + IPAACA_WARNING("Remote InBuffer tried to spuriously write non-existent IU " << update->uid) + return boost::shared_ptr<int>(new int(0)); + } + IU::ptr iu = boost::static_pointer_cast<IU>(iui); + iu->_revision_lock.lock(); + if ((update->revision != 0) && (update->revision != iu->_revision)) { + IPAACA_INFO("Remote write operation failed because request was out of date; IU " << update->uid) + iu->_revision_lock.unlock(); + return boost::shared_ptr<int>(new int(0)); + } + if (update->is_delta) { + iu->modify_links(update->new_links, update->links_to_remove, update->writer_name); + } else { + iu->set_links(update->new_links, update->writer_name); + } + _buffer->call_iu_event_handlers(iu, true, IU_LINKSUPDATED, iu->category()); + revision_t revision = iu->revision(); + iu->_revision_lock.unlock(); + return boost::shared_ptr<int>(new int(revision)); +} +IPAACA_EXPORT boost::shared_ptr<int> CallbackIUCommission::call(const std::string& methodName, boost::shared_ptr<protobuf::IUCommission> update) +{ + IUInterface::ptr iui = _buffer->get(update->uid()); + if (! iui) { + IPAACA_WARNING("Remote InBuffer tried to spuriously write non-existent IU " << update->uid()) + return boost::shared_ptr<int>(new int(0)); + } + IU::ptr iu = boost::static_pointer_cast<IU>(iui); + iu->_revision_lock.lock(); + if ((update->revision() != 0) && (update->revision() != iu->_revision)) { + IPAACA_INFO("Remote write operation failed because request was out of date; IU " << update->uid()) + iu->_revision_lock.unlock(); + return boost::shared_ptr<int>(new int(0)); + } + if (iu->committed()) { + return boost::shared_ptr<int>(new int(0)); + } else { + } + iu->_internal_commit(update->writer_name()); + _buffer->call_iu_event_handlers(iu, true, IU_LINKSUPDATED, iu->category()); + revision_t revision = iu->revision(); + iu->_revision_lock.unlock(); + return boost::shared_ptr<int>(new int(revision)); +} +/** dlw */ +IPAACA_EXPORT boost::shared_ptr<int> CallbackIUResendRequest::call(const std::string& methodName, boost::shared_ptr<protobuf::IUResendRequest> update) +{ + IUInterface::ptr iui = _buffer->get(update->uid()); + if (! iui) { + IPAACA_WARNING("Remote InBuffer tried to spuriously write non-existent IU " << update->uid()) + return boost::shared_ptr<int>(new int(0)); + } + IU::ptr iu = boost::static_pointer_cast<IU>(iui); + if ((update->has_hidden_scope_name() == true)&&(update->hidden_scope_name().compare("") != 0)){ + //_buffer->call_iu_event_handlers(iu, true, IU_UPDATED, update->hidden_scope_name()); + revision_t revision = iu->revision(); + + iu->_publish_resend(iu, update->hidden_scope_name()); + + return boost::shared_ptr<int>(new int(revision)); + } else { + revision_t revision = 0; + return boost::shared_ptr<int>(new int(revision)); + } +} +//}}} + +// OutputBuffer//{{{ + +IPAACA_EXPORT OutputBuffer::OutputBuffer(const std::string& basename, const std::string& channel) +:Buffer(basename, "OB") +{ + //IPAACA_INFO("Entering ...") + _id_prefix = _basename + "-" + _uuid + "-IU-"; + _channel = channel; + _initialize_server(); + //IPAACA_INFO("... exiting.") +} +IPAACA_EXPORT void OutputBuffer::_initialize_server() +{ + //IPAACA_INFO("Entering ...") + //IPAACA_INFO("Calling createServer(\"" << _unique_name << "\")") + _server = getFactory().createServer( Scope( _unique_name ) ); + //IPAACA_INFO("Registering methods") + _server->registerMethod("updatePayload", Server::CallbackPtr(new CallbackIUPayloadUpdate(this))); + _server->registerMethod("updateLinks", Server::CallbackPtr(new CallbackIULinkUpdate(this))); + _server->registerMethod("commit", Server::CallbackPtr(new CallbackIUCommission(this))); + // dlw + _server->registerMethod("resendRequest", Server::CallbackPtr(new CallbackIUResendRequest(this))); + + //IPAACA_INFO("... exiting.") +} +IPAACA_EXPORT OutputBuffer::ptr OutputBuffer::create(const std::string& basename) +{ + Initializer::initialize_ipaaca_rsb_if_needed(); + return OutputBuffer::ptr(new OutputBuffer(basename)); +} +IPAACA_EXPORT 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; +} +IPAACA_EXPORT std::set<IUInterface::ptr> OutputBuffer::get_ius() +{ + std::set<IUInterface::ptr> set; + for (IUStore::iterator it=_iu_store.begin(); it!=_iu_store.end(); ++it) set.insert(it->second); + return set; +} + +IPAACA_EXPORT 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) +{ + IULinkUpdate* lup = new ipaaca::IULinkUpdate(); + Informer<ipaaca::IULinkUpdate>::DataPtr ldata(lup); + lup->uid = iu->uid(); + lup->is_delta = is_delta; + lup->revision = revision; + lup->is_delta = true; + lup->new_links = new_links; + if (is_delta) lup->links_to_remove = links_to_remove; + if (writer_name=="") lup->writer_name = _unique_name; + else lup->writer_name = writer_name; + Informer<AnyType>::Ptr informer = _get_informer(iu->category()); + informer->publish(ldata); +} + +IPAACA_EXPORT void OutputBuffer::_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) +{ + IUPayloadUpdate* pup = new ipaaca::IUPayloadUpdate(); + Informer<ipaaca::IUPayloadUpdate>::DataPtr pdata(pup); + pup->uid = iu->uid(); + pup->is_delta = is_delta; + pup->revision = revision; + pup->new_items = new_items; + if (is_delta) pup->keys_to_remove = keys_to_remove; + if (writer_name=="") pup->writer_name = _unique_name; + else pup->writer_name = writer_name; + Informer<AnyType>::Ptr informer = _get_informer(iu->category()); + informer->publish(pdata); +} + +IPAACA_EXPORT void OutputBuffer::_send_iu_commission(IUInterface* iu, revision_t revision, const std::string& writer_name) +{ + Informer<protobuf::IUCommission>::DataPtr data(new protobuf::IUCommission()); + data->set_uid(iu->uid()); + data->set_revision(revision); + if (writer_name=="") data->set_writer_name(_unique_name); + else data->set_writer_name(writer_name); + + Informer<AnyType>::Ptr informer = _get_informer(iu->category()); + informer->publish(data); +} + + + + + + +IPAACA_EXPORT void OutputBuffer::add(IU::ptr iu) +{ + if (_iu_store.count(iu->uid()) > 0) { + throw IUPublishedError(); + } + if (iu->is_published()) { + throw IUPublishedError(); + } + if (iu->access_mode() != IU_ACCESS_MESSAGE) { + // (for Message-type IUs: do not actually store them) + _iu_store[iu->uid()] = iu; + } + iu->_associate_with_buffer(this); //shared_from_this()); + _publish_iu(iu); +} + +IPAACA_EXPORT void OutputBuffer::_publish_iu(IU::ptr iu) +{ + Informer<AnyType>::Ptr informer = _get_informer(iu->_category); + Informer<ipaaca::IU>::DataPtr iu_data(iu); + informer->publish(iu_data); +} + +IPAACA_EXPORT void OutputBuffer::_publish_iu_resend(IU::ptr iu, const std::string& hidden_scope_name) +{ + Informer<AnyType>::Ptr informer = _get_informer(hidden_scope_name); + Informer<ipaaca::IU>::DataPtr iu_data(iu); + informer->publish(iu_data); +} + + + + +IPAACA_EXPORT Informer<AnyType>::Ptr OutputBuffer::_get_informer(const std::string& category) +{ + if (_informer_store.count(category) > 0) { + return _informer_store[category]; + } else { + //IPAACA_INFO("Making new informer for category " << category) + std::string scope_string = "/ipaaca/channel/" + _channel + "/category/" + category; + + Informer<AnyType>::Ptr informer = getFactory().createInformer<AnyType> ( Scope(scope_string)); + _informer_store[category] = informer; + return informer; + } +} +IPAACA_EXPORT boost::shared_ptr<IU> OutputBuffer::remove(const std::string& iu_uid) +{ + IUStore::iterator it = _iu_store.find(iu_uid); + if (it == _iu_store.end()) { + IPAACA_WARNING("Removal of IU " << iu_uid << " requested, but not present in our OutputBuffer") + //throw IUNotFoundError(); + } + IU::ptr iu = it->second; + _retract_iu(iu); + _iu_store.erase(iu_uid); + return iu; +} +IPAACA_EXPORT boost::shared_ptr<IU> OutputBuffer::remove(IU::ptr iu) +{ + return remove(iu->uid()); // to make sure it is in the store +} + +IPAACA_EXPORT void OutputBuffer::_retract_iu(IU::ptr iu) +{ + Informer<protobuf::IURetraction>::DataPtr data(new protobuf::IURetraction()); + data->set_uid(iu->uid()); + data->set_revision(iu->revision()); + Informer<AnyType>::Ptr informer = _get_informer(iu->category()); + informer->publish(data); +} + + +//}}} + +// InputBuffer//{{{ +IPAACA_EXPORT InputBuffer::InputBuffer(const BufferConfiguration& bufferconfiguration) +:Buffer(bufferconfiguration.get_basename(), "IB") +{ + _channel = bufferconfiguration.get_channel(); + + for (std::vector<std::string>::const_iterator it=bufferconfiguration.get_category_interests().begin(); it!=bufferconfiguration.get_category_interests().end(); ++it) { + _create_category_listener_if_needed(*it); + } + _create_category_listener_if_needed(_uuid); + triggerResend = false; +} +IPAACA_EXPORT InputBuffer::InputBuffer(const std::string& basename, const std::set<std::string>& category_interests) +:Buffer(basename, "IB") +{ + _channel = "default"; + + for (std::set<std::string>::const_iterator it=category_interests.begin(); it!=category_interests.end(); ++it) { + _create_category_listener_if_needed(*it); + } + _create_category_listener_if_needed(_uuid); + triggerResend = false; +} +IPAACA_EXPORT InputBuffer::InputBuffer(const std::string& basename, const std::vector<std::string>& category_interests) +:Buffer(basename, "IB") +{ + _channel = "default"; + + for (std::vector<std::string>::const_iterator it=category_interests.begin(); it!=category_interests.end(); ++it) { + _create_category_listener_if_needed(*it); + } + _create_category_listener_if_needed(_uuid); + triggerResend = false; +} +IPAACA_EXPORT InputBuffer::InputBuffer(const std::string& basename, const std::string& category_interest1) +:Buffer(basename, "IB") +{ + _channel = "default"; + + _create_category_listener_if_needed(category_interest1); +} +IPAACA_EXPORT InputBuffer::InputBuffer(const std::string& basename, const std::string& category_interest1, const std::string& category_interest2) +:Buffer(basename, "IB") +{ + _channel = "default"; + + _create_category_listener_if_needed(category_interest1); + _create_category_listener_if_needed(category_interest2); +} +IPAACA_EXPORT InputBuffer::InputBuffer(const std::string& basename, const std::string& category_interest1, const std::string& category_interest2, const std::string& category_interest3) +:Buffer(basename, "IB") +{ + _channel = "default"; + + _create_category_listener_if_needed(category_interest1); + _create_category_listener_if_needed(category_interest2); + _create_category_listener_if_needed(category_interest3); +} +IPAACA_EXPORT InputBuffer::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) +:Buffer(basename, "IB") +{ + _channel = "default"; + + _create_category_listener_if_needed(category_interest1); + _create_category_listener_if_needed(category_interest2); + _create_category_listener_if_needed(category_interest3); + _create_category_listener_if_needed(category_interest4); +} + +IPAACA_EXPORT InputBuffer::ptr InputBuffer::create(const BufferConfiguration& bufferconfiguration) +{ + Initializer::initialize_ipaaca_rsb_if_needed(); + return InputBuffer::ptr(new InputBuffer(bufferconfiguration)); +} +IPAACA_EXPORT InputBuffer::ptr InputBuffer::create(const std::string& basename, const std::set<std::string>& category_interests) +{ + Initializer::initialize_ipaaca_rsb_if_needed(); + return InputBuffer::ptr(new InputBuffer(basename, category_interests)); +} +IPAACA_EXPORT InputBuffer::ptr InputBuffer::create(const std::string& basename, const std::vector<std::string>& category_interests) +{ + Initializer::initialize_ipaaca_rsb_if_needed(); + return InputBuffer::ptr(new InputBuffer(basename, category_interests)); +} +IPAACA_EXPORT InputBuffer::ptr InputBuffer::create(const std::string& basename, const std::string& category_interest1) +{ + Initializer::initialize_ipaaca_rsb_if_needed(); + return InputBuffer::ptr(new InputBuffer(basename, category_interest1)); +} +IPAACA_EXPORT InputBuffer::ptr InputBuffer::create(const std::string& basename, const std::string& category_interest1, const std::string& category_interest2) +{ + Initializer::initialize_ipaaca_rsb_if_needed(); + return InputBuffer::ptr(new InputBuffer(basename, category_interest1, category_interest2)); +} +IPAACA_EXPORT InputBuffer::ptr InputBuffer::create(const std::string& basename, const std::string& category_interest1, const std::string& category_interest2, const std::string& category_interest3) +{ + Initializer::initialize_ipaaca_rsb_if_needed(); + return InputBuffer::ptr(new InputBuffer(basename, category_interest1, category_interest2, category_interest3)); +} +IPAACA_EXPORT 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) +{ + Initializer::initialize_ipaaca_rsb_if_needed(); + return InputBuffer::ptr(new InputBuffer(basename, category_interest1, category_interest2, category_interest3, category_interest4)); +} + + +IPAACA_EXPORT void InputBuffer::set_resend(bool resendActive) +{ + triggerResend = resendActive; +} + +IPAACA_EXPORT bool InputBuffer::get_resend() +{ + return triggerResend; +} + + +IPAACA_EXPORT 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; +} +IPAACA_EXPORT std::set<IUInterface::ptr> InputBuffer::get_ius() +{ + std::set<IUInterface::ptr> set; + for (RemotePushIUStore::iterator it=_iu_store.begin(); it!=_iu_store.end(); ++it) set.insert(it->second); // TODO genericize + return set; +} + + +IPAACA_EXPORT RemoteServerPtr InputBuffer::_get_remote_server(const std::string& unique_server_name) +{ + std::map<std::string, RemoteServerPtr>::iterator it = _remote_server_store.find(unique_server_name); + if (it!=_remote_server_store.end()) return it->second; + RemoteServerPtr remote_server = getFactory().createRemoteServer(Scope(unique_server_name)); + _remote_server_store[unique_server_name] = remote_server; + return remote_server; +} + +IPAACA_EXPORT ListenerPtr InputBuffer::_create_category_listener_if_needed(const std::string& category) +{ + IPAACA_INFO("Entering ...") + std::map<std::string, ListenerPtr>::iterator it = _listener_store.find(category); + if (it!=_listener_store.end()) { + IPAACA_INFO("... exiting.") + return it->second; + } + //IPAACA_INFO("Creating a new listener for category " << category) + std::string scope_string = "/ipaaca/channel/" + _channel + "/category/" + category; + + ListenerPtr listener = getFactory().createListener( Scope(scope_string) ); + IPAACA_INFO("Adding handler") + HandlerPtr event_handler = HandlerPtr( + new EventFunctionHandler( + boost::bind(&InputBuffer::_handle_iu_events, this, _1) + ) + ); + listener->addHandler(event_handler); + _listener_store[category] = listener; + IPAACA_INFO("... exiting.") + return listener; +} +IPAACA_EXPORT void InputBuffer::_trigger_resend_request(EventPtr event) { + if (!triggerResend) + return; + std::string type = event->getType(); + std::string uid = ""; + std::string writerName = ""; + if (type == "ipaaca::IUPayloadUpdate") { + boost::shared_ptr<IUPayloadUpdate> update = boost::static_pointer_cast<IUPayloadUpdate>(event->getData()); + uid = update->uid; + writerName = update->writer_name; + } else if (type == "ipaaca::IULinkUpdate") { + boost::shared_ptr<IULinkUpdate> update = boost::static_pointer_cast<IULinkUpdate>(event->getData()); + uid = update->uid; + writerName = update->writer_name; + } else if (type == "ipaaca::protobuf::IUCommission") { + boost::shared_ptr<protobuf::IUCommission> update = boost::static_pointer_cast<protobuf::IUCommission>(event->getData()); + uid = update->uid(); + writerName = update->writer_name(); + } else { + std::cout << "trigger ??? else" << std::endl; + } + + if (!writerName.empty()) { + RemoteServerPtr server = _get_remote_server(writerName); + if (!uid.empty()) { + boost::shared_ptr<protobuf::IUResendRequest> update = boost::shared_ptr<protobuf::IUResendRequest>(new protobuf::IUResendRequest()); + update->set_uid(uid); + update->set_hidden_scope_name(_uuid); + boost::shared_ptr<int> result = server->call<int>("resendRequest", update, IPAACA_REMOTE_SERVER_TIMEOUT); + if (*result == 0) { + throw IUResendRequestFailedError(); + } else { + std::cout << "revision " << *result << std::endl; + } + } + } +} +IPAACA_EXPORT void InputBuffer::_handle_iu_events(EventPtr event) +{ + std::cout << "handle iu events" << std::endl; + std::string type = event->getType(); + if (type == "ipaaca::RemotePushIU") { + boost::shared_ptr<RemotePushIU> iu = boost::static_pointer_cast<RemotePushIU>(event->getData()); + if (_iu_store.count(iu->category()) > 0) { + // already got the IU... ignore + } else { + _iu_store[iu->uid()] = iu; + iu->_set_buffer(this); + call_iu_event_handlers(iu, false, IU_ADDED, iu->category() ); + } + //IPAACA_INFO( "New RemotePushIU state: " << (*iu) ) + } else if (type == "ipaaca::RemoteMessage") { + boost::shared_ptr<RemoteMessage> iu = boost::static_pointer_cast<RemoteMessage>(event->getData()); + //_iu_store[iu->uid()] = iu; + //iu->_set_buffer(this); + //std::cout << "REFCNT after cast, before calling handlers: " << iu.use_count() << std::endl; + call_iu_event_handlers(iu, false, IU_MESSAGE, iu->category() ); + //_iu_store.erase(iu->uid()); + } else { + RemotePushIUStore::iterator it; + if (type == "ipaaca::IUPayloadUpdate") { + boost::shared_ptr<IUPayloadUpdate> update = boost::static_pointer_cast<IUPayloadUpdate>(event->getData()); + //IPAACA_INFO("** writer name: " << update->writer_name) + std::cout << "writer name " << update->writer_name << std::endl; + if (update->writer_name == _unique_name) { + return; + } + it = _iu_store.find(update->uid); + if (it == _iu_store.end()) { + _trigger_resend_request(event); + IPAACA_INFO("Using UPDATED message for an IU that we did not fully receive before") + return; + } + + it->second->_apply_update(update); + call_iu_event_handlers(it->second, false, IU_UPDATED, it->second->category() ); + + } else if (type == "ipaaca::IULinkUpdate") { + boost::shared_ptr<IULinkUpdate> update = boost::static_pointer_cast<IULinkUpdate>(event->getData()); + if (update->writer_name == _unique_name) { + return; + } + it = _iu_store.find(update->uid); + if (it == _iu_store.end()) { + _trigger_resend_request(event); + IPAACA_INFO("Ignoring LINKSUPDATED message for an IU that we did not fully receive before") + return; + } + + it->second->_apply_link_update(update); + call_iu_event_handlers(it->second, false, IU_LINKSUPDATED, it->second->category() ); + + } else if (type == "ipaaca::protobuf::IUCommission") { + boost::shared_ptr<protobuf::IUCommission> update = boost::static_pointer_cast<protobuf::IUCommission>(event->getData()); + if (update->writer_name() == _unique_name) { + return; + } + it = _iu_store.find(update->uid()); + if (it == _iu_store.end()) { + _trigger_resend_request(event); + IPAACA_INFO("Ignoring COMMITTED message for an IU that we did not fully receive before") + return; + } + // + it->second->_apply_commission(); + it->second->_revision = update->revision(); + call_iu_event_handlers(it->second, false, IU_COMMITTED, it->second->category() ); + // + // + } else if (type == "ipaaca::protobuf::IURetraction") { + boost::shared_ptr<protobuf::IURetraction> update = boost::static_pointer_cast<protobuf::IURetraction>(event->getData()); + it = _iu_store.find(update->uid()); + if (it == _iu_store.end()) { + _trigger_resend_request(event); + IPAACA_INFO("Ignoring RETRACTED message for an IU that we did not fully receive before") + return; + } + // + it->second->_revision = update->revision(); + it->second->_apply_retraction(); + // remove from InputBuffer FIXME: this is a crossover between retracted and deleted behavior + _iu_store.erase(it->first); + // and call the handler. IU reference is still valid for this call, although removed from buffer. + call_iu_event_handlers(it->second, false, IU_COMMITTED, it->second->category() ); + // + } else { + std::cout << "(Unhandled Event type " << type << " !)" << std::endl; + return; + } + //IPAACA_INFO( "New RemotePushIU state: " << *(it->second) ) + } +} +//}}} + +} // of namespace ipaaca diff --git a/ipaacalib/cpp/src/ipaaca-internal.cc b/ipaacalib/cpp/src/ipaaca-internal.cc new file mode 100644 index 0000000..3e6e82c --- /dev/null +++ b/ipaacalib/cpp/src/ipaaca-internal.cc @@ -0,0 +1,545 @@ +/* + * 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; + +// static library Initializer +IPAACA_EXPORT bool Initializer::_initialized = false; +IPAACA_EXPORT bool Initializer::initialized() { return _initialized; } +IPAACA_EXPORT void Initializer::initialize_ipaaca_rsb_if_needed()//{{{ +{ + if (_initialized) return; + + //IPAACA_INFO("Calling initialize_updated_default_config()") + initialize_updated_default_config(); + + // RYT FIXME This configuration stuff has been simply removed in rsb! + //ParticipantConfig config = ParticipantConfig::fromConfiguration(); + //getFactory().setDefaultParticipantConfig(config); + + //IPAACA_INFO("Creating and registering Converters") + boost::shared_ptr<IUConverter> iu_converter(new IUConverter()); + converterRepository<std::string>()->registerConverter(iu_converter); + + boost::shared_ptr<MessageConverter> message_converter(new MessageConverter()); + converterRepository<std::string>()->registerConverter(message_converter); + + boost::shared_ptr<IUPayloadUpdateConverter> payload_update_converter(new IUPayloadUpdateConverter()); + converterRepository<std::string>()->registerConverter(payload_update_converter); + + boost::shared_ptr<IULinkUpdateConverter> link_update_converter(new IULinkUpdateConverter()); + converterRepository<std::string>()->registerConverter(link_update_converter); + + boost::shared_ptr<ProtocolBufferConverter<protobuf::IUCommission> > iu_commission_converter(new ProtocolBufferConverter<protobuf::IUCommission> ()); + converterRepository<std::string>()->registerConverter(iu_commission_converter); + + // dlw + boost::shared_ptr<ProtocolBufferConverter<protobuf::IUResendRequest> > iu_resendrequest_converter(new ProtocolBufferConverter<protobuf::IUResendRequest> ()); + converterRepository<std::string>()->registerConverter(iu_resendrequest_converter); + + boost::shared_ptr<ProtocolBufferConverter<protobuf::IURetraction> > iu_retraction_converter(new ProtocolBufferConverter<protobuf::IURetraction> ()); + converterRepository<std::string>()->registerConverter(iu_retraction_converter); + + boost::shared_ptr<IntConverter> int_converter(new IntConverter()); + converterRepository<std::string>()->registerConverter(int_converter); + + //IPAACA_INFO("Initialization complete.") + _initialized = true; + //IPAACA_TODO("initialize all converters") +}//}}} +IPAACA_EXPORT void Initializer::dump_current_default_config()//{{{ +{ + IPAACA_INFO("--- Dumping current default participant configuration ---") + rsb::ParticipantConfig config = getFactory().getDefaultParticipantConfig(); + std::set<rsb::ParticipantConfig::Transport> transports = config.getTransports(); + for (std::set<rsb::ParticipantConfig::Transport>::const_iterator it=transports.begin(); it!=transports.end(); ++it) { + IPAACA_INFO( "Active transport: " << it->getName() ) + } + IPAACA_INFO("--- End of configuration dump ---") + //ParticipantConfig::Transport inprocess = config.getTransport("inprocess"); + //inprocess.setEnabled(true); + //config.addTransport(inprocess); +}//}}} +IPAACA_EXPORT void Initializer::initialize_updated_default_config()//{{{ +{ + // quick hack to iterate through the pwd parents + // and find the closest rsb plugin dir + // + // but only if not yet defined + const char* plugin_path = getenv("RSB_PLUGINS_CPP_PATH"); + if (!plugin_path) { +#ifdef WIN32 + LOG_IPAACA_CONSOLE("WARNING: RSB_PLUGINS_CPP_PATH not set - in Windows it has to be specified.") + //throw NotImplementedError(); +#else + LOG_IPAACA_CONSOLE("RSB_PLUGINS_CPP_PATH not set; looking here and up to 7 dirs up.") + std::string pathstr = "./"; + for (int i=0; i< 8 /* depth EIGHT (totally arbitrary..) */ ; i++) { + std::string where_str = pathstr+"deps/lib/rsb*/plugins"; + const char* where = where_str.c_str(); + glob_t g; + glob(where, 0, NULL, &g); + if (g.gl_pathc>0) { + const char* found_path = g.gl_pathv[0]; + LOG_IPAACA_CONSOLE("Found an RSB plugin dir which will be used automatically: " << found_path) + setenv("RSB_PLUGINS_CPP_PATH", found_path, 1); + break; + } // else keep going + globfree(&g); + pathstr += "../"; + } +#endif + } else { + LOG_IPAACA_CONSOLE("RSB_PLUGINS_CPP_PATH already defined: " << plugin_path) + } +}//}}} + +// RSB backend Converters +// IUConverter//{{{ + +IPAACA_EXPORT IUConverter::IUConverter() +: Converter<std::string> (IPAACA_SYSTEM_DEPENDENT_CLASS_NAME("ipaaca::IU"), "ipaaca-iu", true) +{ +} + +IPAACA_EXPORT std::string IUConverter::serialize(const AnnotatedData& data, std::string& wire) +{ + //std::cout << "serialize" << std::endl; + // Ensure that DATA actually holds a datum of the data-type we expect. + assert(data.first == getDataType()); // "ipaaca::IU" + // NOTE: a dynamic_pointer_cast cannot be used from void* + boost::shared_ptr<const IU> obj = boost::static_pointer_cast<const IU> (data.second); + boost::shared_ptr<protobuf::IU> pbo(new protobuf::IU()); + // transfer obj data to pbo + pbo->set_uid(obj->uid()); + pbo->set_revision(obj->revision()); + pbo->set_category(obj->category()); + pbo->set_payload_type(obj->payload_type()); + pbo->set_owner_name(obj->owner_name()); + pbo->set_committed(obj->committed()); + ipaaca::protobuf::IU_AccessMode a_m; + switch(obj->access_mode()) { + case IU_ACCESS_PUSH: + a_m = ipaaca::protobuf::IU_AccessMode_PUSH; + break; + case IU_ACCESS_REMOTE: + a_m = ipaaca::protobuf::IU_AccessMode_REMOTE; + break; + case IU_ACCESS_MESSAGE: + a_m = ipaaca::protobuf::IU_AccessMode_MESSAGE; + break; + } + pbo->set_access_mode(a_m); + pbo->set_read_only(obj->read_only()); + for (std::map<std::string, std::string>::const_iterator it=obj->_payload._store.begin(); it!=obj->_payload._store.end(); ++it) { + protobuf::PayloadItem* item = pbo->add_payload(); + item->set_key(it->first); + item->set_value(it->second); + item->set_type("str"); // FIXME other types than str (later) + } + for (LinkMap::const_iterator it=obj->_links._links.begin(); it!=obj->_links._links.end(); ++it) { + protobuf::LinkSet* links = pbo->add_links(); + links->set_type(it->first); + for (std::set<std::string>::const_iterator it2=it->second.begin(); it2!=it->second.end(); ++it2) { + links->add_targets(*it2); + } + } + pbo->SerializeToString(&wire); + switch(obj->access_mode()) { + case IU_ACCESS_PUSH: + //std::cout << "Requesting to send as ipaaca-iu" << std::endl; + return "ipaaca-iu"; + case IU_ACCESS_MESSAGE: + //std::cout << "Requesting to send as ipaaca-messageiu" << std::endl; + return "ipaaca-messageiu"; + default: + //std::cout << "Requesting to send as default" << std::endl; + return getWireSchema(); + } + +} + +IPAACA_EXPORT AnnotatedData IUConverter::deserialize(const std::string& wireSchema, const std::string& wire) { + //std::cout << "deserialize" << std::endl; + assert(wireSchema == getWireSchema()); // "ipaaca-iu" + boost::shared_ptr<protobuf::IU> pbo(new protobuf::IU()); + pbo->ParseFromString(wire); + IUAccessMode mode = static_cast<IUAccessMode>(pbo->access_mode()); + switch(mode) { + case IU_ACCESS_PUSH: + { + // Create a "remote push IU" + boost::shared_ptr<RemotePushIU> obj = RemotePushIU::create(); + // transfer pbo data to obj + obj->_uid = pbo->uid(); + obj->_revision = pbo->revision(); + obj->_category = pbo->category(); + obj->_payload_type = pbo->payload_type(); + obj->_owner_name = pbo->owner_name(); + obj->_committed = pbo->committed(); + obj->_read_only = pbo->read_only(); + obj->_access_mode = IU_ACCESS_PUSH; + for (int i=0; i<pbo->payload_size(); i++) { + const protobuf::PayloadItem& it = pbo->payload(i); + obj->_payload._store[it.key()] = it.value(); + } + for (int i=0; i<pbo->links_size(); i++) { + const protobuf::LinkSet& pls = pbo->links(i); + LinkSet& ls = obj->_links._links[pls.type()]; + for (int j=0; j<pls.targets_size(); j++) { + ls.insert(pls.targets(j)); + } + } + //return std::make_pair(getDataType(), obj); + return std::make_pair("ipaaca::RemotePushIU", obj); + break; + } + case IU_ACCESS_MESSAGE: + { + // Create a "Message-type IU" + boost::shared_ptr<RemoteMessage> obj = RemoteMessage::create(); + //std::cout << "REFCNT after create: " << obj.use_count() << std::endl; + // transfer pbo data to obj + obj->_uid = pbo->uid(); + obj->_revision = pbo->revision(); + obj->_category = pbo->category(); + obj->_payload_type = pbo->payload_type(); + obj->_owner_name = pbo->owner_name(); + obj->_committed = pbo->committed(); + obj->_read_only = pbo->read_only(); + obj->_access_mode = IU_ACCESS_MESSAGE; + for (int i=0; i<pbo->payload_size(); i++) { + const protobuf::PayloadItem& it = pbo->payload(i); + obj->_payload._store[it.key()] = it.value(); + } + for (int i=0; i<pbo->links_size(); i++) { + const protobuf::LinkSet& pls = pbo->links(i); + LinkSet& ls = obj->_links._links[pls.type()]; + for (int j=0; j<pls.targets_size(); j++) { + ls.insert(pls.targets(j)); + } + } + //return std::make_pair(getDataType(), obj); + return std::make_pair("ipaaca::RemoteMessage", obj); + break; + } + default: + // other cases not handled yet! ( TODO ) + throw NotImplementedError(); + } +} + +//}}} +// MessageConverter//{{{ + +IPAACA_EXPORT MessageConverter::MessageConverter() +: Converter<std::string> (IPAACA_SYSTEM_DEPENDENT_CLASS_NAME("ipaaca::Message"), "ipaaca-messageiu", true) +{ +} + +IPAACA_EXPORT std::string MessageConverter::serialize(const AnnotatedData& data, std::string& wire) +{ + // Ensure that DATA actually holds a datum of the data-type we expect. + assert(data.first == getDataType()); // "ipaaca::Message" + // NOTE: a dynamic_pointer_cast cannot be used from void* + boost::shared_ptr<const Message> obj = boost::static_pointer_cast<const Message> (data.second); + boost::shared_ptr<protobuf::IU> pbo(new protobuf::IU()); + // transfer obj data to pbo + pbo->set_uid(obj->uid()); + pbo->set_revision(obj->revision()); + pbo->set_category(obj->category()); + pbo->set_payload_type(obj->payload_type()); + pbo->set_owner_name(obj->owner_name()); + pbo->set_committed(obj->committed()); + ipaaca::protobuf::IU_AccessMode a_m; + switch(obj->access_mode()) { + case IU_ACCESS_PUSH: + a_m = ipaaca::protobuf::IU_AccessMode_PUSH; + break; + case IU_ACCESS_REMOTE: + a_m = ipaaca::protobuf::IU_AccessMode_REMOTE; + break; + case IU_ACCESS_MESSAGE: + a_m = ipaaca::protobuf::IU_AccessMode_MESSAGE; + break; + } + pbo->set_access_mode(a_m); + pbo->set_read_only(obj->read_only()); + for (std::map<std::string, std::string>::const_iterator it=obj->_payload._store.begin(); it!=obj->_payload._store.end(); ++it) { + protobuf::PayloadItem* item = pbo->add_payload(); + item->set_key(it->first); + item->set_value(it->second); + item->set_type("str"); // FIXME other types than str (later) + } + for (LinkMap::const_iterator it=obj->_links._links.begin(); it!=obj->_links._links.end(); ++it) { + protobuf::LinkSet* links = pbo->add_links(); + links->set_type(it->first); + for (std::set<std::string>::const_iterator it2=it->second.begin(); it2!=it->second.end(); ++it2) { + links->add_targets(*it2); + } + } + pbo->SerializeToString(&wire); + switch(obj->access_mode()) { + case IU_ACCESS_PUSH: + return "ipaaca-iu"; + case IU_ACCESS_MESSAGE: + return "ipaaca-messageiu"; + default: + //std::cout << "Requesting to send as default" << std::endl; + return getWireSchema(); + } + +} + +IPAACA_EXPORT AnnotatedData MessageConverter::deserialize(const std::string& wireSchema, const std::string& wire) { + assert(wireSchema == getWireSchema()); // "ipaaca-iu" + boost::shared_ptr<protobuf::IU> pbo(new protobuf::IU()); + pbo->ParseFromString(wire); + IUAccessMode mode = static_cast<IUAccessMode>(pbo->access_mode()); + switch(mode) { + case IU_ACCESS_PUSH: + { + // Create a "remote push IU" + boost::shared_ptr<RemotePushIU> obj = RemotePushIU::create(); + // transfer pbo data to obj + obj->_uid = pbo->uid(); + obj->_revision = pbo->revision(); + obj->_category = pbo->category(); + obj->_payload_type = pbo->payload_type(); + obj->_owner_name = pbo->owner_name(); + obj->_committed = pbo->committed(); + obj->_read_only = pbo->read_only(); + obj->_access_mode = IU_ACCESS_PUSH; + for (int i=0; i<pbo->payload_size(); i++) { + const protobuf::PayloadItem& it = pbo->payload(i); + obj->_payload._store[it.key()] = it.value(); + } + for (int i=0; i<pbo->links_size(); i++) { + const protobuf::LinkSet& pls = pbo->links(i); + LinkSet& ls = obj->_links._links[pls.type()]; + for (int j=0; j<pls.targets_size(); j++) { + ls.insert(pls.targets(j)); + } + } + //return std::make_pair(getDataType(), obj); + return std::make_pair("ipaaca::RemotePushIU", obj); + break; + } + case IU_ACCESS_MESSAGE: + { + // Create a "Message-type IU" + boost::shared_ptr<RemoteMessage> obj = RemoteMessage::create(); + // transfer pbo data to obj + obj->_uid = pbo->uid(); + obj->_revision = pbo->revision(); + obj->_category = pbo->category(); + obj->_payload_type = pbo->payload_type(); + obj->_owner_name = pbo->owner_name(); + obj->_committed = pbo->committed(); + obj->_read_only = pbo->read_only(); + obj->_access_mode = IU_ACCESS_MESSAGE; + for (int i=0; i<pbo->payload_size(); i++) { + const protobuf::PayloadItem& it = pbo->payload(i); + obj->_payload._store[it.key()] = it.value(); + } + for (int i=0; i<pbo->links_size(); i++) { + const protobuf::LinkSet& pls = pbo->links(i); + LinkSet& ls = obj->_links._links[pls.type()]; + for (int j=0; j<pls.targets_size(); j++) { + ls.insert(pls.targets(j)); + } + } + //return std::make_pair(getDataType(), obj); + return std::make_pair("ipaaca::RemoteMessage", obj); + break; + } + default: + // other cases not handled yet! ( TODO ) + throw NotImplementedError(); + } +} + +//}}} +// IUPayloadUpdateConverter//{{{ + +IPAACA_EXPORT IUPayloadUpdateConverter::IUPayloadUpdateConverter() +: Converter<std::string> (IPAACA_SYSTEM_DEPENDENT_CLASS_NAME("ipaaca::IUPayloadUpdate"), "ipaaca-iu-payload-update", true) +{ +} + +IPAACA_EXPORT std::string IUPayloadUpdateConverter::serialize(const AnnotatedData& data, std::string& wire) +{ + assert(data.first == getDataType()); // "ipaaca::IUPayloadUpdate" + boost::shared_ptr<const IUPayloadUpdate> obj = boost::static_pointer_cast<const IUPayloadUpdate> (data.second); + boost::shared_ptr<protobuf::IUPayloadUpdate> pbo(new protobuf::IUPayloadUpdate()); + // transfer obj data to pbo + pbo->set_uid(obj->uid); + pbo->set_revision(obj->revision); + pbo->set_writer_name(obj->writer_name); + pbo->set_is_delta(obj->is_delta); + for (std::map<std::string, std::string>::const_iterator it=obj->new_items.begin(); it!=obj->new_items.end(); ++it) { + protobuf::PayloadItem* item = pbo->add_new_items(); + item->set_key(it->first); + item->set_value(it->second); + item->set_type("str"); // FIXME other types than str (later) + } + for (std::vector<std::string>::const_iterator it=obj->keys_to_remove.begin(); it!=obj->keys_to_remove.end(); ++it) { + pbo->add_keys_to_remove(*it); + } + pbo->SerializeToString(&wire); + return getWireSchema(); + +} + +AnnotatedData IUPayloadUpdateConverter::deserialize(const std::string& wireSchema, const std::string& wire) { + assert(wireSchema == getWireSchema()); // "ipaaca-iu-payload-update" + boost::shared_ptr<protobuf::IUPayloadUpdate> pbo(new protobuf::IUPayloadUpdate()); + pbo->ParseFromString(wire); + boost::shared_ptr<IUPayloadUpdate> obj(new IUPayloadUpdate()); + // transfer pbo data to obj + obj->uid = pbo->uid(); + obj->revision = pbo->revision(); + obj->writer_name = pbo->writer_name(); + obj->is_delta = pbo->is_delta(); + for (int i=0; i<pbo->new_items_size(); i++) { + const protobuf::PayloadItem& it = pbo->new_items(i); + obj->new_items[it.key()] = it.value(); + } + for (int i=0; i<pbo->keys_to_remove_size(); i++) { + obj->keys_to_remove.push_back(pbo->keys_to_remove(i)); + } + return std::make_pair(getDataType(), obj); +} + +//}}} +// IULinkUpdateConverter//{{{ + +IPAACA_EXPORT IULinkUpdateConverter::IULinkUpdateConverter() +: Converter<std::string> (IPAACA_SYSTEM_DEPENDENT_CLASS_NAME("ipaaca::IULinkUpdate"), "ipaaca-iu-link-update", true) +{ +} + +IPAACA_EXPORT std::string IULinkUpdateConverter::serialize(const AnnotatedData& data, std::string& wire) +{ + assert(data.first == getDataType()); // "ipaaca::IULinkUpdate" + boost::shared_ptr<const IULinkUpdate> obj = boost::static_pointer_cast<const IULinkUpdate> (data.second); + boost::shared_ptr<protobuf::IULinkUpdate> pbo(new protobuf::IULinkUpdate()); + // transfer obj data to pbo + pbo->set_uid(obj->uid); + pbo->set_revision(obj->revision); + pbo->set_writer_name(obj->writer_name); + pbo->set_is_delta(obj->is_delta); + for (std::map<std::string, std::set<std::string> >::const_iterator it=obj->new_links.begin(); it!=obj->new_links.end(); ++it) { + protobuf::LinkSet* links = pbo->add_new_links(); + links->set_type(it->first); + for (std::set<std::string>::const_iterator it2=it->second.begin(); it2!=it->second.end(); ++it2) { + links->add_targets(*it2); + } + } + for (std::map<std::string, std::set<std::string> >::const_iterator it=obj->links_to_remove.begin(); it!=obj->links_to_remove.end(); ++it) { + protobuf::LinkSet* links = pbo->add_links_to_remove(); + links->set_type(it->first); + for (std::set<std::string>::const_iterator it2=it->second.begin(); it2!=it->second.end(); ++it2) { + links->add_targets(*it2); + } + } + pbo->SerializeToString(&wire); + return getWireSchema(); + +} + +AnnotatedData IULinkUpdateConverter::deserialize(const std::string& wireSchema, const std::string& wire) { + assert(wireSchema == getWireSchema()); // "ipaaca-iu-link-update" + boost::shared_ptr<protobuf::IULinkUpdate> pbo(new protobuf::IULinkUpdate()); + pbo->ParseFromString(wire); + boost::shared_ptr<IULinkUpdate> obj(new IULinkUpdate()); + // transfer pbo data to obj + obj->uid = pbo->uid(); + obj->revision = pbo->revision(); + obj->writer_name = pbo->writer_name(); + obj->is_delta = pbo->is_delta(); + for (int i=0; i<pbo->new_links_size(); ++i) { + const protobuf::LinkSet& it = pbo->new_links(i); + for (int j=0; j<it.targets_size(); ++j) { + obj->new_links[it.type()].insert(it.targets(j)); // = vec; + } + } + for (int i=0; i<pbo->links_to_remove_size(); ++i) { + const protobuf::LinkSet& it = pbo->links_to_remove(i); + for (int j=0; j<it.targets_size(); ++j) { + obj->links_to_remove[it.type()].insert(it.targets(j)); + } + } + return std::make_pair(getDataType(), obj); +} + +//}}} +// IntConverter//{{{ + +IPAACA_EXPORT IntConverter::IntConverter() +: Converter<std::string> ("int", "int32", true) +{ +} + +IPAACA_EXPORT std::string IntConverter::serialize(const AnnotatedData& data, std::string& wire) +{ + // Ensure that DATA actually holds a datum of the data-type we expect. + assert(data.first == getDataType()); // "int" + // NOTE: a dynamic_pointer_cast cannot be used from void* + boost::shared_ptr<const int> obj = boost::static_pointer_cast<const int> (data.second); + boost::shared_ptr<protobuf::IntMessage> pbo(new protobuf::IntMessage()); + // transfer obj data to pbo + pbo->set_value(*obj); + pbo->SerializeToString(&wire); + return getWireSchema(); + +} + +IPAACA_EXPORT AnnotatedData IntConverter::deserialize(const std::string& wireSchema, const std::string& wire) { + assert(wireSchema == getWireSchema()); // "int" + boost::shared_ptr<protobuf::IntMessage> pbo(new protobuf::IntMessage()); + pbo->ParseFromString(wire); + boost::shared_ptr<int> obj = boost::shared_ptr<int>(new int(pbo->value())); + return std::make_pair("int", obj); +} + +//}}} + +} // of namespace ipaaca diff --git a/ipaacalib/cpp/src/ipaaca-ius.cc b/ipaacalib/cpp/src/ipaaca-ius.cc new file mode 100644 index 0000000..39c9d5c --- /dev/null +++ b/ipaacalib/cpp/src/ipaaca-ius.cc @@ -0,0 +1,464 @@ +/* + * 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(); + +} + +//}}} + +// IU//{{{ +IPAACA_EXPORT IU::ptr IU::create(const std::string& category, IUAccessMode access_mode, bool read_only, const std::string& payload_type) +{ + IU::ptr iu = IU::ptr(new IU(category, access_mode, read_only, payload_type)); /* params */ //)); + iu->_payload.initialize(iu); + return iu; +} + +IPAACA_EXPORT IU::IU(const std::string& category, IUAccessMode access_mode, bool read_only, const std::string& payload_type) +{ + _revision = 1; + _uid = ipaaca::generate_uuid_string(); + _category = category; + _payload_type = payload_type; + // payload initialization deferred to IU::create(), above + _read_only = read_only; + _access_mode = access_mode; + _committed = false; +} + +IPAACA_EXPORT void IU::_modify_links(bool is_delta, const LinkMap& new_links, const LinkMap& links_to_remove, const std::string& writer_name) +{ + _revision_lock.lock(); + if (_committed) { + _revision_lock.unlock(); + throw IUCommittedError(); + } + _increase_revision_number(); + if (is_published()) { + _buffer->_send_iu_link_update(this, is_delta, _revision, new_links, links_to_remove, writer_name); + } + _revision_lock.unlock(); +} + + +IPAACA_EXPORT void IU::_publish_resend(IU::ptr iu, const std::string& hidden_scope_name) +{ + //_revision_lock.lock(); + //if (_committed) { + // _revision_lock.unlock(); + // throw IUCommittedError(); + //} + //_increase_revision_number(); + //if (is_published()) { + //IUInterface* iu, bool is_delta, revision_t revision, const LinkMap& new_links, const LinkMap& links_to_remove, const std::string& writer_name + _buffer->_publish_iu_resend(iu, hidden_scope_name); + //} + //_revision_lock.unlock(); +} + + + + + +IPAACA_EXPORT void IU::_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) +{ + _revision_lock.lock(); + if (_committed) { + _revision_lock.unlock(); + throw IUCommittedError(); + } + _increase_revision_number(); + if (is_published()) { + //std::cout << "Sending a payload update with " << new_items.size() << " entries to merge." << std::endl; + _buffer->_send_iu_payload_update(this, is_delta, _revision, new_items, keys_to_remove, writer_name); + } + _revision_lock.unlock(); +} + +IPAACA_EXPORT void IU::commit() +{ + _internal_commit(); +} + +IPAACA_EXPORT void IU::_internal_commit(const std::string& writer_name) +{ + _revision_lock.lock(); + if (_committed) { + _revision_lock.unlock(); + throw IUCommittedError(); + } + _increase_revision_number(); + _committed = true; + if (is_published()) { + _buffer->_send_iu_commission(this, _revision, writer_name); + } + _revision_lock.unlock(); +} +//}}} +// Message//{{{ +Message::ptr Message::create(const std::string& category, IUAccessMode access_mode, bool read_only, const std::string& payload_type) +{ + Message::ptr iu = Message::ptr(new Message(category, access_mode, read_only, payload_type)); /* params */ //)); + iu->_payload.initialize(iu); + return iu; +} + +Message::Message(const std::string& category, IUAccessMode access_mode, bool read_only, const std::string& payload_type) +: IU(category, access_mode, read_only, payload_type) +{ +} + +void Message::_modify_links(bool is_delta, const LinkMap& new_links, const LinkMap& links_to_remove, const std::string& writer_name) +{ + if (is_published()) { + IPAACA_INFO("Info: modifying a Message after sending has no global effects") + } +} +void Message::_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) +{ + if (is_published()) { + IPAACA_INFO("Info: modifying a Message after sending has no global effects") + } +} + +void Message::_internal_commit(const std::string& writer_name) +{ + if (is_published()) { + IPAACA_INFO("Info: committing to a Message after sending has no global effects") + } + +} +//}}} + +// RemotePushIU//{{{ + +IPAACA_EXPORT RemotePushIU::ptr RemotePushIU::create() +{ + RemotePushIU::ptr iu = RemotePushIU::ptr(new RemotePushIU(/* params */)); + iu->_payload.initialize(iu); + return iu; +} +IPAACA_EXPORT RemotePushIU::RemotePushIU() +{ + // nothing +} +IPAACA_EXPORT void RemotePushIU::_modify_links(bool is_delta, const LinkMap& new_links, const LinkMap& links_to_remove, const std::string& writer_name) +{ + if (_committed) { + throw IUCommittedError(); + } + if (_read_only) { + throw IUReadOnlyError(); + } + RemoteServerPtr server = boost::static_pointer_cast<InputBuffer>(_buffer)->_get_remote_server(_owner_name); + IULinkUpdate::ptr update = IULinkUpdate::ptr(new IULinkUpdate()); + update->uid = _uid; + update->revision = _revision; + update->is_delta = is_delta; + update->writer_name = _buffer->unique_name(); + update->new_links = new_links; + update->links_to_remove = links_to_remove; + boost::shared_ptr<int> result = server->call<int>("updateLinks", update, IPAACA_REMOTE_SERVER_TIMEOUT); // TODO + if (*result == 0) { + throw IUUpdateFailedError(); + } else { + _revision = *result; + } +} +IPAACA_EXPORT void RemotePushIU::_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) +{ + //std::cout << "-- Sending a modify_payload with " << new_items.size() << " keys to merge." << std::endl; + if (_committed) { + throw IUCommittedError(); + } + if (_read_only) { + throw IUReadOnlyError(); + } + RemoteServerPtr server = boost::static_pointer_cast<InputBuffer>(_buffer)->_get_remote_server(_owner_name); + IUPayloadUpdate::ptr update = IUPayloadUpdate::ptr(new IUPayloadUpdate()); + update->uid = _uid; + update->revision = _revision; + update->is_delta = is_delta; + update->writer_name = _buffer->unique_name(); + update->new_items = new_items; + update->keys_to_remove = keys_to_remove; + boost::shared_ptr<int> result = server->call<int>("updatePayload", update, IPAACA_REMOTE_SERVER_TIMEOUT); // TODO + if (*result == 0) { + throw IUUpdateFailedError(); + } else { + _revision = *result; + } +} + +IPAACA_EXPORT void RemotePushIU::commit() +{ + if (_read_only) { + throw IUReadOnlyError(); + } + if (_committed) { + // Following python version: ignoring multiple commit + return; + } + RemoteServerPtr server = boost::static_pointer_cast<InputBuffer>(_buffer)->_get_remote_server(_owner_name); + boost::shared_ptr<protobuf::IUCommission> update = boost::shared_ptr<protobuf::IUCommission>(new protobuf::IUCommission()); + update->set_uid(_uid); + update->set_revision(_revision); + update->set_writer_name(_buffer->unique_name()); + boost::shared_ptr<int> result = server->call<int>("commit", update, IPAACA_REMOTE_SERVER_TIMEOUT); // TODO + if (*result == 0) { + throw IUUpdateFailedError(); + } else { + _revision = *result; + } +} + +IPAACA_EXPORT void RemotePushIU::_apply_link_update(IULinkUpdate::ptr update) +{ + _revision = update->revision; + if (update->is_delta) { + _add_and_remove_links(update->new_links, update->links_to_remove); + } else { + _replace_links(update->new_links); + } +} +IPAACA_EXPORT void RemotePushIU::_apply_update(IUPayloadUpdate::ptr update) +{ + _revision = update->revision; + if (update->is_delta) { + for (std::vector<std::string>::const_iterator it=update->keys_to_remove.begin(); it!=update->keys_to_remove.end(); ++it) { + _payload._remotely_enforced_delitem(*it); + } + for (std::map<std::string, std::string>::const_iterator it=update->new_items.begin(); it!=update->new_items.end(); ++it) { + _payload._remotely_enforced_setitem(it->first, it->second); + } + } else { + _payload._remotely_enforced_wipe(); + for (std::map<std::string, std::string>::const_iterator it=update->new_items.begin(); it!=update->new_items.end(); ++it) { + _payload._remotely_enforced_setitem(it->first, it->second); + } + } +} +IPAACA_EXPORT void RemotePushIU::_apply_commission() +{ + _committed = true; +} +IPAACA_EXPORT void RemotePushIU::_apply_retraction() +{ + _retracted = true; +} +//}}} + +// RemoteMessage//{{{ + +IPAACA_EXPORT RemoteMessage::ptr RemoteMessage::create() +{ + RemoteMessage::ptr iu = RemoteMessage::ptr(new RemoteMessage(/* params */)); + iu->_payload.initialize(iu); + return iu; +} +IPAACA_EXPORT RemoteMessage::RemoteMessage() +{ + // nothing +} +IPAACA_EXPORT void RemoteMessage::_modify_links(bool is_delta, const LinkMap& new_links, const LinkMap& links_to_remove, const std::string& writer_name) +{ + IPAACA_INFO("Info: modifying a RemoteMessage only has local effects") +} +IPAACA_EXPORT void RemoteMessage::_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) +{ + IPAACA_INFO("Info: modifying a RemoteMessage only has local effects") +} +IPAACA_EXPORT void RemoteMessage::commit() +{ + IPAACA_INFO("Info: committing to a RemoteMessage only has local effects") +} + +IPAACA_EXPORT void RemoteMessage::_apply_link_update(IULinkUpdate::ptr update) +{ + IPAACA_WARNING("Warning: should never be called: RemoteMessage::_apply_link_update") + _revision = update->revision; + if (update->is_delta) { + _add_and_remove_links(update->new_links, update->links_to_remove); + } else { + _replace_links(update->new_links); + } +} +IPAACA_EXPORT void RemoteMessage::_apply_update(IUPayloadUpdate::ptr update) +{ + IPAACA_WARNING("Warning: should never be called: RemoteMessage::_apply_update") + _revision = update->revision; + if (update->is_delta) { + for (std::vector<std::string>::const_iterator it=update->keys_to_remove.begin(); it!=update->keys_to_remove.end(); ++it) { + _payload._remotely_enforced_delitem(*it); + } + for (std::map<std::string, std::string>::const_iterator it=update->new_items.begin(); it!=update->new_items.end(); ++it) { + _payload._remotely_enforced_setitem(it->first, it->second); + } + } else { + _payload._remotely_enforced_wipe(); + for (std::map<std::string, std::string>::const_iterator it=update->new_items.begin(); it!=update->new_items.end(); ++it) { + _payload._remotely_enforced_setitem(it->first, it->second); + } + } +} +IPAACA_EXPORT void RemoteMessage::_apply_commission() +{ + IPAACA_WARNING("Warning: should never be called: RemoteMessage::_apply_commission") + _committed = true; +} +IPAACA_EXPORT void RemoteMessage::_apply_retraction() +{ + IPAACA_WARNING("Warning: should never be called: RemoteMessage::_apply_retraction") + _retracted = true; +} + +//}}} + +} // of namespace ipaaca diff --git a/ipaacalib/cpp/src/ipaaca-locking.cc b/ipaacalib/cpp/src/ipaaca-locking.cc new file mode 100644 index 0000000..96748cd --- /dev/null +++ b/ipaacalib/cpp/src/ipaaca-locking.cc @@ -0,0 +1,43 @@ +/* + * 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 { + +Lock& logger_lock() { + static Lock lock; + return lock; +} + +} // of namespace ipaaca diff --git a/ipaacalib/cpp/src/ipaaca-payload.cc b/ipaacalib/cpp/src/ipaaca-payload.cc new file mode 100644 index 0000000..fdc1d61 --- /dev/null +++ b/ipaacalib/cpp/src/ipaaca-payload.cc @@ -0,0 +1,226 @@ +/* + * 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 Payload& obj)//{{{ +{ + os << "{"; + bool first = true; + for (std::map<std::string, std::string>::const_iterator it=obj._store.begin(); it!=obj._store.end(); ++it) { + if (first) { first=false; } else { os << ", "; } + os << "'" << it->first << "':'" << it->second << "'"; + } + os << "}"; + return os; +} +//}}} + +// PayloadEntryProxy//{{{ + +IPAACA_EXPORT PayloadEntryProxy::PayloadEntryProxy(Payload* payload, const std::string& key) +: _payload(payload), _key(key) +{ +} +IPAACA_EXPORT PayloadEntryProxy& PayloadEntryProxy::operator=(const std::string& value) +{ + //std::cout << "operator=(string)" << std::endl; + _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); + return *this; +} +IPAACA_EXPORT PayloadEntryProxy& PayloadEntryProxy::operator=(double value) +{ + //std::cout << "operator=(double)" << std::endl; + _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)); + return *this; +} + +IPAACA_EXPORT inline PayloadEntryProxy::operator std::string() +{ + return PayloadEntryProxy::get<std::string>(); } +IPAACA_EXPORT inline PayloadEntryProxy::operator long() +{ + return PayloadEntryProxy::get<long>(); +} +IPAACA_EXPORT inline PayloadEntryProxy::operator double() +{ + return PayloadEntryProxy::get<double>(); +} +IPAACA_EXPORT inline PayloadEntryProxy::operator bool() +{ + return PayloadEntryProxy::get<bool>(); +} +IPAACA_EXPORT inline std::string PayloadEntryProxy::to_str() +{ + return PayloadEntryProxy::get<std::string>(); +} +IPAACA_EXPORT inline long PayloadEntryProxy::to_long() +{ + return PayloadEntryProxy::get<long>(); +} +IPAACA_EXPORT inline double PayloadEntryProxy::to_float() +{ + return PayloadEntryProxy::get<double>(); +} +IPAACA_EXPORT inline bool PayloadEntryProxy::to_bool() +{ + return PayloadEntryProxy::get<bool>(); +} + + +// +// new stuff for protocol v2 +// +IPAACA_HEADER_EXPORT template<> std::string PayloadEntryProxy::get<std::string>() +{ + return _payload->get(_key); +} +IPAACA_HEADER_EXPORT template<> long PayloadEntryProxy::get<long>() +{ + return atof(operator std::string().c_str()); +} +IPAACA_HEADER_EXPORT template<> double PayloadEntryProxy::get<double>() +{ + return atol(operator std::string().c_str()); +} +IPAACA_HEADER_EXPORT template<> bool PayloadEntryProxy::get<bool>() +{ + std::string s = operator std::string(); + return ((s=="1")||(s=="true")||(s=="True")); +} +// complex types +IPAACA_HEADER_EXPORT template<> std::list<std::string> PayloadEntryProxy::get<std::list<std::string> >() +{ + std::list<std::string> l; + l.push_back(PayloadEntryProxy::get<std::string>()); + return l; +} +IPAACA_HEADER_EXPORT template<> std::vector<std::string> PayloadEntryProxy::get<std::vector<std::string> >() +{ + std::vector<std::string> v; + v.push_back(PayloadEntryProxy::get<std::string>()); + return v; +} +IPAACA_HEADER_EXPORT template<> std::map<std::string, std::string> PayloadEntryProxy::get<std::map<std::string, std::string> >() +{ + std::map<std::string, std::string> m; + m["__automatic__"] = PayloadEntryProxy::get<std::string>(); + return m; +} +//}}} + +// Payload//{{{ + +IPAACA_EXPORT void Payload::initialize(boost::shared_ptr<IUInterface> iu) +{ + _iu = boost::weak_ptr<IUInterface>(iu); +} + +IPAACA_EXPORT PayloadEntryProxy Payload::operator[](const std::string& key) +{ + //boost::shared_ptr<PayloadEntryProxy> p(new PayloadEntryProxy(this, key)); + return PayloadEntryProxy(this, key); +} +IPAACA_EXPORT Payload::operator std::map<std::string, std::string>() +{ + return _store; +} + +IPAACA_EXPORT void Payload::_internal_set(const std::string& k, const std::string& v, const std::string& writer_name) { + std::map<std::string, std::string> _new; + std::vector<std::string> _remove; + _new[k]=v; + _iu.lock()->_modify_payload(true, _new, _remove, writer_name ); + _store[k] = v; +} +IPAACA_EXPORT void Payload::_internal_remove(const std::string& k, const std::string& writer_name) { + std::map<std::string, std::string> _new; + std::vector<std::string> _remove; + _remove.push_back(k); + _iu.lock()->_modify_payload(true, _new, _remove, writer_name ); + _store.erase(k); +} +IPAACA_EXPORT void Payload::_internal_replace_all(const std::map<std::string, std::string>& 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; +} +IPAACA_EXPORT void Payload::_internal_merge(const std::map<std::string, std::string>& contents_to_merge, const std::string& writer_name) +{ + std::vector<std::string> _remove; + _iu.lock()->_modify_payload(true, contents_to_merge, _remove, writer_name ); + _store.insert(contents_to_merge.begin(), contents_to_merge.end()); + //for (std::map<std::string, std::string>::iterator it = contents_to_merge.begin(); it!=contents_to_merge.end(); i++) { + // _store[it->first] = it->second; + //} +} +IPAACA_EXPORT inline std::string Payload::get(const std::string& k) { + if (_store.count(k)>0) return _store[k]; + else return IPAACA_PAYLOAD_DEFAULT_STRING_VALUE; +} +IPAACA_EXPORT void Payload::_remotely_enforced_wipe() +{ + _store.clear(); +} +IPAACA_EXPORT void Payload::_remotely_enforced_delitem(const std::string& k) +{ + _store.erase(k); +} +IPAACA_EXPORT void Payload::_remotely_enforced_setitem(const std::string& k, const std::string& v) +{ + _store[k] = v; +} + +//}}} + +} // of namespace ipaaca diff --git a/ipaacalib/cpp/src/ipaaca.cc b/ipaacalib/cpp/src/ipaaca.cc index c70df0b..a6a092f 100644 --- a/ipaacalib/cpp/src/ipaaca.cc +++ b/ipaacalib/cpp/src/ipaaca.cc @@ -3,7 +3,8 @@ * "Incremental Processing Architecture * for Artificial Conversational Agents". * - * Copyright (c) 2009-2013 Sociable Agents Group + * Copyright (c) 2009-2015 Social Cognitive Systems Group + * (formerly the Sociable Agents Group) * CITEC, Bielefeld University * * http://opensource.cit-ec.de/projects/ipaaca/ @@ -31,127 +32,11 @@ */ #include <ipaaca/ipaaca.h> -#include <cstdlib> - -#ifdef WIN32 -#include <rpc.h> -#else -#include <uuid/uuid.h> -#include <glob.h> -#endif namespace ipaaca { -using namespace rsb; -using namespace rsb::filter; -using namespace rsb::converter; -using namespace rsb::patterns; - -#define VERBOSE_HANDLERS 0 - -Lock& logger_lock() { - static Lock lock; - return lock; -} - -// util and init//{{{ - -IPAACA_EXPORT bool Initializer::_initialized = false; - -//const LinkSet EMPTY_LINK_SET = LinkSet(); -//const std::set<std::string> EMPTY_LINK_SET(); -IPAACA_EXPORT bool Initializer::initialized() { return _initialized; } -IPAACA_EXPORT void Initializer::initialize_ipaaca_rsb_if_needed() -{ - if (_initialized) return; - - //IPAACA_INFO("Calling initialize_updated_default_config()") - initialize_updated_default_config(); - - // RYT FIXME This configuration stuff has been simply removed in rsb! - //ParticipantConfig config = ParticipantConfig::fromConfiguration(); - //getFactory().setDefaultParticipantConfig(config); - - //IPAACA_INFO("Creating and registering Converters") - boost::shared_ptr<IUConverter> iu_converter(new IUConverter()); - converterRepository<std::string>()->registerConverter(iu_converter); - - boost::shared_ptr<MessageConverter> message_converter(new MessageConverter()); - converterRepository<std::string>()->registerConverter(message_converter); - - boost::shared_ptr<IUPayloadUpdateConverter> payload_update_converter(new IUPayloadUpdateConverter()); - converterRepository<std::string>()->registerConverter(payload_update_converter); - - boost::shared_ptr<IULinkUpdateConverter> link_update_converter(new IULinkUpdateConverter()); - converterRepository<std::string>()->registerConverter(link_update_converter); - - boost::shared_ptr<ProtocolBufferConverter<protobuf::IUCommission> > iu_commission_converter(new ProtocolBufferConverter<protobuf::IUCommission> ()); - converterRepository<std::string>()->registerConverter(iu_commission_converter); - - // dlw - boost::shared_ptr<ProtocolBufferConverter<protobuf::IUResendRequest> > iu_resendrequest_converter(new ProtocolBufferConverter<protobuf::IUResendRequest> ()); - converterRepository<std::string>()->registerConverter(iu_resendrequest_converter); - - boost::shared_ptr<ProtocolBufferConverter<protobuf::IURetraction> > iu_retraction_converter(new ProtocolBufferConverter<protobuf::IURetraction> ()); - converterRepository<std::string>()->registerConverter(iu_retraction_converter); - - boost::shared_ptr<IntConverter> int_converter(new IntConverter()); - converterRepository<std::string>()->registerConverter(int_converter); - - //IPAACA_INFO("Initialization complete.") - _initialized = true; - //IPAACA_TODO("initialize all converters") -} - -IPAACA_EXPORT void Initializer::dump_current_default_config() -{ - IPAACA_INFO("--- Dumping current default participant configuration ---") - rsb::ParticipantConfig config = getFactory().getDefaultParticipantConfig(); - std::set<rsb::ParticipantConfig::Transport> transports = config.getTransports(); - for (std::set<rsb::ParticipantConfig::Transport>::const_iterator it=transports.begin(); it!=transports.end(); ++it) { - IPAACA_INFO( "Active transport: " << it->getName() ) - } - IPAACA_INFO("--- End of configuration dump ---") - //ParticipantConfig::Transport inprocess = config.getTransport("inprocess"); - //inprocess.setEnabled(true); - //config.addTransport(inprocess); -} - -IPAACA_EXPORT void Initializer::initialize_updated_default_config() -{ - // quick hack to iterate through the pwd parents - // and find the closest rsb plugin dir - // - // but only if not yet defined - const char* plugin_path = getenv("RSB_PLUGINS_CPP_PATH"); - if (!plugin_path) { -#ifdef WIN32 - LOG_IPAACA_CONSOLE("WARNING: RSB_PLUGINS_CPP_PATH not set - in Windows it has to be specified.") - //throw NotImplementedError(); -#else - LOG_IPAACA_CONSOLE("RSB_PLUGINS_CPP_PATH not set; looking here and up to 7 dirs up.") - std::string pathstr = "./"; - for (int i=0; i< 8 /* depth EIGHT (totally arbitrary..) */ ; i++) { - std::string where_str = pathstr+"deps/lib/rsb*/plugins"; - const char* where = where_str.c_str(); - glob_t g; - glob(where, 0, NULL, &g); - if (g.gl_pathc>0) { - const char* found_path = g.gl_pathv[0]; - LOG_IPAACA_CONSOLE("Found an RSB plugin dir which will be used automatically: " << found_path) - setenv("RSB_PLUGINS_CPP_PATH", found_path, 1); - break; - } // else keep going - globfree(&g); - pathstr += "../"; - } -#endif - } else { - LOG_IPAACA_CONSOLE("RSB_PLUGINS_CPP_PATH already defined: " << plugin_path) - } -} - -IPAACA_EXPORT std::string generate_uuid_string() +// UUID generation +IPAACA_EXPORT std::string generate_uuid_string()//{{{ { #ifdef WIN32 // Windows @@ -185,7 +70,7 @@ IPAACA_EXPORT std::string generate_uuid_string() return result_c; #endif #endif -} +}//}}} /* void init_inprocess_too() { @@ -197,1780 +82,7 @@ void init_inprocess_too() { getFactory().setDefaultParticipantConfig(config); } */ -//}}} - -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 Payload& obj)//{{{ -{ - os << "{"; - bool first = true; - for (std::map<std::string, std::string>::const_iterator it=obj._store.begin(); it!=obj._store.end(); ++it) { - if (first) { first=false; } else { os << ", "; } - os << "'" << it->first << "':'" << it->second << "'"; - } - os << "}"; - return os; -} -//}}} -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; -} -//}}} -IPAACA_EXPORT std::ostream& operator<<(std::ostream& os, const IUPayloadUpdate& obj)//{{{ -{ - os << "PayloadUpdate(uid=" << obj.uid << ", revision=" << obj.revision; - os << ", writer_name=" << obj.writer_name << ", is_delta=" << (obj.is_delta?"True":"False"); - os << ", new_items = {"; - bool first = true; - for (std::map<std::string, std::string>::const_iterator it=obj.new_items.begin(); it!=obj.new_items.end(); ++it) { - if (first) { first=false; } else { os << ", "; } - os << "'" << it->first << "':'" << it->second << "'"; - } - os << "}, keys_to_remove = ["; - first = true; - for (std::vector<std::string>::const_iterator it=obj.keys_to_remove.begin(); it!=obj.keys_to_remove.end(); ++it) { - if (first) { first=false; } else { os << ", "; } - os << "'" << *it << "'"; - } - os << "])"; - return os; -} -//}}} -IPAACA_EXPORT std::ostream& operator<<(std::ostream& os, const IULinkUpdate& obj)//{{{ -{ - os << "LinkUpdate(uid=" << obj.uid << ", revision=" << obj.revision; - os << ", writer_name=" << obj.writer_name << ", is_delta=" << (obj.is_delta?"True":"False"); - os << ", new_links = {"; - bool first = true; - for (std::map<std::string, std::set<std::string> >::const_iterator it=obj.new_links.begin(); it!=obj.new_links.end(); ++it) { - if (first) { first=false; } else { os << ", "; } - os << "'" << it->first << "': ["; - bool ffirst = true; - for (std::set<std::string>::const_iterator it2=it->second.begin(); it2!=it->second.end(); ++it2) { - if (ffirst) { ffirst=false; } else { os << ", "; } - os << "'" << *it2 << "'"; - } - os << "]"; - } - os << "}, links_to_remove = {"; - first = true; - for (std::map<std::string, std::set<std::string> >::const_iterator it=obj.links_to_remove.begin(); it!=obj.links_to_remove.end(); ++it) { - if (first) { first=false; } else { os << ", "; } - os << "'" << it->first << "': ["; - bool ffirst = true; - for (std::set<std::string>::const_iterator it2=it->second.begin(); it2!=it->second.end(); ++it2) { - if (ffirst) { ffirst=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; -} -//}}} - -// IUEventHandler//{{{ -IPAACA_EXPORT 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); - } -} -IPAACA_EXPORT 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; - } -} -IPAACA_EXPORT 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) { -#if VERBOSE_HANDLERS == 1 - std::cout << "[" << pthread_self() << " handler ENTER]" << std::endl; -#endif - _function(iu, event_type, local); -#if VERBOSE_HANDLERS == 1 - std::cout << "[" << pthread_self() << " handler EXIT]" << std::endl; -#endif - //} - } -} -//}}} - -// Buffer//{{{ -IPAACA_EXPORT void Buffer::_allocate_unique_name(const std::string& basename, const std::string& function) { - std::string uuid = ipaaca::generate_uuid_string(); - _basename = basename; - _uuid = uuid.substr(0,8); - _unique_name = "/ipaaca/component/" + _basename + "ID" + _uuid + "/" + function; -} -IPAACA_EXPORT void Buffer::register_handler(IUEventHandlerFunction function, IUEventType event_mask, const std::set<std::string>& categories) -{ - std::cout << "register_handler " << function << " " << event_mask << " " << categories << std::endl; - IUEventHandler::ptr handler = IUEventHandler::ptr(new IUEventHandler(function, event_mask, categories)); - _event_handlers.push_back(handler); -} -IPAACA_EXPORT void Buffer::register_handler(IUEventHandlerFunction function, IUEventType event_mask, const std::string& category) -{ - std::cout << "register_handler " << function << " " << event_mask << " " << category << std::endl; - IUEventHandler::ptr handler = IUEventHandler::ptr(new IUEventHandler(function, event_mask, category)); - _event_handlers.push_back(handler); -} -IPAACA_EXPORT void Buffer::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 " << iu->uid()) - std::cout << "handling an event " << ipaaca::iu_event_type_to_str(event_type) << " for IU " << iu->uid() << std::endl; - for (std::vector<IUEventHandler::ptr>::iterator it = _event_handlers.begin(); it != _event_handlers.end(); ++it) { - (*it)->call(this, iu, local, event_type, category); - } -} -//}}} - -// Callbacks for OutputBuffer//{{{ -IPAACA_EXPORT CallbackIUPayloadUpdate::CallbackIUPayloadUpdate(Buffer* buffer): _buffer(buffer) { } -IPAACA_EXPORT CallbackIULinkUpdate::CallbackIULinkUpdate(Buffer* buffer): _buffer(buffer) { } -IPAACA_EXPORT CallbackIUCommission::CallbackIUCommission(Buffer* buffer): _buffer(buffer) { } -// dlw -IPAACA_EXPORT CallbackIUResendRequest::CallbackIUResendRequest(Buffer* buffer): _buffer(buffer) { } - -IPAACA_EXPORT boost::shared_ptr<int> CallbackIUPayloadUpdate::call(const std::string& methodName, boost::shared_ptr<IUPayloadUpdate> update) -{ - //std::cout << "-- Received a modify_payload with " << update->new_items.size() << " keys to merge." << std::endl; - IUInterface::ptr iui = _buffer->get(update->uid); - if (! iui) { - IPAACA_WARNING("Remote InBuffer tried to spuriously write non-existent IU " << update->uid) - return boost::shared_ptr<int>(new int(0)); - } - IU::ptr iu = boost::static_pointer_cast<IU>(iui); - iu->_revision_lock.lock(); - if ((update->revision != 0) && (update->revision != iu->_revision)) { - IPAACA_INFO("Remote write operation failed because request was out of date; IU " << update->uid) - iu->_revision_lock.unlock(); - return boost::shared_ptr<int>(new int(0)); - } - if (update->is_delta) { - // FIXME FIXME this is an unsolved problem atm: deletes in a delta update are - // sent individually. We should have something like _internal_merge_and_remove - for (std::vector<std::string>::const_iterator it=update->keys_to_remove.begin(); it!=update->keys_to_remove.end(); ++it) { - iu->payload()._internal_remove(*it, update->writer_name); //_buffer->unique_name()); - } - // but it is solved for pure merges: - iu->payload()._internal_merge(update->new_items, update->writer_name); - } else { - iu->payload()._internal_replace_all(update->new_items, update->writer_name); //_buffer->unique_name()); - } - //std::cout << "-- Calling update handler due to remote write." << std::endl; - _buffer->call_iu_event_handlers(iu, true, IU_UPDATED, iu->category()); - revision_t revision = iu->revision(); - iu->_revision_lock.unlock(); - return boost::shared_ptr<int>(new int(revision)); -} - -IPAACA_EXPORT boost::shared_ptr<int> CallbackIULinkUpdate::call(const std::string& methodName, boost::shared_ptr<IULinkUpdate> update) -{ - IUInterface::ptr iui = _buffer->get(update->uid); - if (! iui) { - IPAACA_WARNING("Remote InBuffer tried to spuriously write non-existent IU " << update->uid) - return boost::shared_ptr<int>(new int(0)); - } - IU::ptr iu = boost::static_pointer_cast<IU>(iui); - iu->_revision_lock.lock(); - if ((update->revision != 0) && (update->revision != iu->_revision)) { - IPAACA_INFO("Remote write operation failed because request was out of date; IU " << update->uid) - iu->_revision_lock.unlock(); - return boost::shared_ptr<int>(new int(0)); - } - if (update->is_delta) { - iu->modify_links(update->new_links, update->links_to_remove, update->writer_name); - } else { - iu->set_links(update->new_links, update->writer_name); - } - _buffer->call_iu_event_handlers(iu, true, IU_LINKSUPDATED, iu->category()); - revision_t revision = iu->revision(); - iu->_revision_lock.unlock(); - return boost::shared_ptr<int>(new int(revision)); -} -IPAACA_EXPORT boost::shared_ptr<int> CallbackIUCommission::call(const std::string& methodName, boost::shared_ptr<protobuf::IUCommission> update) -{ - IUInterface::ptr iui = _buffer->get(update->uid()); - if (! iui) { - IPAACA_WARNING("Remote InBuffer tried to spuriously write non-existent IU " << update->uid()) - return boost::shared_ptr<int>(new int(0)); - } - IU::ptr iu = boost::static_pointer_cast<IU>(iui); - iu->_revision_lock.lock(); - if ((update->revision() != 0) && (update->revision() != iu->_revision)) { - IPAACA_INFO("Remote write operation failed because request was out of date; IU " << update->uid()) - iu->_revision_lock.unlock(); - return boost::shared_ptr<int>(new int(0)); - } - if (iu->committed()) { - return boost::shared_ptr<int>(new int(0)); - } else { - } - iu->_internal_commit(update->writer_name()); - _buffer->call_iu_event_handlers(iu, true, IU_LINKSUPDATED, iu->category()); - revision_t revision = iu->revision(); - iu->_revision_lock.unlock(); - return boost::shared_ptr<int>(new int(revision)); -} -/** dlw */ -IPAACA_EXPORT boost::shared_ptr<int> CallbackIUResendRequest::call(const std::string& methodName, boost::shared_ptr<protobuf::IUResendRequest> update) -{ - IUInterface::ptr iui = _buffer->get(update->uid()); - if (! iui) { - IPAACA_WARNING("Remote InBuffer tried to spuriously write non-existent IU " << update->uid()) - return boost::shared_ptr<int>(new int(0)); - } - IU::ptr iu = boost::static_pointer_cast<IU>(iui); - if ((update->has_hidden_scope_name() == true)&&(update->hidden_scope_name().compare("") != 0)){ - //_buffer->call_iu_event_handlers(iu, true, IU_UPDATED, update->hidden_scope_name()); - revision_t revision = iu->revision(); - - iu->_publish_resend(iu, update->hidden_scope_name()); - - return boost::shared_ptr<int>(new int(revision)); - } else { - revision_t revision = 0; - return boost::shared_ptr<int>(new int(revision)); - } -} -//}}} - -// OutputBuffer//{{{ - -IPAACA_EXPORT OutputBuffer::OutputBuffer(const std::string& basename, const std::string& channel) -:Buffer(basename, "OB") -{ - //IPAACA_INFO("Entering ...") - _id_prefix = _basename + "-" + _uuid + "-IU-"; - _channel = channel; - _initialize_server(); - //IPAACA_INFO("... exiting.") -} -IPAACA_EXPORT void OutputBuffer::_initialize_server() -{ - //IPAACA_INFO("Entering ...") - //IPAACA_INFO("Calling createServer(\"" << _unique_name << "\")") - _server = getFactory().createServer( Scope( _unique_name ) ); - //IPAACA_INFO("Registering methods") - _server->registerMethod("updatePayload", Server::CallbackPtr(new CallbackIUPayloadUpdate(this))); - _server->registerMethod("updateLinks", Server::CallbackPtr(new CallbackIULinkUpdate(this))); - _server->registerMethod("commit", Server::CallbackPtr(new CallbackIUCommission(this))); - // dlw - _server->registerMethod("resendRequest", Server::CallbackPtr(new CallbackIUResendRequest(this))); - - //IPAACA_INFO("... exiting.") -} -IPAACA_EXPORT OutputBuffer::ptr OutputBuffer::create(const std::string& basename) -{ - Initializer::initialize_ipaaca_rsb_if_needed(); - return OutputBuffer::ptr(new OutputBuffer(basename)); -} -IPAACA_EXPORT 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; -} -IPAACA_EXPORT std::set<IUInterface::ptr> OutputBuffer::get_ius() -{ - std::set<IUInterface::ptr> set; - for (IUStore::iterator it=_iu_store.begin(); it!=_iu_store.end(); ++it) set.insert(it->second); - return set; -} - -IPAACA_EXPORT 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) -{ - IULinkUpdate* lup = new ipaaca::IULinkUpdate(); - Informer<ipaaca::IULinkUpdate>::DataPtr ldata(lup); - lup->uid = iu->uid(); - lup->is_delta = is_delta; - lup->revision = revision; - lup->is_delta = true; - lup->new_links = new_links; - if (is_delta) lup->links_to_remove = links_to_remove; - if (writer_name=="") lup->writer_name = _unique_name; - else lup->writer_name = writer_name; - Informer<AnyType>::Ptr informer = _get_informer(iu->category()); - informer->publish(ldata); -} - -IPAACA_EXPORT void OutputBuffer::_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) -{ - IUPayloadUpdate* pup = new ipaaca::IUPayloadUpdate(); - Informer<ipaaca::IUPayloadUpdate>::DataPtr pdata(pup); - pup->uid = iu->uid(); - pup->is_delta = is_delta; - pup->revision = revision; - pup->new_items = new_items; - if (is_delta) pup->keys_to_remove = keys_to_remove; - if (writer_name=="") pup->writer_name = _unique_name; - else pup->writer_name = writer_name; - Informer<AnyType>::Ptr informer = _get_informer(iu->category()); - informer->publish(pdata); -} - -IPAACA_EXPORT void OutputBuffer::_send_iu_commission(IUInterface* iu, revision_t revision, const std::string& writer_name) -{ - Informer<protobuf::IUCommission>::DataPtr data(new protobuf::IUCommission()); - data->set_uid(iu->uid()); - data->set_revision(revision); - if (writer_name=="") data->set_writer_name(_unique_name); - else data->set_writer_name(writer_name); - - Informer<AnyType>::Ptr informer = _get_informer(iu->category()); - informer->publish(data); -} - - - - - - -IPAACA_EXPORT void OutputBuffer::add(IU::ptr iu) -{ - if (_iu_store.count(iu->uid()) > 0) { - throw IUPublishedError(); - } - if (iu->is_published()) { - throw IUPublishedError(); - } - if (iu->access_mode() != IU_ACCESS_MESSAGE) { - // (for Message-type IUs: do not actually store them) - _iu_store[iu->uid()] = iu; - } - iu->_associate_with_buffer(this); //shared_from_this()); - _publish_iu(iu); -} - -IPAACA_EXPORT void OutputBuffer::_publish_iu(IU::ptr iu) -{ - Informer<AnyType>::Ptr informer = _get_informer(iu->_category); - Informer<ipaaca::IU>::DataPtr iu_data(iu); - informer->publish(iu_data); -} - -IPAACA_EXPORT void OutputBuffer::_publish_iu_resend(IU::ptr iu, const std::string& hidden_scope_name) -{ - Informer<AnyType>::Ptr informer = _get_informer(hidden_scope_name); - Informer<ipaaca::IU>::DataPtr iu_data(iu); - informer->publish(iu_data); -} - - - - -IPAACA_EXPORT Informer<AnyType>::Ptr OutputBuffer::_get_informer(const std::string& category) -{ - if (_informer_store.count(category) > 0) { - return _informer_store[category]; - } else { - //IPAACA_INFO("Making new informer for category " << category) - std::string scope_string = "/ipaaca/channel/" + _channel + "/category/" + category; - - Informer<AnyType>::Ptr informer = getFactory().createInformer<AnyType> ( Scope(scope_string)); - _informer_store[category] = informer; - return informer; - } -} -IPAACA_EXPORT boost::shared_ptr<IU> OutputBuffer::remove(const std::string& iu_uid) -{ - IUStore::iterator it = _iu_store.find(iu_uid); - if (it == _iu_store.end()) { - IPAACA_WARNING("Removal of IU " << iu_uid << " requested, but not present in our OutputBuffer") - //throw IUNotFoundError(); - } - IU::ptr iu = it->second; - _retract_iu(iu); - _iu_store.erase(iu_uid); - return iu; -} -IPAACA_EXPORT boost::shared_ptr<IU> OutputBuffer::remove(IU::ptr iu) -{ - return remove(iu->uid()); // to make sure it is in the store -} - -IPAACA_EXPORT void OutputBuffer::_retract_iu(IU::ptr iu) -{ - Informer<protobuf::IURetraction>::DataPtr data(new protobuf::IURetraction()); - data->set_uid(iu->uid()); - data->set_revision(iu->revision()); - Informer<AnyType>::Ptr informer = _get_informer(iu->category()); - informer->publish(data); -} - - -//}}} - -// InputBuffer//{{{ -IPAACA_EXPORT InputBuffer::InputBuffer(const BufferConfiguration& bufferconfiguration) -:Buffer(bufferconfiguration.get_basename(), "IB") -{ - _channel = bufferconfiguration.get_channel(); - - for (std::vector<std::string>::const_iterator it=bufferconfiguration.get_category_interests().begin(); it!=bufferconfiguration.get_category_interests().end(); ++it) { - _create_category_listener_if_needed(*it); - } - _create_category_listener_if_needed(_uuid); - triggerResend = false; -} -IPAACA_EXPORT InputBuffer::InputBuffer(const std::string& basename, const std::set<std::string>& category_interests) -:Buffer(basename, "IB") -{ - _channel = "default"; - - for (std::set<std::string>::const_iterator it=category_interests.begin(); it!=category_interests.end(); ++it) { - _create_category_listener_if_needed(*it); - } - _create_category_listener_if_needed(_uuid); - triggerResend = false; -} -IPAACA_EXPORT InputBuffer::InputBuffer(const std::string& basename, const std::vector<std::string>& category_interests) -:Buffer(basename, "IB") -{ - _channel = "default"; - - for (std::vector<std::string>::const_iterator it=category_interests.begin(); it!=category_interests.end(); ++it) { - _create_category_listener_if_needed(*it); - } - _create_category_listener_if_needed(_uuid); - triggerResend = false; -} -IPAACA_EXPORT InputBuffer::InputBuffer(const std::string& basename, const std::string& category_interest1) -:Buffer(basename, "IB") -{ - _channel = "default"; - - _create_category_listener_if_needed(category_interest1); -} -IPAACA_EXPORT InputBuffer::InputBuffer(const std::string& basename, const std::string& category_interest1, const std::string& category_interest2) -:Buffer(basename, "IB") -{ - _channel = "default"; - - _create_category_listener_if_needed(category_interest1); - _create_category_listener_if_needed(category_interest2); -} -IPAACA_EXPORT InputBuffer::InputBuffer(const std::string& basename, const std::string& category_interest1, const std::string& category_interest2, const std::string& category_interest3) -:Buffer(basename, "IB") -{ - _channel = "default"; - - _create_category_listener_if_needed(category_interest1); - _create_category_listener_if_needed(category_interest2); - _create_category_listener_if_needed(category_interest3); -} -IPAACA_EXPORT InputBuffer::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) -:Buffer(basename, "IB") -{ - _channel = "default"; - - _create_category_listener_if_needed(category_interest1); - _create_category_listener_if_needed(category_interest2); - _create_category_listener_if_needed(category_interest3); - _create_category_listener_if_needed(category_interest4); -} - -IPAACA_EXPORT InputBuffer::ptr InputBuffer::create(const BufferConfiguration& bufferconfiguration) -{ - Initializer::initialize_ipaaca_rsb_if_needed(); - return InputBuffer::ptr(new InputBuffer(bufferconfiguration)); -} -IPAACA_EXPORT InputBuffer::ptr InputBuffer::create(const std::string& basename, const std::set<std::string>& category_interests) -{ - Initializer::initialize_ipaaca_rsb_if_needed(); - return InputBuffer::ptr(new InputBuffer(basename, category_interests)); -} -IPAACA_EXPORT InputBuffer::ptr InputBuffer::create(const std::string& basename, const std::vector<std::string>& category_interests) -{ - Initializer::initialize_ipaaca_rsb_if_needed(); - return InputBuffer::ptr(new InputBuffer(basename, category_interests)); -} -IPAACA_EXPORT InputBuffer::ptr InputBuffer::create(const std::string& basename, const std::string& category_interest1) -{ - Initializer::initialize_ipaaca_rsb_if_needed(); - return InputBuffer::ptr(new InputBuffer(basename, category_interest1)); -} -IPAACA_EXPORT InputBuffer::ptr InputBuffer::create(const std::string& basename, const std::string& category_interest1, const std::string& category_interest2) -{ - Initializer::initialize_ipaaca_rsb_if_needed(); - return InputBuffer::ptr(new InputBuffer(basename, category_interest1, category_interest2)); -} -IPAACA_EXPORT InputBuffer::ptr InputBuffer::create(const std::string& basename, const std::string& category_interest1, const std::string& category_interest2, const std::string& category_interest3) -{ - Initializer::initialize_ipaaca_rsb_if_needed(); - return InputBuffer::ptr(new InputBuffer(basename, category_interest1, category_interest2, category_interest3)); -} -IPAACA_EXPORT 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) -{ - Initializer::initialize_ipaaca_rsb_if_needed(); - return InputBuffer::ptr(new InputBuffer(basename, category_interest1, category_interest2, category_interest3, category_interest4)); -} - - -IPAACA_EXPORT void InputBuffer::set_resend(bool resendActive) -{ - triggerResend = resendActive; -} - -IPAACA_EXPORT bool InputBuffer::get_resend() -{ - return triggerResend; -} - - -IPAACA_EXPORT 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; -} -IPAACA_EXPORT std::set<IUInterface::ptr> InputBuffer::get_ius() -{ - std::set<IUInterface::ptr> set; - for (RemotePushIUStore::iterator it=_iu_store.begin(); it!=_iu_store.end(); ++it) set.insert(it->second); // TODO genericize - return set; -} - - -IPAACA_EXPORT RemoteServerPtr InputBuffer::_get_remote_server(const std::string& unique_server_name) -{ - std::map<std::string, RemoteServerPtr>::iterator it = _remote_server_store.find(unique_server_name); - if (it!=_remote_server_store.end()) return it->second; - RemoteServerPtr remote_server = getFactory().createRemoteServer(Scope(unique_server_name)); - _remote_server_store[unique_server_name] = remote_server; - return remote_server; -} - -IPAACA_EXPORT ListenerPtr InputBuffer::_create_category_listener_if_needed(const std::string& category) -{ - IPAACA_INFO("Entering ...") - std::map<std::string, ListenerPtr>::iterator it = _listener_store.find(category); - if (it!=_listener_store.end()) { - IPAACA_INFO("... exiting.") - return it->second; - } - //IPAACA_INFO("Creating a new listener for category " << category) - std::string scope_string = "/ipaaca/channel/" + _channel + "/category/" + category; - - ListenerPtr listener = getFactory().createListener( Scope(scope_string) ); - IPAACA_INFO("Adding handler") - HandlerPtr event_handler = HandlerPtr( - new EventFunctionHandler( - boost::bind(&InputBuffer::_handle_iu_events, this, _1) - ) - ); - listener->addHandler(event_handler); - _listener_store[category] = listener; - IPAACA_INFO("... exiting.") - return listener; -} -IPAACA_EXPORT void InputBuffer::_trigger_resend_request(EventPtr event) { - if (!triggerResend) - return; - std::string type = event->getType(); - std::string uid = ""; - std::string writerName = ""; - if (type == "ipaaca::IUPayloadUpdate") { - boost::shared_ptr<IUPayloadUpdate> update = boost::static_pointer_cast<IUPayloadUpdate>(event->getData()); - uid = update->uid; - writerName = update->writer_name; - } else if (type == "ipaaca::IULinkUpdate") { - boost::shared_ptr<IULinkUpdate> update = boost::static_pointer_cast<IULinkUpdate>(event->getData()); - uid = update->uid; - writerName = update->writer_name; - } else if (type == "ipaaca::protobuf::IUCommission") { - boost::shared_ptr<protobuf::IUCommission> update = boost::static_pointer_cast<protobuf::IUCommission>(event->getData()); - uid = update->uid(); - writerName = update->writer_name(); - } else { - std::cout << "trigger ??? else" << std::endl; - } - - if (!writerName.empty()) { - RemoteServerPtr server = _get_remote_server(writerName); - if (!uid.empty()) { - boost::shared_ptr<protobuf::IUResendRequest> update = boost::shared_ptr<protobuf::IUResendRequest>(new protobuf::IUResendRequest()); - update->set_uid(uid); - update->set_hidden_scope_name(_uuid); - boost::shared_ptr<int> result = server->call<int>("resendRequest", update, IPAACA_REMOTE_SERVER_TIMEOUT); - if (*result == 0) { - throw IUResendRequestFailedError(); - } else { - std::cout << "revision " << *result << std::endl; - } - } - } -} -IPAACA_EXPORT void InputBuffer::_handle_iu_events(EventPtr event) -{ - std::cout << "handle iu events" << std::endl; - std::string type = event->getType(); - if (type == "ipaaca::RemotePushIU") { - boost::shared_ptr<RemotePushIU> iu = boost::static_pointer_cast<RemotePushIU>(event->getData()); - if (_iu_store.count(iu->category()) > 0) { - // already got the IU... ignore - } else { - _iu_store[iu->uid()] = iu; - iu->_set_buffer(this); - call_iu_event_handlers(iu, false, IU_ADDED, iu->category() ); - } - //IPAACA_INFO( "New RemotePushIU state: " << (*iu) ) - } else if (type == "ipaaca::RemoteMessage") { - boost::shared_ptr<RemoteMessage> iu = boost::static_pointer_cast<RemoteMessage>(event->getData()); - //_iu_store[iu->uid()] = iu; - //iu->_set_buffer(this); - //std::cout << "REFCNT after cast, before calling handlers: " << iu.use_count() << std::endl; - call_iu_event_handlers(iu, false, IU_MESSAGE, iu->category() ); - //_iu_store.erase(iu->uid()); - } else { - RemotePushIUStore::iterator it; - if (type == "ipaaca::IUPayloadUpdate") { - boost::shared_ptr<IUPayloadUpdate> update = boost::static_pointer_cast<IUPayloadUpdate>(event->getData()); - //IPAACA_INFO("** writer name: " << update->writer_name) - std::cout << "writer name " << update->writer_name << std::endl; - if (update->writer_name == _unique_name) { - return; - } - it = _iu_store.find(update->uid); - if (it == _iu_store.end()) { - _trigger_resend_request(event); - IPAACA_INFO("Using UPDATED message for an IU that we did not fully receive before") - return; - } - - it->second->_apply_update(update); - call_iu_event_handlers(it->second, false, IU_UPDATED, it->second->category() ); - - } else if (type == "ipaaca::IULinkUpdate") { - boost::shared_ptr<IULinkUpdate> update = boost::static_pointer_cast<IULinkUpdate>(event->getData()); - if (update->writer_name == _unique_name) { - return; - } - it = _iu_store.find(update->uid); - if (it == _iu_store.end()) { - _trigger_resend_request(event); - IPAACA_INFO("Ignoring LINKSUPDATED message for an IU that we did not fully receive before") - return; - } - - it->second->_apply_link_update(update); - call_iu_event_handlers(it->second, false, IU_LINKSUPDATED, it->second->category() ); - - } else if (type == "ipaaca::protobuf::IUCommission") { - boost::shared_ptr<protobuf::IUCommission> update = boost::static_pointer_cast<protobuf::IUCommission>(event->getData()); - if (update->writer_name() == _unique_name) { - return; - } - it = _iu_store.find(update->uid()); - if (it == _iu_store.end()) { - _trigger_resend_request(event); - IPAACA_INFO("Ignoring COMMITTED message for an IU that we did not fully receive before") - return; - } - // - it->second->_apply_commission(); - it->second->_revision = update->revision(); - call_iu_event_handlers(it->second, false, IU_COMMITTED, it->second->category() ); - // - // - } else if (type == "ipaaca::protobuf::IURetraction") { - boost::shared_ptr<protobuf::IURetraction> update = boost::static_pointer_cast<protobuf::IURetraction>(event->getData()); - it = _iu_store.find(update->uid()); - if (it == _iu_store.end()) { - _trigger_resend_request(event); - IPAACA_INFO("Ignoring RETRACTED message for an IU that we did not fully receive before") - return; - } - // - it->second->_revision = update->revision(); - it->second->_apply_retraction(); - // remove from InputBuffer FIXME: this is a crossover between retracted and deleted behavior - _iu_store.erase(it->first); - // and call the handler. IU reference is still valid for this call, although removed from buffer. - call_iu_event_handlers(it->second, false, IU_COMMITTED, it->second->category() ); - // - } else { - std::cout << "(Unhandled Event type " << type << " !)" << std::endl; - return; - } - //IPAACA_INFO( "New RemotePushIU state: " << *(it->second) ) - } -} -//}}} - - - -// 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) -{ - IU::ptr iu = IU::ptr(new IU(category, access_mode, read_only, payload_type)); /* params */ //)); - iu->_payload.initialize(iu); - return iu; -} - -IPAACA_EXPORT IU::IU(const std::string& category, IUAccessMode access_mode, bool read_only, const std::string& payload_type) -{ - _revision = 1; - _uid = ipaaca::generate_uuid_string(); - _category = category; - _payload_type = payload_type; - // payload initialization deferred to IU::create(), above - _read_only = read_only; - _access_mode = access_mode; - _committed = false; -} - -IPAACA_EXPORT void IU::_modify_links(bool is_delta, const LinkMap& new_links, const LinkMap& links_to_remove, const std::string& writer_name) -{ - _revision_lock.lock(); - if (_committed) { - _revision_lock.unlock(); - throw IUCommittedError(); - } - _increase_revision_number(); - if (is_published()) { - _buffer->_send_iu_link_update(this, is_delta, _revision, new_links, links_to_remove, writer_name); - } - _revision_lock.unlock(); -} - - -IPAACA_EXPORT void IU::_publish_resend(IU::ptr iu, const std::string& hidden_scope_name) -{ - //_revision_lock.lock(); - //if (_committed) { - // _revision_lock.unlock(); - // throw IUCommittedError(); - //} - //_increase_revision_number(); - //if (is_published()) { - //IUInterface* iu, bool is_delta, revision_t revision, const LinkMap& new_links, const LinkMap& links_to_remove, const std::string& writer_name - _buffer->_publish_iu_resend(iu, hidden_scope_name); - //} - //_revision_lock.unlock(); -} - - - - - -IPAACA_EXPORT void IU::_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) -{ - _revision_lock.lock(); - if (_committed) { - _revision_lock.unlock(); - throw IUCommittedError(); - } - _increase_revision_number(); - if (is_published()) { - //std::cout << "Sending a payload update with " << new_items.size() << " entries to merge." << std::endl; - _buffer->_send_iu_payload_update(this, is_delta, _revision, new_items, keys_to_remove, writer_name); - } - _revision_lock.unlock(); -} - -IPAACA_EXPORT void IU::commit() -{ - _internal_commit(); -} - -IPAACA_EXPORT void IU::_internal_commit(const std::string& writer_name) -{ - _revision_lock.lock(); - if (_committed) { - _revision_lock.unlock(); - throw IUCommittedError(); - } - _increase_revision_number(); - _committed = true; - if (is_published()) { - _buffer->_send_iu_commission(this, _revision, writer_name); - } - _revision_lock.unlock(); -} -//}}} -// Message//{{{ -Message::ptr Message::create(const std::string& category, IUAccessMode access_mode, bool read_only, const std::string& payload_type) -{ - Message::ptr iu = Message::ptr(new Message(category, access_mode, read_only, payload_type)); /* params */ //)); - iu->_payload.initialize(iu); - return iu; -} - -Message::Message(const std::string& category, IUAccessMode access_mode, bool read_only, const std::string& payload_type) -: IU(category, access_mode, read_only, payload_type) -{ -} - -void Message::_modify_links(bool is_delta, const LinkMap& new_links, const LinkMap& links_to_remove, const std::string& writer_name) -{ - if (is_published()) { - IPAACA_INFO("Info: modifying a Message after sending has no global effects") - } -} -void Message::_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) -{ - if (is_published()) { - IPAACA_INFO("Info: modifying a Message after sending has no global effects") - } -} - -void Message::_internal_commit(const std::string& writer_name) -{ - if (is_published()) { - IPAACA_INFO("Info: committing to a Message after sending has no global effects") - } - -} -//}}} - -// RemotePushIU//{{{ - -IPAACA_EXPORT RemotePushIU::ptr RemotePushIU::create() -{ - RemotePushIU::ptr iu = RemotePushIU::ptr(new RemotePushIU(/* params */)); - iu->_payload.initialize(iu); - return iu; -} -IPAACA_EXPORT RemotePushIU::RemotePushIU() -{ - // nothing -} -IPAACA_EXPORT void RemotePushIU::_modify_links(bool is_delta, const LinkMap& new_links, const LinkMap& links_to_remove, const std::string& writer_name) -{ - if (_committed) { - throw IUCommittedError(); - } - if (_read_only) { - throw IUReadOnlyError(); - } - RemoteServerPtr server = boost::static_pointer_cast<InputBuffer>(_buffer)->_get_remote_server(_owner_name); - IULinkUpdate::ptr update = IULinkUpdate::ptr(new IULinkUpdate()); - update->uid = _uid; - update->revision = _revision; - update->is_delta = is_delta; - update->writer_name = _buffer->unique_name(); - update->new_links = new_links; - update->links_to_remove = links_to_remove; - boost::shared_ptr<int> result = server->call<int>("updateLinks", update, IPAACA_REMOTE_SERVER_TIMEOUT); // TODO - if (*result == 0) { - throw IUUpdateFailedError(); - } else { - _revision = *result; - } -} -IPAACA_EXPORT void RemotePushIU::_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) -{ - //std::cout << "-- Sending a modify_payload with " << new_items.size() << " keys to merge." << std::endl; - if (_committed) { - throw IUCommittedError(); - } - if (_read_only) { - throw IUReadOnlyError(); - } - RemoteServerPtr server = boost::static_pointer_cast<InputBuffer>(_buffer)->_get_remote_server(_owner_name); - IUPayloadUpdate::ptr update = IUPayloadUpdate::ptr(new IUPayloadUpdate()); - update->uid = _uid; - update->revision = _revision; - update->is_delta = is_delta; - update->writer_name = _buffer->unique_name(); - update->new_items = new_items; - update->keys_to_remove = keys_to_remove; - boost::shared_ptr<int> result = server->call<int>("updatePayload", update, IPAACA_REMOTE_SERVER_TIMEOUT); // TODO - if (*result == 0) { - throw IUUpdateFailedError(); - } else { - _revision = *result; - } -} - -IPAACA_EXPORT void RemotePushIU::commit() -{ - if (_read_only) { - throw IUReadOnlyError(); - } - if (_committed) { - // Following python version: ignoring multiple commit - return; - } - RemoteServerPtr server = boost::static_pointer_cast<InputBuffer>(_buffer)->_get_remote_server(_owner_name); - boost::shared_ptr<protobuf::IUCommission> update = boost::shared_ptr<protobuf::IUCommission>(new protobuf::IUCommission()); - update->set_uid(_uid); - update->set_revision(_revision); - update->set_writer_name(_buffer->unique_name()); - boost::shared_ptr<int> result = server->call<int>("commit", update, IPAACA_REMOTE_SERVER_TIMEOUT); // TODO - if (*result == 0) { - throw IUUpdateFailedError(); - } else { - _revision = *result; - } -} - -IPAACA_EXPORT void RemotePushIU::_apply_link_update(IULinkUpdate::ptr update) -{ - _revision = update->revision; - if (update->is_delta) { - _add_and_remove_links(update->new_links, update->links_to_remove); - } else { - _replace_links(update->new_links); - } -} -IPAACA_EXPORT void RemotePushIU::_apply_update(IUPayloadUpdate::ptr update) -{ - _revision = update->revision; - if (update->is_delta) { - for (std::vector<std::string>::const_iterator it=update->keys_to_remove.begin(); it!=update->keys_to_remove.end(); ++it) { - _payload._remotely_enforced_delitem(*it); - } - for (std::map<std::string, std::string>::const_iterator it=update->new_items.begin(); it!=update->new_items.end(); ++it) { - _payload._remotely_enforced_setitem(it->first, it->second); - } - } else { - _payload._remotely_enforced_wipe(); - for (std::map<std::string, std::string>::const_iterator it=update->new_items.begin(); it!=update->new_items.end(); ++it) { - _payload._remotely_enforced_setitem(it->first, it->second); - } - } -} -IPAACA_EXPORT void RemotePushIU::_apply_commission() -{ - _committed = true; -} -IPAACA_EXPORT void RemotePushIU::_apply_retraction() -{ - _retracted = true; -} -//}}} - -// RemoteMessage//{{{ - -IPAACA_EXPORT RemoteMessage::ptr RemoteMessage::create() -{ - RemoteMessage::ptr iu = RemoteMessage::ptr(new RemoteMessage(/* params */)); - iu->_payload.initialize(iu); - return iu; -} -IPAACA_EXPORT RemoteMessage::RemoteMessage() -{ - // nothing -} -IPAACA_EXPORT void RemoteMessage::_modify_links(bool is_delta, const LinkMap& new_links, const LinkMap& links_to_remove, const std::string& writer_name) -{ - IPAACA_INFO("Info: modifying a RemoteMessage only has local effects") -} -IPAACA_EXPORT void RemoteMessage::_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) -{ - IPAACA_INFO("Info: modifying a RemoteMessage only has local effects") -} -IPAACA_EXPORT void RemoteMessage::commit() -{ - IPAACA_INFO("Info: committing to a RemoteMessage only has local effects") -} - -IPAACA_EXPORT void RemoteMessage::_apply_link_update(IULinkUpdate::ptr update) -{ - IPAACA_WARNING("Warning: should never be called: RemoteMessage::_apply_link_update") - _revision = update->revision; - if (update->is_delta) { - _add_and_remove_links(update->new_links, update->links_to_remove); - } else { - _replace_links(update->new_links); - } -} -IPAACA_EXPORT void RemoteMessage::_apply_update(IUPayloadUpdate::ptr update) -{ - IPAACA_WARNING("Warning: should never be called: RemoteMessage::_apply_update") - _revision = update->revision; - if (update->is_delta) { - for (std::vector<std::string>::const_iterator it=update->keys_to_remove.begin(); it!=update->keys_to_remove.end(); ++it) { - _payload._remotely_enforced_delitem(*it); - } - for (std::map<std::string, std::string>::const_iterator it=update->new_items.begin(); it!=update->new_items.end(); ++it) { - _payload._remotely_enforced_setitem(it->first, it->second); - } - } else { - _payload._remotely_enforced_wipe(); - for (std::map<std::string, std::string>::const_iterator it=update->new_items.begin(); it!=update->new_items.end(); ++it) { - _payload._remotely_enforced_setitem(it->first, it->second); - } - } -} -IPAACA_EXPORT void RemoteMessage::_apply_commission() -{ - IPAACA_WARNING("Warning: should never be called: RemoteMessage::_apply_commission") - _committed = true; -} -IPAACA_EXPORT void RemoteMessage::_apply_retraction() -{ - IPAACA_WARNING("Warning: should never be called: RemoteMessage::_apply_retraction") - _retracted = true; -} - -//}}} - - - -// PayloadEntryProxy//{{{ - -IPAACA_EXPORT PayloadEntryProxy::PayloadEntryProxy(Payload* payload, const std::string& key) -: _payload(payload), _key(key) -{ -} -IPAACA_EXPORT PayloadEntryProxy& PayloadEntryProxy::operator=(const std::string& value) -{ - //std::cout << "operator=(string)" << std::endl; - _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); - return *this; -} -IPAACA_EXPORT PayloadEntryProxy& PayloadEntryProxy::operator=(double value) -{ - //std::cout << "operator=(double)" << std::endl; - _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)); - return *this; -} - -IPAACA_EXPORT inline PayloadEntryProxy::operator std::string() -{ - return PayloadEntryProxy::get<std::string>(); } -IPAACA_EXPORT inline PayloadEntryProxy::operator long() -{ - return PayloadEntryProxy::get<long>(); -} -IPAACA_EXPORT inline PayloadEntryProxy::operator double() -{ - return PayloadEntryProxy::get<double>(); -} -IPAACA_EXPORT inline PayloadEntryProxy::operator bool() -{ - return PayloadEntryProxy::get<bool>(); -} -IPAACA_EXPORT inline std::string PayloadEntryProxy::to_str() -{ - return PayloadEntryProxy::get<std::string>(); -} -IPAACA_EXPORT inline long PayloadEntryProxy::to_long() -{ - return PayloadEntryProxy::get<long>(); -} -IPAACA_EXPORT inline double PayloadEntryProxy::to_float() -{ - return PayloadEntryProxy::get<double>(); -} -IPAACA_EXPORT inline bool PayloadEntryProxy::to_bool() -{ - return PayloadEntryProxy::get<bool>(); -} - - -// -// new stuff for protocol v2 -// -IPAACA_HEADER_EXPORT template<> std::string PayloadEntryProxy::get<std::string>() -{ - return _payload->get(_key); -} -IPAACA_HEADER_EXPORT template<> long PayloadEntryProxy::get<long>() -{ - return atof(operator std::string().c_str()); -} -IPAACA_HEADER_EXPORT template<> double PayloadEntryProxy::get<double>() -{ - return atol(operator std::string().c_str()); -} -IPAACA_HEADER_EXPORT template<> bool PayloadEntryProxy::get<bool>() -{ - std::string s = operator std::string(); - return ((s=="1")||(s=="true")||(s=="True")); -} -// complex types -IPAACA_HEADER_EXPORT template<> std::list<std::string> PayloadEntryProxy::get<std::list<std::string> >() -{ - std::list<std::string> l; - l.push_back(PayloadEntryProxy::get<std::string>()); - return l; -} -IPAACA_HEADER_EXPORT template<> std::vector<std::string> PayloadEntryProxy::get<std::vector<std::string> >() -{ - std::vector<std::string> v; - v.push_back(PayloadEntryProxy::get<std::string>()); - return v; -} -IPAACA_HEADER_EXPORT template<> std::map<std::string, std::string> PayloadEntryProxy::get<std::map<std::string, std::string> >() -{ - std::map<std::string, std::string> m; - m["__automatic__"] = PayloadEntryProxy::get<std::string>(); - return m; -} -//}}} - -// Payload//{{{ - -IPAACA_EXPORT void Payload::initialize(boost::shared_ptr<IUInterface> iu) -{ - _iu = boost::weak_ptr<IUInterface>(iu); -} - -IPAACA_EXPORT PayloadEntryProxy Payload::operator[](const std::string& key) -{ - //boost::shared_ptr<PayloadEntryProxy> p(new PayloadEntryProxy(this, key)); - return PayloadEntryProxy(this, key); -} -IPAACA_EXPORT Payload::operator std::map<std::string, std::string>() -{ - return _store; -} - -IPAACA_EXPORT inline void Payload::_internal_set(const std::string& k, const std::string& v, const std::string& writer_name) { - std::map<std::string, std::string> _new; - std::vector<std::string> _remove; - _new[k]=v; - _iu.lock()->_modify_payload(true, _new, _remove, writer_name ); - _store[k] = v; -} -IPAACA_EXPORT inline void Payload::_internal_remove(const std::string& k, const std::string& writer_name) { - std::map<std::string, std::string> _new; - std::vector<std::string> _remove; - _remove.push_back(k); - _iu.lock()->_modify_payload(true, _new, _remove, writer_name ); - _store.erase(k); -} -IPAACA_EXPORT void Payload::_internal_replace_all(const std::map<std::string, std::string>& 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; -} -IPAACA_EXPORT void Payload::_internal_merge(const std::map<std::string, std::string>& contents_to_merge, const std::string& writer_name) -{ - std::vector<std::string> _remove; - _iu.lock()->_modify_payload(true, contents_to_merge, _remove, writer_name ); - _store.insert(contents_to_merge.begin(), contents_to_merge.end()); - //for (std::map<std::string, std::string>::iterator it = contents_to_merge.begin(); it!=contents_to_merge.end(); i++) { - // _store[it->first] = it->second; - //} -} -IPAACA_EXPORT inline std::string Payload::get(const std::string& k) { - if (_store.count(k)>0) return _store[k]; - else return IPAACA_PAYLOAD_DEFAULT_STRING_VALUE; -} -IPAACA_EXPORT void Payload::_remotely_enforced_wipe() -{ - _store.clear(); -} -IPAACA_EXPORT void Payload::_remotely_enforced_delitem(const std::string& k) -{ - _store.erase(k); -} -IPAACA_EXPORT void Payload::_remotely_enforced_setitem(const std::string& k, const std::string& v) -{ - _store[k] = v; -} - -//}}} - -// IUConverter//{{{ - -IPAACA_EXPORT IUConverter::IUConverter() -: Converter<std::string> (IPAACA_SYSTEM_DEPENDENT_CLASS_NAME("ipaaca::IU"), "ipaaca-iu", true) -{ -} - -IPAACA_EXPORT std::string IUConverter::serialize(const AnnotatedData& data, std::string& wire) -{ - //std::cout << "serialize" << std::endl; - // Ensure that DATA actually holds a datum of the data-type we expect. - assert(data.first == getDataType()); // "ipaaca::IU" - // NOTE: a dynamic_pointer_cast cannot be used from void* - boost::shared_ptr<const IU> obj = boost::static_pointer_cast<const IU> (data.second); - boost::shared_ptr<protobuf::IU> pbo(new protobuf::IU()); - // transfer obj data to pbo - pbo->set_uid(obj->uid()); - pbo->set_revision(obj->revision()); - pbo->set_category(obj->category()); - pbo->set_payload_type(obj->payload_type()); - pbo->set_owner_name(obj->owner_name()); - pbo->set_committed(obj->committed()); - ipaaca::protobuf::IU_AccessMode a_m; - switch(obj->access_mode()) { - case IU_ACCESS_PUSH: - a_m = ipaaca::protobuf::IU_AccessMode_PUSH; - break; - case IU_ACCESS_REMOTE: - a_m = ipaaca::protobuf::IU_AccessMode_REMOTE; - break; - case IU_ACCESS_MESSAGE: - a_m = ipaaca::protobuf::IU_AccessMode_MESSAGE; - break; - } - pbo->set_access_mode(a_m); - pbo->set_read_only(obj->read_only()); - for (std::map<std::string, std::string>::const_iterator it=obj->_payload._store.begin(); it!=obj->_payload._store.end(); ++it) { - protobuf::PayloadItem* item = pbo->add_payload(); - item->set_key(it->first); - item->set_value(it->second); - item->set_type("str"); // FIXME other types than str (later) - } - for (LinkMap::const_iterator it=obj->_links._links.begin(); it!=obj->_links._links.end(); ++it) { - protobuf::LinkSet* links = pbo->add_links(); - links->set_type(it->first); - for (std::set<std::string>::const_iterator it2=it->second.begin(); it2!=it->second.end(); ++it2) { - links->add_targets(*it2); - } - } - pbo->SerializeToString(&wire); - switch(obj->access_mode()) { - case IU_ACCESS_PUSH: - //std::cout << "Requesting to send as ipaaca-iu" << std::endl; - return "ipaaca-iu"; - case IU_ACCESS_MESSAGE: - //std::cout << "Requesting to send as ipaaca-messageiu" << std::endl; - return "ipaaca-messageiu"; - default: - //std::cout << "Requesting to send as default" << std::endl; - return getWireSchema(); - } - -} - -IPAACA_EXPORT AnnotatedData IUConverter::deserialize(const std::string& wireSchema, const std::string& wire) { - //std::cout << "deserialize" << std::endl; - assert(wireSchema == getWireSchema()); // "ipaaca-iu" - boost::shared_ptr<protobuf::IU> pbo(new protobuf::IU()); - pbo->ParseFromString(wire); - IUAccessMode mode = static_cast<IUAccessMode>(pbo->access_mode()); - switch(mode) { - case IU_ACCESS_PUSH: - { - // Create a "remote push IU" - boost::shared_ptr<RemotePushIU> obj = RemotePushIU::create(); - // transfer pbo data to obj - obj->_uid = pbo->uid(); - obj->_revision = pbo->revision(); - obj->_category = pbo->category(); - obj->_payload_type = pbo->payload_type(); - obj->_owner_name = pbo->owner_name(); - obj->_committed = pbo->committed(); - obj->_read_only = pbo->read_only(); - obj->_access_mode = IU_ACCESS_PUSH; - for (int i=0; i<pbo->payload_size(); i++) { - const protobuf::PayloadItem& it = pbo->payload(i); - obj->_payload._store[it.key()] = it.value(); - } - for (int i=0; i<pbo->links_size(); i++) { - const protobuf::LinkSet& pls = pbo->links(i); - LinkSet& ls = obj->_links._links[pls.type()]; - for (int j=0; j<pls.targets_size(); j++) { - ls.insert(pls.targets(j)); - } - } - //return std::make_pair(getDataType(), obj); - return std::make_pair("ipaaca::RemotePushIU", obj); - break; - } - case IU_ACCESS_MESSAGE: - { - // Create a "Message-type IU" - boost::shared_ptr<RemoteMessage> obj = RemoteMessage::create(); - //std::cout << "REFCNT after create: " << obj.use_count() << std::endl; - // transfer pbo data to obj - obj->_uid = pbo->uid(); - obj->_revision = pbo->revision(); - obj->_category = pbo->category(); - obj->_payload_type = pbo->payload_type(); - obj->_owner_name = pbo->owner_name(); - obj->_committed = pbo->committed(); - obj->_read_only = pbo->read_only(); - obj->_access_mode = IU_ACCESS_MESSAGE; - for (int i=0; i<pbo->payload_size(); i++) { - const protobuf::PayloadItem& it = pbo->payload(i); - obj->_payload._store[it.key()] = it.value(); - } - for (int i=0; i<pbo->links_size(); i++) { - const protobuf::LinkSet& pls = pbo->links(i); - LinkSet& ls = obj->_links._links[pls.type()]; - for (int j=0; j<pls.targets_size(); j++) { - ls.insert(pls.targets(j)); - } - } - //return std::make_pair(getDataType(), obj); - return std::make_pair("ipaaca::RemoteMessage", obj); - break; - } - default: - // other cases not handled yet! ( TODO ) - throw NotImplementedError(); - } -} - -//}}} - -// MessageConverter//{{{ - -IPAACA_EXPORT MessageConverter::MessageConverter() -: Converter<std::string> (IPAACA_SYSTEM_DEPENDENT_CLASS_NAME("ipaaca::Message"), "ipaaca-messageiu", true) -{ -} - -IPAACA_EXPORT std::string MessageConverter::serialize(const AnnotatedData& data, std::string& wire) -{ - // Ensure that DATA actually holds a datum of the data-type we expect. - assert(data.first == getDataType()); // "ipaaca::Message" - // NOTE: a dynamic_pointer_cast cannot be used from void* - boost::shared_ptr<const Message> obj = boost::static_pointer_cast<const Message> (data.second); - boost::shared_ptr<protobuf::IU> pbo(new protobuf::IU()); - // transfer obj data to pbo - pbo->set_uid(obj->uid()); - pbo->set_revision(obj->revision()); - pbo->set_category(obj->category()); - pbo->set_payload_type(obj->payload_type()); - pbo->set_owner_name(obj->owner_name()); - pbo->set_committed(obj->committed()); - ipaaca::protobuf::IU_AccessMode a_m; - switch(obj->access_mode()) { - case IU_ACCESS_PUSH: - a_m = ipaaca::protobuf::IU_AccessMode_PUSH; - break; - case IU_ACCESS_REMOTE: - a_m = ipaaca::protobuf::IU_AccessMode_REMOTE; - break; - case IU_ACCESS_MESSAGE: - a_m = ipaaca::protobuf::IU_AccessMode_MESSAGE; - break; - } - pbo->set_access_mode(a_m); - pbo->set_read_only(obj->read_only()); - for (std::map<std::string, std::string>::const_iterator it=obj->_payload._store.begin(); it!=obj->_payload._store.end(); ++it) { - protobuf::PayloadItem* item = pbo->add_payload(); - item->set_key(it->first); - item->set_value(it->second); - item->set_type("str"); // FIXME other types than str (later) - } - for (LinkMap::const_iterator it=obj->_links._links.begin(); it!=obj->_links._links.end(); ++it) { - protobuf::LinkSet* links = pbo->add_links(); - links->set_type(it->first); - for (std::set<std::string>::const_iterator it2=it->second.begin(); it2!=it->second.end(); ++it2) { - links->add_targets(*it2); - } - } - pbo->SerializeToString(&wire); - switch(obj->access_mode()) { - case IU_ACCESS_PUSH: - return "ipaaca-iu"; - case IU_ACCESS_MESSAGE: - return "ipaaca-messageiu"; - default: - //std::cout << "Requesting to send as default" << std::endl; - return getWireSchema(); - } - -} - -IPAACA_EXPORT AnnotatedData MessageConverter::deserialize(const std::string& wireSchema, const std::string& wire) { - assert(wireSchema == getWireSchema()); // "ipaaca-iu" - boost::shared_ptr<protobuf::IU> pbo(new protobuf::IU()); - pbo->ParseFromString(wire); - IUAccessMode mode = static_cast<IUAccessMode>(pbo->access_mode()); - switch(mode) { - case IU_ACCESS_PUSH: - { - // Create a "remote push IU" - boost::shared_ptr<RemotePushIU> obj = RemotePushIU::create(); - // transfer pbo data to obj - obj->_uid = pbo->uid(); - obj->_revision = pbo->revision(); - obj->_category = pbo->category(); - obj->_payload_type = pbo->payload_type(); - obj->_owner_name = pbo->owner_name(); - obj->_committed = pbo->committed(); - obj->_read_only = pbo->read_only(); - obj->_access_mode = IU_ACCESS_PUSH; - for (int i=0; i<pbo->payload_size(); i++) { - const protobuf::PayloadItem& it = pbo->payload(i); - obj->_payload._store[it.key()] = it.value(); - } - for (int i=0; i<pbo->links_size(); i++) { - const protobuf::LinkSet& pls = pbo->links(i); - LinkSet& ls = obj->_links._links[pls.type()]; - for (int j=0; j<pls.targets_size(); j++) { - ls.insert(pls.targets(j)); - } - } - //return std::make_pair(getDataType(), obj); - return std::make_pair("ipaaca::RemotePushIU", obj); - break; - } - case IU_ACCESS_MESSAGE: - { - // Create a "Message-type IU" - boost::shared_ptr<RemoteMessage> obj = RemoteMessage::create(); - // transfer pbo data to obj - obj->_uid = pbo->uid(); - obj->_revision = pbo->revision(); - obj->_category = pbo->category(); - obj->_payload_type = pbo->payload_type(); - obj->_owner_name = pbo->owner_name(); - obj->_committed = pbo->committed(); - obj->_read_only = pbo->read_only(); - obj->_access_mode = IU_ACCESS_MESSAGE; - for (int i=0; i<pbo->payload_size(); i++) { - const protobuf::PayloadItem& it = pbo->payload(i); - obj->_payload._store[it.key()] = it.value(); - } - for (int i=0; i<pbo->links_size(); i++) { - const protobuf::LinkSet& pls = pbo->links(i); - LinkSet& ls = obj->_links._links[pls.type()]; - for (int j=0; j<pls.targets_size(); j++) { - ls.insert(pls.targets(j)); - } - } - //return std::make_pair(getDataType(), obj); - return std::make_pair("ipaaca::RemoteMessage", obj); - break; - } - default: - // other cases not handled yet! ( TODO ) - throw NotImplementedError(); - } -} - -//}}} - -// IUPayloadUpdateConverter//{{{ - -IPAACA_EXPORT IUPayloadUpdateConverter::IUPayloadUpdateConverter() -: Converter<std::string> (IPAACA_SYSTEM_DEPENDENT_CLASS_NAME("ipaaca::IUPayloadUpdate"), "ipaaca-iu-payload-update", true) -{ -} - -IPAACA_EXPORT std::string IUPayloadUpdateConverter::serialize(const AnnotatedData& data, std::string& wire) -{ - assert(data.first == getDataType()); // "ipaaca::IUPayloadUpdate" - boost::shared_ptr<const IUPayloadUpdate> obj = boost::static_pointer_cast<const IUPayloadUpdate> (data.second); - boost::shared_ptr<protobuf::IUPayloadUpdate> pbo(new protobuf::IUPayloadUpdate()); - // transfer obj data to pbo - pbo->set_uid(obj->uid); - pbo->set_revision(obj->revision); - pbo->set_writer_name(obj->writer_name); - pbo->set_is_delta(obj->is_delta); - for (std::map<std::string, std::string>::const_iterator it=obj->new_items.begin(); it!=obj->new_items.end(); ++it) { - protobuf::PayloadItem* item = pbo->add_new_items(); - item->set_key(it->first); - item->set_value(it->second); - item->set_type("str"); // FIXME other types than str (later) - } - for (std::vector<std::string>::const_iterator it=obj->keys_to_remove.begin(); it!=obj->keys_to_remove.end(); ++it) { - pbo->add_keys_to_remove(*it); - } - pbo->SerializeToString(&wire); - return getWireSchema(); - -} - -AnnotatedData IUPayloadUpdateConverter::deserialize(const std::string& wireSchema, const std::string& wire) { - assert(wireSchema == getWireSchema()); // "ipaaca-iu-payload-update" - boost::shared_ptr<protobuf::IUPayloadUpdate> pbo(new protobuf::IUPayloadUpdate()); - pbo->ParseFromString(wire); - boost::shared_ptr<IUPayloadUpdate> obj(new IUPayloadUpdate()); - // transfer pbo data to obj - obj->uid = pbo->uid(); - obj->revision = pbo->revision(); - obj->writer_name = pbo->writer_name(); - obj->is_delta = pbo->is_delta(); - for (int i=0; i<pbo->new_items_size(); i++) { - const protobuf::PayloadItem& it = pbo->new_items(i); - obj->new_items[it.key()] = it.value(); - } - for (int i=0; i<pbo->keys_to_remove_size(); i++) { - obj->keys_to_remove.push_back(pbo->keys_to_remove(i)); - } - return std::make_pair(getDataType(), obj); -} - -//}}} - -// IULinkUpdateConverter//{{{ - -IPAACA_EXPORT IULinkUpdateConverter::IULinkUpdateConverter() -: Converter<std::string> (IPAACA_SYSTEM_DEPENDENT_CLASS_NAME("ipaaca::IULinkUpdate"), "ipaaca-iu-link-update", true) -{ -} - -IPAACA_EXPORT std::string IULinkUpdateConverter::serialize(const AnnotatedData& data, std::string& wire) -{ - assert(data.first == getDataType()); // "ipaaca::IULinkUpdate" - boost::shared_ptr<const IULinkUpdate> obj = boost::static_pointer_cast<const IULinkUpdate> (data.second); - boost::shared_ptr<protobuf::IULinkUpdate> pbo(new protobuf::IULinkUpdate()); - // transfer obj data to pbo - pbo->set_uid(obj->uid); - pbo->set_revision(obj->revision); - pbo->set_writer_name(obj->writer_name); - pbo->set_is_delta(obj->is_delta); - for (std::map<std::string, std::set<std::string> >::const_iterator it=obj->new_links.begin(); it!=obj->new_links.end(); ++it) { - protobuf::LinkSet* links = pbo->add_new_links(); - links->set_type(it->first); - for (std::set<std::string>::const_iterator it2=it->second.begin(); it2!=it->second.end(); ++it2) { - links->add_targets(*it2); - } - } - for (std::map<std::string, std::set<std::string> >::const_iterator it=obj->links_to_remove.begin(); it!=obj->links_to_remove.end(); ++it) { - protobuf::LinkSet* links = pbo->add_links_to_remove(); - links->set_type(it->first); - for (std::set<std::string>::const_iterator it2=it->second.begin(); it2!=it->second.end(); ++it2) { - links->add_targets(*it2); - } - } - pbo->SerializeToString(&wire); - return getWireSchema(); - -} - -AnnotatedData IULinkUpdateConverter::deserialize(const std::string& wireSchema, const std::string& wire) { - assert(wireSchema == getWireSchema()); // "ipaaca-iu-link-update" - boost::shared_ptr<protobuf::IULinkUpdate> pbo(new protobuf::IULinkUpdate()); - pbo->ParseFromString(wire); - boost::shared_ptr<IULinkUpdate> obj(new IULinkUpdate()); - // transfer pbo data to obj - obj->uid = pbo->uid(); - obj->revision = pbo->revision(); - obj->writer_name = pbo->writer_name(); - obj->is_delta = pbo->is_delta(); - for (int i=0; i<pbo->new_links_size(); ++i) { - const protobuf::LinkSet& it = pbo->new_links(i); - for (int j=0; j<it.targets_size(); ++j) { - obj->new_links[it.type()].insert(it.targets(j)); // = vec; - } - } - for (int i=0; i<pbo->links_to_remove_size(); ++i) { - const protobuf::LinkSet& it = pbo->links_to_remove(i); - for (int j=0; j<it.targets_size(); ++j) { - obj->links_to_remove[it.type()].insert(it.targets(j)); - } - } - return std::make_pair(getDataType(), obj); -} - -//}}} - -// IntConverter//{{{ - -IPAACA_EXPORT IntConverter::IntConverter() -: Converter<std::string> ("int", "int32", true) -{ -} - -IPAACA_EXPORT std::string IntConverter::serialize(const AnnotatedData& data, std::string& wire) -{ - // Ensure that DATA actually holds a datum of the data-type we expect. - assert(data.first == getDataType()); // "int" - // NOTE: a dynamic_pointer_cast cannot be used from void* - boost::shared_ptr<const int> obj = boost::static_pointer_cast<const int> (data.second); - boost::shared_ptr<protobuf::IntMessage> pbo(new protobuf::IntMessage()); - // transfer obj data to pbo - pbo->set_value(*obj); - pbo->SerializeToString(&wire); - return getWireSchema(); - -} - -IPAACA_EXPORT AnnotatedData IntConverter::deserialize(const std::string& wireSchema, const std::string& wire) { - assert(wireSchema == getWireSchema()); // "int" - boost::shared_ptr<protobuf::IntMessage> pbo(new protobuf::IntMessage()); - pbo->ParseFromString(wire); - boost::shared_ptr<int> obj = boost::shared_ptr<int>(new int(pbo->value())); - return std::make_pair("int", obj); -} -//}}} } // of namespace ipaaca -- GitLab