Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • scs/ipaaca
  • ramin.yaghoubzadeh/ipaaca
2 results
Show changes
Showing
with 929 additions and 489 deletions
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* "Incremental Processing Architecture * "Incremental Processing Architecture
* for Artificial Conversational Agents". * for Artificial Conversational Agents".
* *
* Copyright (c) 2009-2015 Social Cognitive Systems Group * Copyright (c) 2009-2022 Social Cognitive Systems Group
* (formerly the Sociable Agents Group) * (formerly the Sociable Agents Group)
* CITEC, Bielefeld University * CITEC, Bielefeld University
* *
...@@ -35,11 +35,6 @@ ...@@ -35,11 +35,6 @@
namespace ipaaca { namespace ipaaca {
using namespace rsb;
using namespace rsb::filter;
using namespace rsb::converter;
using namespace rsb::patterns;
// IU//{{{ // IU//{{{
IPAACA_EXPORT IU::ptr IU::create(const std::string& category, IUAccessMode access_mode, bool read_only, const std::string& payload_type) IPAACA_EXPORT IU::ptr IU::create(const std::string& category, IUAccessMode access_mode, bool read_only, const std::string& payload_type)
{ {
...@@ -62,6 +57,7 @@ IPAACA_EXPORT IU::IU(const std::string& category, IUAccessMode access_mode, bool ...@@ -62,6 +57,7 @@ IPAACA_EXPORT IU::IU(const std::string& category, IUAccessMode access_mode, bool
_read_only = read_only; _read_only = read_only;
_access_mode = access_mode; _access_mode = access_mode;
_committed = false; _committed = false;
_retracted = false;
} }
IPAACA_EXPORT void IU::_modify_links(bool is_delta, const LinkMap& new_links, const LinkMap& links_to_remove, const std::string& writer_name) IPAACA_EXPORT void IU::_modify_links(bool is_delta, const LinkMap& new_links, const LinkMap& links_to_remove, const std::string& writer_name)
...@@ -70,6 +66,9 @@ IPAACA_EXPORT void IU::_modify_links(bool is_delta, const LinkMap& new_links, co ...@@ -70,6 +66,9 @@ IPAACA_EXPORT void IU::_modify_links(bool is_delta, const LinkMap& new_links, co
if (_committed) { if (_committed) {
_revision_lock.unlock(); _revision_lock.unlock();
throw IUCommittedError(); throw IUCommittedError();
} else if (_retracted) {
_revision_lock.unlock();
throw IURetractedError();
} }
_increase_revision_number(); _increase_revision_number();
if (is_published()) { if (is_published()) {
...@@ -78,39 +77,29 @@ IPAACA_EXPORT void IU::_modify_links(bool is_delta, const LinkMap& new_links, co ...@@ -78,39 +77,29 @@ IPAACA_EXPORT void IU::_modify_links(bool is_delta, const LinkMap& new_links, co
_revision_lock.unlock(); _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, PayloadDocumentEntry::ptr>& new_items, const std::vector<std::string>& keys_to_remove, const std::string& writer_name) IPAACA_EXPORT void IU::_modify_payload(bool is_delta, const std::map<std::string, PayloadDocumentEntry::ptr>& new_items, const std::vector<std::string>& keys_to_remove, const std::string& writer_name)
{ {
IPAACA_INFO("") //IPAACA_INFO("")
_revision_lock.lock(); _revision_lock.lock();
if (_committed) { if (_committed) {
_revision_lock.unlock(); _revision_lock.unlock();
throw IUCommittedError(); throw IUCommittedError();
} else if (_retracted) {
_revision_lock.unlock();
throw IURetractedError();
} }
_increase_revision_number(); _increase_revision_number();
if (is_published()) { if (is_published()) {
//std::cout << "Sending a payload update with " << new_items.size() << " entries to merge." << std::endl; IPAACA_DEBUG("Sending a payload update, new entries:")
for (auto& kv: new_items) {
IPAACA_DEBUG(" " << kv.first << " -> " << kv.second)
}
IPAACA_DEBUG("and with removed keys:")
for (auto& k: keys_to_remove) {
IPAACA_DEBUG(" " << k)
}
_buffer->_send_iu_payload_update(this, is_delta, _revision, new_items, keys_to_remove, writer_name); _buffer->_send_iu_payload_update(this, is_delta, _revision, new_items, keys_to_remove, writer_name);
IPAACA_DEBUG("... sent.")
} }
_revision_lock.unlock(); _revision_lock.unlock();
} }
...@@ -126,6 +115,9 @@ IPAACA_EXPORT void IU::_internal_commit(const std::string& writer_name) ...@@ -126,6 +115,9 @@ IPAACA_EXPORT void IU::_internal_commit(const std::string& writer_name)
if (_committed) { if (_committed) {
_revision_lock.unlock(); _revision_lock.unlock();
throw IUCommittedError(); throw IUCommittedError();
} else if (_retracted) {
_revision_lock.unlock();
throw IURetractedError();
} }
_increase_revision_number(); _increase_revision_number();
_committed = true; _committed = true;
...@@ -178,23 +170,23 @@ void Message::_internal_commit(const std::string& writer_name) ...@@ -178,23 +170,23 @@ void Message::_internal_commit(const std::string& writer_name)
IPAACA_EXPORT RemotePushIU::ptr RemotePushIU::create() IPAACA_EXPORT RemotePushIU::ptr RemotePushIU::create()
{ {
RemotePushIU::ptr iu = RemotePushIU::ptr(new RemotePushIU(/* params */)); RemotePushIU::ptr iu = RemotePushIU::ptr(new RemotePushIU());
iu->_payload.initialize(iu); iu->_payload.initialize(iu);
return iu; return iu;
} }
IPAACA_EXPORT RemotePushIU::RemotePushIU() 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) 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) { if (_committed) {
throw IUCommittedError(); throw IUCommittedError();
} } else if (_retracted) {
if (_read_only) { throw IURetractedError();
} else if (_read_only) {
throw IUReadOnlyError(); throw IUReadOnlyError();
} }
RemoteServerPtr server = boost::static_pointer_cast<InputBuffer>(_buffer)->_get_remote_server(_owner_name); auto server = ((InputBuffer*)_buffer)->_get_remote_server(_owner_name);
IULinkUpdate::ptr update = IULinkUpdate::ptr(new IULinkUpdate()); IULinkUpdate::ptr update = IULinkUpdate::ptr(new IULinkUpdate());
update->uid = _uid; update->uid = _uid;
update->revision = _revision; update->revision = _revision;
...@@ -202,23 +194,24 @@ IPAACA_EXPORT void RemotePushIU::_modify_links(bool is_delta, const LinkMap& new ...@@ -202,23 +194,24 @@ IPAACA_EXPORT void RemotePushIU::_modify_links(bool is_delta, const LinkMap& new
update->writer_name = _buffer->unique_name(); update->writer_name = _buffer->unique_name();
update->new_links = new_links; update->new_links = new_links;
update->links_to_remove = links_to_remove; update->links_to_remove = links_to_remove;
boost::shared_ptr<int> result = server->call<int>("updateLinks", update, IPAACA_REMOTE_SERVER_TIMEOUT); // TODO int result = server->request_remote_link_update(update); // TODO
if (*result == 0) { if (result == 0) {
throw IUUpdateFailedError(); throw IUUpdateFailedError();
} else { } else {
_revision = *result; _revision = result;
} }
} }
IPAACA_EXPORT void RemotePushIU::_modify_payload(bool is_delta, const std::map<std::string, PayloadDocumentEntry::ptr>& new_items, const std::vector<std::string>& keys_to_remove, const std::string& writer_name) IPAACA_EXPORT void RemotePushIU::_modify_payload(bool is_delta, const std::map<std::string, PayloadDocumentEntry::ptr>& new_items, const std::vector<std::string>& keys_to_remove, const std::string& writer_name)
{ {
//std::cout << "-- Sending a modify_payload with " << new_items.size() << " keys to merge." << std::endl; IPAACA_DEBUG("Sending a modify_payload with " << new_items.size() << " keys to merge.")
if (_committed) { if (_committed) {
throw IUCommittedError(); throw IUCommittedError();
} } else if (_retracted) {
if (_read_only) { throw IURetractedError();
} else if (_read_only) {
throw IUReadOnlyError(); throw IUReadOnlyError();
} }
RemoteServerPtr server = boost::static_pointer_cast<InputBuffer>(_buffer)->_get_remote_server(_owner_name); auto server = ((InputBuffer*)_buffer)->_get_remote_server(_owner_name);
IUPayloadUpdate::ptr update = IUPayloadUpdate::ptr(new IUPayloadUpdate()); IUPayloadUpdate::ptr update = IUPayloadUpdate::ptr(new IUPayloadUpdate());
update->uid = _uid; update->uid = _uid;
update->revision = _revision; update->revision = _revision;
...@@ -227,11 +220,11 @@ IPAACA_EXPORT void RemotePushIU::_modify_payload(bool is_delta, const std::map<s ...@@ -227,11 +220,11 @@ IPAACA_EXPORT void RemotePushIU::_modify_payload(bool is_delta, const std::map<s
update->new_items = new_items; update->new_items = new_items;
update->keys_to_remove = keys_to_remove; update->keys_to_remove = keys_to_remove;
update->payload_type = _payload_type; update->payload_type = _payload_type;
boost::shared_ptr<int> result = server->call<int>("updatePayload", update, IPAACA_REMOTE_SERVER_TIMEOUT); // TODO int result = server->request_remote_payload_update(update);
if (*result == 0) { if (result == 0) {
throw IUUpdateFailedError(); throw IUUpdateFailedError();
} else { } else {
_revision = *result; _revision = result;
} }
} }
...@@ -239,21 +232,23 @@ IPAACA_EXPORT void RemotePushIU::commit() ...@@ -239,21 +232,23 @@ IPAACA_EXPORT void RemotePushIU::commit()
{ {
if (_read_only) { if (_read_only) {
throw IUReadOnlyError(); throw IUReadOnlyError();
} else if (_retracted) {
throw IURetractedError();
} }
if (_committed) { if (_committed) {
// Following python version: ignoring multiple commit // Following python version: ignoring multiple commit
return; return;
} }
RemoteServerPtr server = boost::static_pointer_cast<InputBuffer>(_buffer)->_get_remote_server(_owner_name); auto server = ((InputBuffer*)_buffer)->_get_remote_server(_owner_name);
boost::shared_ptr<protobuf::IUCommission> update = boost::shared_ptr<protobuf::IUCommission>(new protobuf::IUCommission()); std::shared_ptr<protobuf::IUCommission> update = std::shared_ptr<protobuf::IUCommission>(new protobuf::IUCommission());
update->set_uid(_uid); update->set_uid(_uid);
update->set_revision(_revision); update->set_revision(_revision);
update->set_writer_name(_buffer->unique_name()); update->set_writer_name(_buffer->unique_name());
boost::shared_ptr<int> result = server->call<int>("commit", update, IPAACA_REMOTE_SERVER_TIMEOUT); // TODO int result = server->request_remote_commission(update);
if (*result == 0) { if (result == 0) {
throw IUUpdateFailedError(); throw IUUpdateFailedError();
} else { } else {
_revision = *result; _revision = result;
} }
} }
...@@ -297,13 +292,12 @@ IPAACA_EXPORT void RemotePushIU::_apply_retraction() ...@@ -297,13 +292,12 @@ IPAACA_EXPORT void RemotePushIU::_apply_retraction()
IPAACA_EXPORT RemoteMessage::ptr RemoteMessage::create() IPAACA_EXPORT RemoteMessage::ptr RemoteMessage::create()
{ {
RemoteMessage::ptr iu = RemoteMessage::ptr(new RemoteMessage(/* params */)); RemoteMessage::ptr iu = RemoteMessage::ptr(new RemoteMessage());
iu->_payload.initialize(iu); iu->_payload.initialize(iu);
return iu; return iu;
} }
IPAACA_EXPORT RemoteMessage::RemoteMessage() 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_EXPORT void RemoteMessage::_modify_links(bool is_delta, const LinkMap& new_links, const LinkMap& links_to_remove, const std::string& writer_name)
{ {
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* "Incremental Processing Architecture * "Incremental Processing Architecture
* for Artificial Conversational Agents". * for Artificial Conversational Agents".
* *
* Copyright (c) 2009-2015 Social Cognitive Systems Group * Copyright (c) 2009-2022 Social Cognitive Systems Group
* (formerly the Sociable Agents Group) * (formerly the Sociable Agents Group)
* CITEC, Bielefeld University * CITEC, Bielefeld University
* *
...@@ -31,15 +31,245 @@ ...@@ -31,15 +31,245 @@
* Excellence Initiative. * Excellence Initiative.
*/ */
/**
* \file ipaaca-json.cc
*
* \brief Testbed for ipaaca / JSON functionality
*
* This file is not used in the ipaaca library, but produces
* a separate program, if enabled in CMakeLists.txt
*
* \author Ramin Yaghoubzadeh (ryaghoubzadeh@uni-bielefeld.de)
* \date March, 2015
*/
#include <ipaaca/ipaaca.h> #include <ipaaca/ipaaca.h>
#include <ipaaca/ipaaca-json.h>
#include "rapidjson/document.h"
#include "rapidjson/prettywriter.h"
#include "rapidjson/filestream.h"
#include <cstdio>
#include <iomanip> #include <iomanip>
// Notes:
// - From http://stackoverflow.com/questions/10426924/json-root-element
// Actually there are two different JSON specifications. RFC 4627 requires a JSON text to be
// an object or an array. ECMA-262, 5th edition, section 15.12 does not impose this restriction.
using namespace rapidjson; using namespace rapidjson;
using namespace std; using namespace std;
int json_testbed_main(int argc, char** argv) int batch_update_main(int argc, char** argv)//{{{
{
ipaaca::OutputBuffer::ptr ob = ipaaca::OutputBuffer::create("myprog");
std::cout << std::endl << "Setting up an IU with initial contents" << std::endl;
ipaaca::IU::ptr iu = ipaaca::IU::create("testcategory");
iu->payload()["a"] = "OLD: initial contents of payload";
iu->payload()["b"] = "OLD: initial value for b";
std::cout << std::endl << "Initial contents of payload:" << std::endl;
for (auto it: iu->payload()) {
std::cout << " " << it.first << " -> " << it.second << std::endl;
}
std::cout << std::endl << "Publishing IU (sniffer should receive one ADDED)" << std::endl;
ob->add(iu);
std::cout << "Waiting 5 sec" << std::endl;
sleep(5);
std::cout << std::endl << "Batch-writing some stuff (sniffer should receive a single UPDATED)" << std::endl;
{
ipaaca::Locker locker(iu->payload());
iu->payload().set(std::map<std::string, std::string>{{"b", "VALUE"}, {"bPrime", "VALUE"}});
iu->payload()["a"] = std::map<std::string, long>{{"a", 1},{"b", 2},{"c", 3}};
iu->payload()["remove_me"] = "WARNING: this should not be in the payload where an update is received!";
iu->payload()["c"] = "WARNING: this should read abc123, not this warning message!";
iu->payload()["d"] = 100;
iu->payload().remove("d");
iu->payload()["d"] = 200;
iu->payload()["d"] = 300;
iu->payload().remove("d");
iu->payload()["d"] = 400;
iu->payload()["e"] = "Note: a key 'd' should exist with value 400, and 'b' and 'bPrime' should be equal";
iu->payload()["f"] = "12.5000";
iu->payload()["g"] = std::vector<std::string>{"g1", "g2"};
iu->payload().remove("remove_me");
iu->payload()["c"] = "abc123";
iu->payload()["testlist"] = std::vector<long> {0, 1, 2, 3, 4, 5};
}
std::cout << std::endl << "Adding another key 'XYZ' and changing testlist to start with 2 1000s (sniffer -> 1x UPDATED)" << std::endl;
{
ipaaca::Locker locker(iu->payload());
iu->payload()["XYZ"] = "testlist should now start with two 1000s";
iu->payload()["testlist"][0] = 500;
iu->payload()["testlist"][0] = 1000;
iu->payload()["testlist"][1] = 1000;
}
std::cout << std::endl << "Final batch update, wiping most (sniffer should receive a third UPDATED, with 3 keys remaining in the payload)" << std::endl;
{
ipaaca::Locker locker(iu->payload());
iu->payload()["SHOULD_NOT_EXIST"] = "WARNING: this key should never be visible";
iu->payload().set(std::map<std::string, std::string>{{"A", "Final contents (3 entries)"}, {"B", "Final stuff (3 entries)"}});
iu->payload()["C"] = std::vector<std::string>{"payload ", "should ", "have ", "three ", "entries, ", "A ", "B ", "and ", "C"};
}
std::cout << std::endl << "Final contents of payload:" << std::endl;
for (auto it: iu->payload()) {
std::cout << " " << it.first << " -> " << it.second << std::endl;
}
std::cout << "Waiting 2 sec" << std::endl;
sleep(2);
return 0;
}
//}}}
#ifdef IPAACA_BUILD_MOCK_OBJECTS
int iterators_main(int argc, char** argv)//{{{
{
std::string json_source("[\n\
\"old\",\n\
[\n\
\"str\",\n\
null\n\
],\n\
3,\n\
{\n\
\"key1\": \"value1\",\n\
\"key2\": \"value2\"\n\
}\n\
]");
std::cout << "Using this JSON document as initial payload entry 'a':" << std::endl << json_source << std::endl;
ipaaca::PayloadDocumentEntry::ptr entry = ipaaca::PayloadDocumentEntry::from_json_string_representation(json_source);
std::cout << std::endl << "Setting up payload by adding some additional values" << std::endl;
ipaaca::FakeIU::ptr iu = ipaaca::FakeIU::create();
iu->add_fake_payload_item("a", entry);
iu->payload()["b"] = "simpleString";
iu->payload()["bPrime"] = "simpleString";
iu->payload()["c"] = "anotherSimpleString";
iu->payload()["d"] = 100;
iu->payload()["e"] = 3l;
iu->payload()["f"] = "12.5000";
iu->payload()["g"] = std::vector<std::string>{"g1", "g2"};
std::cout << std::endl << "Iterate over payload" << std::endl;
for (auto it = iu->payload().begin(); it != iu->payload().end(); ++it) {
std::cout << " " << it->first << " -> " << it->second << std::endl;
}
std::cout << std::endl << "Iterate over payload, range-based" << std::endl;
for (auto it: iu->payload()) {
std::cout << " " << it.first << " -> " << it.second << std::endl;
}
std::cout << std::endl << "Comparisons" << std::endl;
bool eq;
eq = iu->payload()["a"] == iu->payload()["b"];
std::cout << " a==b ? : " << (eq?"true":"false") << std::endl;
eq = iu->payload()["b"] == iu->payload()["bPrime"];
std::cout << " b==bPrime ? : " << (eq?"true":"false") << std::endl;
eq = iu->payload()["b"] == "simpleString";
std::cout << " b==\"simpleString\" ? : " << (eq?"true":"false") << std::endl;
eq = iu->payload()["b"] == 100;
std::cout << " b==100 ? : " << (eq?"true":"false") << std::endl;
eq = iu->payload()["d"] == 100;
std::cout << " d==100 ? : " << (eq?"true":"false") << std::endl;
eq = iu->payload()["a"][2] == iu->payload()["e"];
std::cout << " a[2]==e ? : " << (eq?"true":"false") << std::endl;
std::cout << std::endl << "Type checks" << std::endl;
std::cout << " a[3] is_null() ? : " << ((iu->payload()["a"][3].is_null())?"true":"false") << std::endl;
std::cout << " a[3] is_string() ? : " << ((iu->payload()["a"][3].is_string())?"true":"false") << std::endl;
std::cout << " a[3] is_number() ? : " << ((iu->payload()["a"][3].is_number())?"true":"false") << std::endl;
std::cout << " a[3] is_list() ? : " << ((iu->payload()["a"][3].is_list())?"true":"false") << std::endl;
std::cout << " a[3] is_map() ? : " << ((iu->payload()["a"][3].is_map())?"true":"false") << std::endl;
std::cout << std::endl;
std::cout << " f is_null() ? : " << ((iu->payload()["f"].is_null())?"true":"false") << std::endl;
std::cout << " f is_string() ? : " << ((iu->payload()["f"].is_string())?"true":"false") << std::endl;
std::cout << " f is_number() ? : " << ((iu->payload()["f"].is_number())?"true":"false") << std::endl;
std::cout << " f is_list() ? : " << ((iu->payload()["f"].is_list())?"true":"false") << std::endl;
std::cout << " f is_map() ? : " << ((iu->payload()["f"].is_map())?"true":"false") << std::endl;
std::cout << std::endl << "Inner iterators, map (printing values as strings)" << std::endl;
try {
auto inner = iu->payload()["a"][3];
std::cout << "Map iteration over payload['a'][3], which equals " << inner << std::endl;
std::cout << "Reported size is " << inner.size() << std::endl;
for (auto kv: inner.as_map()) {
std::cout << " \"" << kv.first << "\" -> \"" << kv.second << "\"" << std::endl;
}
} catch (ipaaca::Exception& ex) {
std::cout << " Unexpected exception: " << ex.what() << std::endl;
}
try {
auto inner = iu->payload()["a"][2];
std::cout << "Map iteration over payload['a'][2], which equals " << inner << std::endl;
std::cout << "Reported size is " << inner.size() << std::endl;
for (auto kv: inner.as_map()) {
std::cout << " \"" << kv.first << "\" -> \"" << kv.second << "\"" << std::endl;
}
} catch (ipaaca::PayloadTypeConversionError& ex) {
std::cout << " Failed as expected with " << ex.what() << std::endl;
} catch (ipaaca::Exception& ex) {
std::cout << " Unexpected exception: " << ex.what() << std::endl;
}
std::cout << std::endl << "Inner iterators, list (printing values as strings)" << std::endl;
try {
auto inner = iu->payload()["a"][1];
std::cout << "List iteration over payload['a'][1], which equals " << inner << std::endl;
std::cout << "Reported size is " << inner.size() << std::endl;
for (auto proxy: inner.as_list()) {
std::cout << " \"" << proxy << "\"" << std::endl;
}
} catch (ipaaca::Exception& ex) {
std::cout << " Unexpected exception: " << ex.what() << std::endl;
}
try {
auto inner = iu->payload()["a"][1][1];
std::cout << "List iteration over payload['a'][1][1], which equals " << inner << std::endl;
std::cout << "Reported size is " << inner.size() << std::endl;
for (auto proxy: inner.as_list()) {
std::cout << " \"" << proxy << "\"" << std::endl;
}
} catch (ipaaca::PayloadTypeConversionError& ex) {
std::cout << " Failed as expected with " << ex.what() << std::endl;
} catch (ipaaca::Exception& ex) {
std::cout << " Unexpected exception: " << ex.what() << std::endl;
}
std::cout << std::endl << "Appending a string item to the end of payload['a']" << std::endl;
iu->payload()["a"].push_back("appended string entry");
std::cout << "Resulting entries in payload['a']:" << std::endl;
for (auto v: iu->payload()["a"].as_list()) {
std::cout << " " << v << std::endl;
}
std::cout << std::endl << "Extending payload['a'] by a list of three bools" << std::endl;
iu->payload()["a"].extend(std::list<bool>{false, false, true});
std::cout << "Resulting entries in payload['a']:" << std::endl;
for (auto v: iu->payload()["a"].as_list()) {
std::cout << " " << v << std::endl;
}
std::cout << std::endl << "Extending payload['a'] by payload['g'] and appending payload['f']" << std::endl;
iu->payload()["a"].extend(iu->payload()["g"]);
iu->payload()["a"].push_back(iu->payload()["f"]);
std::cout << "Resulting entries in payload['a']:" << std::endl;
for (auto v: iu->payload()["a"].as_list()) {
std::cout << " " << v << std::endl;
}
return 0;
}
//}}}
int json_testbed_main(int argc, char** argv)//{{{
{ {
std::string json_source("[\"old\",2,3,4]"); std::string json_source("[\"old\",2,3,4]");
ipaaca::PayloadDocumentEntry::ptr entry = ipaaca::PayloadDocumentEntry::from_json_string_representation(json_source); ipaaca::PayloadDocumentEntry::ptr entry = ipaaca::PayloadDocumentEntry::from_json_string_representation(json_source);
...@@ -50,9 +280,9 @@ int json_testbed_main(int argc, char** argv) ...@@ -50,9 +280,9 @@ int json_testbed_main(int argc, char** argv)
ipaaca::FakeIU::ptr iu = ipaaca::FakeIU::create(); ipaaca::FakeIU::ptr iu = ipaaca::FakeIU::create();
iu->add_fake_payload_item("a", entry); iu->add_fake_payload_item("a", entry);
iu->add_fake_payload_item("b", entrynew); iu->add_fake_payload_item("b", entrynew);
iu->payload()["c"] = "simpleString";
auto proxy = iu->payload()["a"][3]; auto proxy = iu->payload()["a"][3];
std::cout << proxy << std::endl;
std::cout << "IU payload before: " << iu->payload() << std::endl; std::cout << "IU payload before: " << iu->payload() << std::endl;
std::cout << "Entry before: " << entry << std::endl; std::cout << "Entry before: " << entry << std::endl;
...@@ -73,9 +303,9 @@ int json_testbed_main(int argc, char** argv) ...@@ -73,9 +303,9 @@ int json_testbed_main(int argc, char** argv)
return 0; return 0;
} }
//}}}
int fakeiu_main(int argc, char** argv)//{{{
int fakeiu_main(int argc, char** argv)
{ {
//if (argc<2) { //if (argc<2) {
// std::cout << "Please provide json content as the first argument." << std::endl; // std::cout << "Please provide json content as the first argument." << std::endl;
...@@ -197,20 +427,12 @@ int fakeiu_main(int argc, char** argv) ...@@ -197,20 +427,12 @@ int fakeiu_main(int argc, char** argv)
for (auto& kv: pl_flat) { for (auto& kv: pl_flat) {
std::cout << " " << std::left << std::setw(15) << (kv.first+": ") << kv.second << std::endl; std::cout << " " << std::left << std::setw(15) << (kv.first+": ") << kv.second << std::endl;
} }
/*{
StringBuffer buffer;
Writer<StringBuffer> writer(buffer);
entry->document.Accept(writer);
std::string docstring = buffer.GetString();
std::cout << "Final document: " << docstring << std::endl;
}*/
// Done
return 0; return 0;
} }
//}}}
#endif
int legacy_iu_main(int argc, char** argv)//{{{
int legacy_iu_main(int argc, char** argv)
{ {
// produce and fill a new and a legacy IU with identical contents // produce and fill a new and a legacy IU with identical contents
...@@ -220,7 +442,7 @@ int legacy_iu_main(int argc, char** argv) ...@@ -220,7 +442,7 @@ int legacy_iu_main(int argc, char** argv)
}); });
std::cout << "--- Create IUs with category jsonTest" << std::endl; std::cout << "--- Create IUs with category jsonTest" << std::endl;
ipaaca::IU::ptr iu1 = ipaaca::IU::create("jsonTest"); ipaaca::IU::ptr iu1 = ipaaca::IU::create("jsonTest");
ipaaca::IU::ptr iu2 = ipaaca::IU::create("jsonTest", "STR"); ipaaca::IU::ptr iu2 = ipaaca::IU::create("jsonTest", "STR"); // explicity request old payload
std::map<std::string, long> newmap = { {"fifty", 50}, {"ninety-nine", 99} }; std::map<std::string, long> newmap = { {"fifty", 50}, {"ninety-nine", 99} };
std::cout << "--- Set map" << std::endl; std::cout << "--- Set map" << std::endl;
iu1->payload()["map"] = newmap; iu1->payload()["map"] = newmap;
...@@ -235,8 +457,9 @@ int legacy_iu_main(int argc, char** argv) ...@@ -235,8 +457,9 @@ int legacy_iu_main(int argc, char** argv)
sleep(5); sleep(5);
return 0; return 0;
} }
//}}}
int iu_main(int argc, char** argv) int iu_main(int argc, char** argv)//{{{
{ {
ipaaca::InputBuffer::ptr ib = ipaaca::InputBuffer::create("jsonTestReceiver", "jsonTest"); ipaaca::InputBuffer::ptr ib = ipaaca::InputBuffer::create("jsonTestReceiver", "jsonTest");
ib->register_handler([](ipaaca::IUInterface::ptr iu, ipaaca::IUEventType event_type, bool local) { ib->register_handler([](ipaaca::IUInterface::ptr iu, ipaaca::IUEventType event_type, bool local) {
...@@ -284,13 +507,16 @@ int iu_main(int argc, char** argv) ...@@ -284,13 +507,16 @@ int iu_main(int argc, char** argv)
std::cout << "--- Terminating " << std::endl; std::cout << "--- Terminating " << std::endl;
return 0; return 0;
} }
//}}}
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
ipaaca::CommandLineParser::ptr parser = ipaaca::CommandLineParser::create(); ipaaca::CommandLineParser::ptr parser = ipaaca::CommandLineParser::create();
ipaaca::CommandLineOptions::ptr options = parser->parse(argc, argv); ipaaca::CommandLineOptions::ptr options = parser->parse(argc, argv);
return json_testbed_main(argc, argv); return batch_update_main(argc, argv);
//return iterators_main(argc, argv);
//return json_testbed_main(argc, argv);
//return legacy_iu_main(argc, argv); //return legacy_iu_main(argc, argv);
//return fakeiu_main(argc, argv); //return fakeiu_main(argc, argv);
//return iu_main(argc, argv); //return iu_main(argc, argv);
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* "Incremental Processing Architecture * "Incremental Processing Architecture
* for Artificial Conversational Agents". * for Artificial Conversational Agents".
* *
* Copyright (c) 2009-2015 Social Cognitive Systems Group * Copyright (c) 2009-2022 Social Cognitive Systems Group
* (formerly the Sociable Agents Group) * (formerly the Sociable Agents Group)
* CITEC, Bielefeld University * CITEC, Bielefeld University
* *
...@@ -35,11 +35,6 @@ ...@@ -35,11 +35,6 @@
namespace ipaaca { 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)//{{{ IPAACA_EXPORT std::ostream& operator<<(std::ostream& os, const SmartLinkMap& obj)//{{{
{ {
os << "{"; os << "{";
...@@ -87,7 +82,6 @@ IPAACA_EXPORT void SmartLinkMap::_add_and_remove_links(const LinkMap& add, const ...@@ -87,7 +82,6 @@ IPAACA_EXPORT void SmartLinkMap::_add_and_remove_links(const LinkMap& add, const
} }
IPAACA_EXPORT void SmartLinkMap::_replace_links(const LinkMap& links) IPAACA_EXPORT void SmartLinkMap::_replace_links(const LinkMap& links)
{ {
//_links.clear();
_links=links; _links=links;
} }
IPAACA_EXPORT const LinkSet& SmartLinkMap::get_links(const std::string& key) IPAACA_EXPORT const LinkSet& SmartLinkMap::get_links(const std::string& key)
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* "Incremental Processing Architecture * "Incremental Processing Architecture
* for Artificial Conversational Agents". * for Artificial Conversational Agents".
* *
* Copyright (c) 2009-2015 Social Cognitive Systems Group * Copyright (c) 2009-2022 Social Cognitive Systems Group
* (formerly the Sociable Agents Group) * (formerly the Sociable Agents Group)
* CITEC, Bielefeld University * CITEC, Bielefeld University
* *
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* "Incremental Processing Architecture * "Incremental Processing Architecture
* for Artificial Conversational Agents". * for Artificial Conversational Agents".
* *
* Copyright (c) 2009-2015 Social Cognitive Systems Group * Copyright (c) 2009-2022 Social Cognitive Systems Group
* (formerly the Sociable Agents Group) * (formerly the Sociable Agents Group)
* CITEC, Bielefeld University * CITEC, Bielefeld University
* *
...@@ -33,15 +33,12 @@ ...@@ -33,15 +33,12 @@
#include <ipaaca/ipaaca.h> #include <ipaaca/ipaaca.h>
#include <sstream>
namespace ipaaca { namespace ipaaca {
using namespace rapidjson; using namespace rapidjson;
using namespace rsb;
using namespace rsb::filter;
using namespace rsb::converter;
using namespace rsb::patterns;
// temporary helper to show rapidjson internal type // temporary helper to show rapidjson internal type
std::string value_diagnosis(rapidjson::Value* val) std::string value_diagnosis(rapidjson::Value* val)
{ {
...@@ -53,10 +50,8 @@ std::string value_diagnosis(rapidjson::Value* val) ...@@ -53,10 +50,8 @@ std::string value_diagnosis(rapidjson::Value* val)
if (val->IsArray()) return "array"; if (val->IsArray()) return "array";
if (val->IsObject()) return "object"; if (val->IsObject()) return "object";
return "other"; return "other";
} }
IPAACA_EXPORT std::ostream& operator<<(std::ostream& os, const rapidjson::Value& val)//{{{ IPAACA_EXPORT std::ostream& operator<<(std::ostream& os, const rapidjson::Value& val)//{{{
{ {
os << json_value_cast<std::string>(val); os << json_value_cast<std::string>(val);
...@@ -83,13 +78,27 @@ IPAACA_EXPORT std::ostream& operator<<(std::ostream& os, const Payload& obj)//{{ ...@@ -83,13 +78,27 @@ IPAACA_EXPORT std::ostream& operator<<(std::ostream& os, const Payload& obj)//{{
bool first = true; bool first = true;
for (auto& kv: obj._document_store) { for (auto& kv: obj._document_store) {
if (first) { first=false; } else { os << ", "; } if (first) { first=false; } else { os << ", "; }
os << "'" << kv.first << "':'" << kv.second->json_source << "'"; os << "\"" << kv.first << "\":" << kv.second->to_json_string_representation() << "";
} }
os << "}"; os << "}";
return os; return os;
} }
//}}} //}}}
double strict_numerical_interpretation(const std::string& str)
{
char* endptr;
auto s = str_trim(str);
const char* startptr = s.c_str();
double d = strtod(startptr, &endptr);
if ((*endptr)=='\0') {
// everything could be parsed
return d;
} else {
throw PayloadTypeConversionError();
}
}
// json_value_cast//{{{ // json_value_cast//{{{
IPAACA_EXPORT template<> std::string json_value_cast(const rapidjson::Value& v) IPAACA_EXPORT template<> std::string json_value_cast(const rapidjson::Value& v)
{ {
...@@ -102,7 +111,7 @@ IPAACA_EXPORT template<> std::string json_value_cast(const rapidjson::Value& v) ...@@ -102,7 +111,7 @@ IPAACA_EXPORT template<> std::string json_value_cast(const rapidjson::Value& v)
} }
IPAACA_EXPORT template<> long json_value_cast(const rapidjson::Value& v) IPAACA_EXPORT template<> long json_value_cast(const rapidjson::Value& v)
{ {
if (v.IsString()) return atol(std::string(v.GetString()).c_str()); if (v.IsString()) return (long) strict_numerical_interpretation(v.GetString());
if (v.IsInt()) return v.GetInt(); if (v.IsInt()) return v.GetInt();
if (v.IsUint()) return v.GetUint(); if (v.IsUint()) return v.GetUint();
if (v.IsInt64()) return v.GetInt64(); if (v.IsInt64()) return v.GetInt64();
...@@ -111,14 +120,23 @@ IPAACA_EXPORT template<> long json_value_cast(const rapidjson::Value& v) ...@@ -111,14 +120,23 @@ IPAACA_EXPORT template<> long json_value_cast(const rapidjson::Value& v)
if (v.IsBool()) return v.GetBool() ? 1l : 0l; if (v.IsBool()) return v.GetBool() ? 1l : 0l;
if (v.IsNull()) return 0l; if (v.IsNull()) return 0l;
// default: return parse of string version (should always be 0 though?) // default: return parse of string version (should always be 0 though?)
rapidjson::StringBuffer buffer; throw PayloadTypeConversionError();
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer); }
v.Accept(writer); IPAACA_EXPORT template<> int json_value_cast(const rapidjson::Value& v)
return atol(std::string(buffer.GetString()).c_str()); {
if (v.IsString()) return (int) strict_numerical_interpretation(v.GetString());
if (v.IsInt()) return v.GetInt();
if (v.IsUint()) return v.GetUint();
if (v.IsInt64()) return v.GetInt64();
if (v.IsUint64()) return v.GetUint64();
if (v.IsDouble()) return (long) v.GetDouble();
if (v.IsBool()) return v.GetBool() ? 1l : 0l;
if (v.IsNull()) return 0l;
throw PayloadTypeConversionError();
} }
IPAACA_EXPORT template<> double json_value_cast(const rapidjson::Value& v) IPAACA_EXPORT template<> double json_value_cast(const rapidjson::Value& v)
{ {
if (v.IsString()) return atof(std::string(v.GetString()).c_str()); if (v.IsString()) return strict_numerical_interpretation(v.GetString());
if (v.IsDouble()) return v.GetDouble(); if (v.IsDouble()) return v.GetDouble();
if (v.IsInt()) return (double) v.GetInt(); if (v.IsInt()) return (double) v.GetInt();
if (v.IsUint()) return (double) v.GetUint(); if (v.IsUint()) return (double) v.GetUint();
...@@ -126,18 +144,13 @@ IPAACA_EXPORT template<> double json_value_cast(const rapidjson::Value& v) ...@@ -126,18 +144,13 @@ IPAACA_EXPORT template<> double json_value_cast(const rapidjson::Value& v)
if (v.IsUint64()) return (double) v.GetUint64(); if (v.IsUint64()) return (double) v.GetUint64();
if (v.IsBool()) return v.GetBool() ? 1.0 : 0.0; if (v.IsBool()) return v.GetBool() ? 1.0 : 0.0;
if (v.IsNull()) return 0.0; if (v.IsNull()) return 0.0;
// default: return parse of string version (should always be 0.0 though?) throw PayloadTypeConversionError();
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
v.Accept(writer);
return atof(std::string(buffer.GetString()).c_str());
} }
IPAACA_EXPORT template<> bool json_value_cast(const rapidjson::Value& v) IPAACA_EXPORT template<> bool json_value_cast(const rapidjson::Value& v)
{ {
if (v.IsString()) { if (v.IsString()) {
std::string s = v.GetString(); std::string s = v.GetString();
return !((s=="")||(s=="false")||(s=="False")||(s=="0")); return !(s==""); // NEW: only empty string maps to false
//return ((s=="1")||(s=="true")||(s=="True"));
} }
if (v.IsBool()) return v.GetBool(); if (v.IsBool()) return v.GetBool();
if (v.IsNull()) return false; if (v.IsNull()) return false;
...@@ -146,21 +159,17 @@ IPAACA_EXPORT template<> bool json_value_cast(const rapidjson::Value& v) ...@@ -146,21 +159,17 @@ IPAACA_EXPORT template<> bool json_value_cast(const rapidjson::Value& v)
if (v.IsInt64()) return v.GetInt64() != 0; if (v.IsInt64()) return v.GetInt64() != 0;
if (v.IsUint64()) return v.GetUint64() != 0; if (v.IsUint64()) return v.GetUint64() != 0;
if (v.IsDouble()) return v.GetDouble() != 0.0; if (v.IsDouble()) return v.GetDouble() != 0.0;
// default: return parse of string version (should always be 0.0 though?) // NEW: empty structures map to false ('Pythonesque' semantics!)
rapidjson::StringBuffer buffer; if (v.IsArray()) return v.Size() > 0;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer); if (v.IsObject()) return v.MemberCount() > 0;
v.Accept(writer); throw NotImplementedError(); // should never be reached anyway
std::string s = buffer.GetString();
return !((s=="")||(s=="false")||(s=="False")||(s=="0"));
} }
/*
* std::map<std::string, std::string> result;
std::for_each(_document_store.begin(), _document_store.end(), [&result](std::pair<std::string, PayloadDocumentEntry::ptr> pair) {
result[pair.first] = pair.second->document.GetString();
});
*/
//}}} //}}}
IPAACA_EXPORT void pack_into_json_value(rapidjson::Value& valueobject, rapidjson::Document::AllocatorType& allocator, int newvalue)
{
valueobject.SetInt(newvalue);
}
IPAACA_EXPORT void pack_into_json_value(rapidjson::Value& valueobject, rapidjson::Document::AllocatorType& allocator, long newvalue) IPAACA_EXPORT void pack_into_json_value(rapidjson::Value& valueobject, rapidjson::Document::AllocatorType& allocator, long newvalue)
{ {
valueobject.SetInt(newvalue); valueobject.SetInt(newvalue);
...@@ -181,25 +190,6 @@ IPAACA_EXPORT void pack_into_json_value(rapidjson::Value& valueobject, rapidjson ...@@ -181,25 +190,6 @@ IPAACA_EXPORT void pack_into_json_value(rapidjson::Value& valueobject, rapidjson
{ {
valueobject.SetString(newvalue, allocator); valueobject.SetString(newvalue, allocator);
} }
/*
IPAACA_EXPORT template<> void pack_into_json_value(rapidjson::Value& valueobject, rapidjson::Document::AllocatorType& allocator, const std::vector<std::string>& newvalue)
{
valueobject.SetArray();
for (auto& str: newvalue) {
rapidjson::Value sv;
sv.SetString(str, allocator);
valueobject.PushBack(sv, allocator);
}
}
IPAACA_EXPORT template<> void pack_into_json_value(rapidjson::Value& valueobject, rapidjson::Document::AllocatorType& allocator, const std::list<std::string>& newvalue)
{
IPAACA_IMPLEMENT_ME
}
IPAACA_EXPORT template<> void pack_into_json_value(rapidjson::Value& valueobject, rapidjson::Document::AllocatorType& allocator, const std::map<std::string, std::string>& newvalue)
{
IPAACA_IMPLEMENT_ME
}
*/
// PayloadDocumentEntry//{{{ // PayloadDocumentEntry//{{{
IPAACA_EXPORT std::string PayloadDocumentEntry::to_json_string_representation() IPAACA_EXPORT std::string PayloadDocumentEntry::to_json_string_representation()
...@@ -215,34 +205,25 @@ IPAACA_EXPORT PayloadDocumentEntry::ptr PayloadDocumentEntry::from_json_string_r ...@@ -215,34 +205,25 @@ IPAACA_EXPORT PayloadDocumentEntry::ptr PayloadDocumentEntry::from_json_string_r
if (entry->document.Parse(json_str.c_str()).HasParseError()) { if (entry->document.Parse(json_str.c_str()).HasParseError()) {
throw JsonParsingError(); throw JsonParsingError();
} }
entry->json_source = json_str;
return entry; return entry;
} }
IPAACA_EXPORT PayloadDocumentEntry::ptr PayloadDocumentEntry::from_unquoted_string_value(const std::string& str) IPAACA_EXPORT PayloadDocumentEntry::ptr PayloadDocumentEntry::from_unquoted_string_value(const std::string& str)
{ {
PayloadDocumentEntry::ptr entry = std::make_shared<ipaaca::PayloadDocumentEntry>(); PayloadDocumentEntry::ptr entry = std::make_shared<ipaaca::PayloadDocumentEntry>();
entry->document.SetString(str.c_str(), entry->document.GetAllocator()); entry->document.SetString(str.c_str(), entry->document.GetAllocator());
entry->update_json_source();
return entry; return entry;
} }
/// update json_source after a write operation (on newly cloned entries)
IPAACA_EXPORT void PayloadDocumentEntry::update_json_source()
{
json_source = to_json_string_representation();
}
IPAACA_EXPORT PayloadDocumentEntry::ptr PayloadDocumentEntry::create_null() IPAACA_EXPORT PayloadDocumentEntry::ptr PayloadDocumentEntry::create_null()
{ {
PayloadDocumentEntry::ptr entry = std::make_shared<ipaaca::PayloadDocumentEntry>(); PayloadDocumentEntry::ptr entry = std::make_shared<ipaaca::PayloadDocumentEntry>();
entry->json_source = "null"; // rapidjson::Document value is also null implicitly
return entry; return entry;
} }
IPAACA_EXPORT PayloadDocumentEntry::ptr PayloadDocumentEntry::clone() IPAACA_EXPORT PayloadDocumentEntry::ptr PayloadDocumentEntry::clone()
{ {
auto entry = PayloadDocumentEntry::from_json_string_representation(this->json_source); auto entry = PayloadDocumentEntry::create_null();
IPAACA_DEBUG("Cloned for copy-on-write, contents: " << entry) entry->document.CopyFrom(this->document, entry->document.GetAllocator());
IPAACA_DEBUG("PayloadDocumentEntry cloned for copy-on-write, contents: " << entry)
return entry; return entry;
} }
IPAACA_EXPORT rapidjson::Value& PayloadDocumentEntry::get_or_create_nested_value_from_proxy_path(PayloadEntryProxy* pep) IPAACA_EXPORT rapidjson::Value& PayloadDocumentEntry::get_or_create_nested_value_from_proxy_path(PayloadEntryProxy* pep)
...@@ -254,6 +235,7 @@ IPAACA_EXPORT rapidjson::Value& PayloadDocumentEntry::get_or_create_nested_value ...@@ -254,6 +235,7 @@ IPAACA_EXPORT rapidjson::Value& PayloadDocumentEntry::get_or_create_nested_value
if (pep->addressed_as_array) { if (pep->addressed_as_array) {
IPAACA_DEBUG("Addressed as array with index " << pep->addressed_index) IPAACA_DEBUG("Addressed as array with index " << pep->addressed_index)
if (! parent_value.IsArray()) { if (! parent_value.IsArray()) {
IPAACA_INFO("parent value is not of type Array")
throw PayloadAddressingError(); throw PayloadAddressingError();
} else { } else {
long idx = pep->addressed_index; long idx = pep->addressed_index;
...@@ -264,42 +246,13 @@ IPAACA_EXPORT rapidjson::Value& PayloadDocumentEntry::get_or_create_nested_value ...@@ -264,42 +246,13 @@ IPAACA_EXPORT rapidjson::Value& PayloadDocumentEntry::get_or_create_nested_value
throw PayloadAddressingError(); throw PayloadAddressingError();
} }
} }
// for append / push_back? :
/*if (parent_value.IsNull()) {
wasnull = true;
parent_value.SetArray();
}
if (wasnull || parent_value.IsArray()) {
long idx = pep->addressed_index;
long s = parent_value.Size();
if (idx<s) {
// existing element modified
parent_value[idx] = *json_value;
} else {
// implicitly initialize missing elements to null values
if (idx>s) {
long missing_elements = pep->addressed_index - p;
for (int i=0; i<missing_elements; ++i) {
parent_value.PushBack(, allocator)
}
}
}
if (s ==
} else {
throw PayloadAddressingError();
}*/
} else { } else {
IPAACA_DEBUG("Addressed as dict with key " << pep->addressed_key) IPAACA_DEBUG("Addressed as dict with key " << pep->addressed_key)
// addressed as object (dict)
//rapidjson::Value& parent_value = *(pep->parent->json_value);
if (! parent_value.IsObject()) { if (! parent_value.IsObject()) {
IPAACA_DEBUG("parent is not of type Object") IPAACA_INFO("parent value is not of type Object")
throw PayloadAddressingError(); throw PayloadAddressingError();
} else { } else {
rapidjson::Document::AllocatorType& allocator = document.GetAllocator(); rapidjson::Document::AllocatorType& allocator = document.GetAllocator();
//Value key;
//key.SetString(pep->addressed_key, allocator);
//parent_value.AddMember(key, *json_value, allocator);
rapidjson::Value key; rapidjson::Value key;
key.SetString(pep->addressed_key, allocator); key.SetString(pep->addressed_key, allocator);
auto it = parent_value.FindMember(key); auto it = parent_value.FindMember(key);
...@@ -315,77 +268,15 @@ IPAACA_EXPORT rapidjson::Value& PayloadDocumentEntry::get_or_create_nested_value ...@@ -315,77 +268,15 @@ IPAACA_EXPORT rapidjson::Value& PayloadDocumentEntry::get_or_create_nested_value
} }
} }
} }
//}}} //}}}
// PayloadEntryProxy//{{{ // PayloadEntryProxy//{{{
// only if not top-level
#if 0
IPAACA_EXPORT void PayloadEntryProxy::connect_to_existing_parents()
{
rapidjson::Document::AllocatorType& allocator = document_entry->document.GetAllocator();
PayloadEntryProxy* pep = this;
while (!(pep->existent) && pep->parent) { // only if not top-level
if (pep->addressed_as_array) {
rapidjson::Value& parent_value = *(pep->parent->json_value);
if (! parent_value.IsArray()) {
throw PayloadAddressingError();
} else {
long idx = pep->addressed_index;
long s = parent_value.Size();
if (idx<s) {
parent_value[idx] = *json_value;
} else {
throw PayloadAddressingError();
}
}
/*if (parent_value.IsNull()) {
wasnull = true;
parent_value.SetArray();
}
if (wasnull || parent_value.IsArray()) {
long idx = pep->addressed_index;
long s = parent_value.Size();
if (idx<s) {
// existing element modified
parent_value[idx] = *json_value;
} else {
// implicitly initialize missing elements to null values
if (idx>s) {
long missing_elements = pep->addressed_index - p;
for (int i=0; i<missing_elements; ++i) {
parent_value.PushBack(, allocator)
}
}
}
if (s ==
} else {
throw PayloadAddressingError();
}*/
} else {
// addressed as object (dict)
rapidjson::Value& parent_value = *(pep->parent->json_value);
if (! parent_value.IsObject()) {
throw PayloadAddressingError();
} else {
Value key;
key.SetString(pep->addressed_key, allocator);
parent_value.AddMember(key, *json_value, allocator);
}
}
// repeat for next parent in the tree
pep = pep->parent;
}
}
#endif
IPAACA_EXPORT PayloadEntryProxy::PayloadEntryProxy(Payload* payload, const std::string& key) IPAACA_EXPORT PayloadEntryProxy::PayloadEntryProxy(Payload* payload, const std::string& key)
: _payload(payload), _key(key), parent(nullptr) : _payload(payload), _key(key), parent(nullptr)
{ {
document_entry = _payload->get_entry(key); document_entry = _payload->get_entry(key);
json_value = &(document_entry->document); set_json_value(&(document_entry->document), "construction");
} }
IPAACA_EXPORT PayloadEntryProxy::PayloadEntryProxy(PayloadEntryProxy* parent_, const std::string& addr_key_) IPAACA_EXPORT PayloadEntryProxy::PayloadEntryProxy(PayloadEntryProxy* parent_, const std::string& addr_key_)
: parent(parent_), addressed_key(addr_key_), addressed_as_array(false) : parent(parent_), addressed_key(addr_key_), addressed_as_array(false)
...@@ -395,10 +286,10 @@ IPAACA_EXPORT PayloadEntryProxy::PayloadEntryProxy(PayloadEntryProxy* parent_, c ...@@ -395,10 +286,10 @@ IPAACA_EXPORT PayloadEntryProxy::PayloadEntryProxy(PayloadEntryProxy* parent_, c
document_entry = parent->document_entry; document_entry = parent->document_entry;
auto it = parent->json_value->FindMember(addr_key_.c_str()); auto it = parent->json_value->FindMember(addr_key_.c_str());
if (it != parent->json_value->MemberEnd()) { if (it != parent->json_value->MemberEnd()) {
json_value = &(parent->json_value->operator[](addr_key_.c_str())); set_json_value(&(parent->json_value->operator[](addr_key_.c_str())), std::string("construction from str addressing with ")+addr_key_);
existent = true; existent = true;
} else { } else {
json_value = nullptr; // avoid heap construction here set_json_value(nullptr, std::string("null-construction from failed str addressing with ")+addr_key_); // avoid heap construction here
existent = false; existent = false;
} }
} }
...@@ -408,7 +299,7 @@ IPAACA_EXPORT PayloadEntryProxy::PayloadEntryProxy(PayloadEntryProxy* parent_, s ...@@ -408,7 +299,7 @@ IPAACA_EXPORT PayloadEntryProxy::PayloadEntryProxy(PayloadEntryProxy* parent_, s
_payload = parent->_payload; _payload = parent->_payload;
_key = parent->_key; _key = parent->_key;
document_entry = parent->document_entry; document_entry = parent->document_entry;
json_value = &(parent->json_value->operator[](addr_idx_)); set_json_value(&(parent->json_value->operator[](addr_idx_)), std::string("construction from int addressing with ")+std::to_string(addr_idx_));
existent = true; existent = true;
} }
...@@ -419,11 +310,13 @@ IPAACA_EXPORT PayloadEntryProxy PayloadEntryProxy::operator[](const char* addr_k ...@@ -419,11 +310,13 @@ IPAACA_EXPORT PayloadEntryProxy PayloadEntryProxy::operator[](const char* addr_k
IPAACA_EXPORT PayloadEntryProxy PayloadEntryProxy::operator[](const std::string& addr_key_) IPAACA_EXPORT PayloadEntryProxy PayloadEntryProxy::operator[](const std::string& addr_key_)
{ {
if (!json_value) { if (!json_value) {
IPAACA_DEBUG("Invalid json_value!") IPAACA_INFO("Invalid json_value")
throw PayloadAddressingError(); throw PayloadAddressingError();
} }
//IPAACA_DEBUG("string addressing with '" << addr_key_ << "' of json object " << (off_t) json_value )
if (! json_value->IsObject()) { if (! json_value->IsObject()) {
IPAACA_DEBUG("Expected Object for operator[](string)!") IPAACA_INFO("Expected Object for operator[](string)")
//IPAACA_DEBUG(" But type is: " << value_diagnosis(json_value) )
throw PayloadAddressingError(); throw PayloadAddressingError();
} }
return PayloadEntryProxy(this, addr_key_); return PayloadEntryProxy(this, addr_key_);
...@@ -431,16 +324,16 @@ IPAACA_EXPORT PayloadEntryProxy PayloadEntryProxy::operator[](const std::string& ...@@ -431,16 +324,16 @@ IPAACA_EXPORT PayloadEntryProxy PayloadEntryProxy::operator[](const std::string&
IPAACA_EXPORT PayloadEntryProxy PayloadEntryProxy::operator[](size_t addr_idx_) IPAACA_EXPORT PayloadEntryProxy PayloadEntryProxy::operator[](size_t addr_idx_)
{ {
if (!json_value) { if (!json_value) {
IPAACA_DEBUG("Invalid json_value!") IPAACA_INFO("Invalid json_value")
throw PayloadAddressingError(); throw PayloadAddressingError();
} }
if (! json_value->IsArray()) { if (! json_value->IsArray()) {
IPAACA_DEBUG("Expected Array for operator[](size_t)!") IPAACA_INFO("Expected Array for operator[](size_t)")
throw PayloadAddressingError(); throw PayloadAddressingError();
} }
long s = json_value->Size(); long s = json_value->Size();
if (addr_idx_>=s) { if (addr_idx_>=s) {
IPAACA_DEBUG("Array out of bounds!") IPAACA_INFO("Array out of bounds")
throw PayloadAddressingError(); throw PayloadAddressingError();
} }
return PayloadEntryProxy(this, addr_idx_); return PayloadEntryProxy(this, addr_idx_);
...@@ -448,7 +341,7 @@ IPAACA_EXPORT PayloadEntryProxy PayloadEntryProxy::operator[](size_t addr_idx_) ...@@ -448,7 +341,7 @@ IPAACA_EXPORT PayloadEntryProxy PayloadEntryProxy::operator[](size_t addr_idx_)
IPAACA_EXPORT PayloadEntryProxy PayloadEntryProxy::operator[](int addr_idx_) IPAACA_EXPORT PayloadEntryProxy PayloadEntryProxy::operator[](int addr_idx_)
{ {
if (addr_idx_ < 0) { if (addr_idx_ < 0) {
IPAACA_DEBUG("Negative index!") IPAACA_INFO("Negative array index")
throw PayloadAddressingError(); throw PayloadAddressingError();
} }
return operator[]((size_t) addr_idx_); return operator[]((size_t) addr_idx_);
...@@ -462,149 +355,136 @@ IPAACA_EXPORT PayloadEntryProxy& PayloadEntryProxy::operator=(const PayloadEntry ...@@ -462,149 +355,136 @@ IPAACA_EXPORT PayloadEntryProxy& PayloadEntryProxy::operator=(const PayloadEntry
if (valueptr) { // only set if value is valid, keep default null value otherwise if (valueptr) { // only set if value is valid, keep default null value otherwise
newval.CopyFrom(*valueptr, new_entry->document.GetAllocator()); newval.CopyFrom(*valueptr, new_entry->document.GetAllocator());
} }
new_entry->update_json_source();
_payload->set(_key, new_entry); _payload->set(_key, new_entry);
return *this; return *this;
} }
/*
IPAACA_EXPORT PayloadEntryProxy& PayloadEntryProxy::operator=(const std::string& value)
{
//std::cout << "operator=(string)" << std::endl;
IPAACA_IMPLEMENT_ME
//_payload->set(_key, value);
return *this;
}
IPAACA_EXPORT PayloadEntryProxy& PayloadEntryProxy::operator=(const char* value)
{
//std::cout << "operator=(const char*)" << std::endl;
IPAACA_IMPLEMENT_ME
//_payload->set(_key, value);
return *this;
}
IPAACA_EXPORT PayloadEntryProxy& PayloadEntryProxy::operator=(double value)
{
//std::cout << "operator=(double)" << std::endl;
IPAACA_IMPLEMENT_ME
//_payload->set(_key, boost::lexical_cast<std::string>(value));
return *this;
}
IPAACA_EXPORT PayloadEntryProxy& PayloadEntryProxy::operator=(bool value)
{
//std::cout << "operator=(bool)" << std::endl;
IPAACA_IMPLEMENT_ME
//_payload->set(_key, boost::lexical_cast<std::string>(value));
return *this;
}
*/
IPAACA_EXPORT PayloadEntryProxy::operator std::string() IPAACA_EXPORT PayloadEntryProxy::operator std::string()
{ {
return json_value_cast<std::string>(json_value); return json_value_cast<std::string>(json_value);
//PayloadEntryProxy::get<std::string>(); }
IPAACA_EXPORT PayloadEntryProxy::operator int()
{
return json_value_cast<int>(json_value);
} }
IPAACA_EXPORT PayloadEntryProxy::operator long() IPAACA_EXPORT PayloadEntryProxy::operator long()
{ {
return json_value_cast<long>(json_value); return json_value_cast<long>(json_value);
//return PayloadEntryProxy::get<long>();
} }
IPAACA_EXPORT PayloadEntryProxy::operator double() IPAACA_EXPORT PayloadEntryProxy::operator double()
{ {
return json_value_cast<double>(json_value); return json_value_cast<double>(json_value);
//return PayloadEntryProxy::get<double>();
} }
IPAACA_EXPORT PayloadEntryProxy::operator bool() IPAACA_EXPORT PayloadEntryProxy::operator bool()
{ {
return json_value_cast<bool>(json_value); return json_value_cast<bool>(json_value);
//return PayloadEntryProxy::get<bool>();
} }
IPAACA_EXPORT std::string PayloadEntryProxy::to_str() IPAACA_EXPORT std::string PayloadEntryProxy::to_str()
{ {
return json_value_cast<std::string>(json_value); return json_value_cast<std::string>(json_value);
//return PayloadEntryProxy::get<std::string>(); }
IPAACA_EXPORT int PayloadEntryProxy::to_int()
{
return json_value_cast<int>(json_value);
} }
IPAACA_EXPORT long PayloadEntryProxy::to_long() IPAACA_EXPORT long PayloadEntryProxy::to_long()
{ {
return json_value_cast<long>(json_value); return json_value_cast<long>(json_value);
//return PayloadEntryProxy::get<long>();
} }
IPAACA_EXPORT double PayloadEntryProxy::to_float() IPAACA_EXPORT double PayloadEntryProxy::to_float()
{ {
return json_value_cast<double>(json_value); return json_value_cast<double>(json_value);
//return PayloadEntryProxy::get<double>(); }
IPAACA_EXPORT double PayloadEntryProxy::to_double()
{
return json_value_cast<double>(json_value);
} }
IPAACA_EXPORT bool PayloadEntryProxy::to_bool() IPAACA_EXPORT bool PayloadEntryProxy::to_bool()
{ {
return json_value_cast<bool>(json_value); return json_value_cast<bool>(json_value);
//return PayloadEntryProxy::get<bool>();
} }
IPAACA_EXPORT PayloadEntryProxyMapDecorator PayloadEntryProxy::as_map()
{
if (json_value && json_value->IsObject()) return PayloadEntryProxyMapDecorator(this);
throw PayloadTypeConversionError();
}
// IPAACA_EXPORT PayloadEntryProxyListDecorator PayloadEntryProxy::as_list()
// new stuff for protocol v2
//
/*
IPAACA_EXPORT template<> std::string PayloadEntryProxy::get<std::string>()
{ {
if (!json_value) return ""; if (json_value && json_value->IsArray()) return PayloadEntryProxyListDecorator(this);
//IPAACA_INFO( value_diagnosis(json_value) ) throw PayloadTypeConversionError();
if (json_value->IsString()) return json_value->GetString();
if (json_value->IsNull()) return "";
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
json_value->Accept(writer);
return buffer.GetString();
//return _payload->get(_key);
} }
IPAACA_EXPORT template<> long PayloadEntryProxy::get<long>()
IPAACA_EXPORT size_t PayloadEntryProxy::size()
{ {
return atof(operator std::string().c_str()); if (!json_value) return 0;
if (json_value->IsArray()) return json_value->Size();
if (json_value->IsObject()) return json_value->MemberCount();
return 0;
} }
IPAACA_EXPORT template<> double PayloadEntryProxy::get<double>() IPAACA_EXPORT bool PayloadEntryProxy::is_null()
{ {
return atol(operator std::string().c_str()); return (!json_value) || json_value->IsNull();
} }
IPAACA_EXPORT template<> bool PayloadEntryProxy::get<bool>() IPAACA_EXPORT bool PayloadEntryProxy::is_string()
{ {
std::string s = operator std::string(); return json_value && json_value->IsString();
return ((s=="1")||(s=="true")||(s=="True"));
} }
// complex types
IPAACA_EXPORT template<> std::list<std::string> PayloadEntryProxy::get<std::list<std::string> >() /// is_number => whether it is *interpretable* as a numerical value (i.e. including conversions)
IPAACA_EXPORT bool PayloadEntryProxy::is_number()
{ {
std::list<std::string> l; if (!json_value) return false;
l.push_back(PayloadEntryProxy::get<std::string>()); try {
return l; double dummy = json_value_cast<double>(*json_value);
return true;
} catch (PayloadTypeConversionError& ex) {
return false;
}
} }
IPAACA_EXPORT template<> std::vector<std::string> PayloadEntryProxy::get<std::vector<std::string> >() IPAACA_EXPORT bool PayloadEntryProxy::is_list()
{ {
std::vector<std::string> v; return json_value && json_value->IsArray();
v.push_back(PayloadEntryProxy::get<std::string>());
return v;
} }
IPAACA_EXPORT template<> std::map<std::string, std::string> PayloadEntryProxy::get<std::map<std::string, std::string> >() IPAACA_EXPORT bool PayloadEntryProxy::is_map()
{ {
std::map<std::string, std::string> m; return json_value && json_value->IsObject();
m["__automatic__"] = PayloadEntryProxy::get<std::string>();
return m;
} }
*/
//}}} //}}}
// Payload//{{{ // Payload//{{{
IPAACA_EXPORT void Payload::initialize(boost::shared_ptr<IUInterface> iu) IPAACA_EXPORT void Payload::on_lock()
{
Locker locker(_payload_operation_mode_lock);
IPAACA_DEBUG("Starting payload batch update mode ...")
_update_on_every_change = false;
std::stringstream ss;
ss << std::this_thread::get_id();
_writing_thread_id = ss.str();
}
IPAACA_EXPORT void Payload::on_unlock()
{
Locker locker(_payload_operation_mode_lock);
IPAACA_DEBUG("... applying payload batch update with " << _collected_modifications.size() << " modifications and " << _collected_removals.size() << " removals ...")
_internal_merge_and_remove(_collected_modifications, _collected_removals, _batch_update_writer_name);
_update_on_every_change = true;
_batch_update_writer_name = "";
_collected_modifications.clear();
_collected_removals.clear();
IPAACA_DEBUG("... exiting payload batch update mode.")
_writing_thread_id = "";
}
IPAACA_EXPORT void Payload::initialize(std::shared_ptr<IUInterface> iu)
{ {
_iu = boost::weak_ptr<IUInterface>(iu); _iu = std::weak_ptr<IUInterface>(iu);
} }
IPAACA_EXPORT PayloadEntryProxy Payload::operator[](const std::string& key) IPAACA_EXPORT PayloadEntryProxy Payload::operator[](const std::string& key)
{ {
// TODO atomicize
//boost::shared_ptr<PayloadEntryProxy> p(new PayloadEntryProxy(this, key));
return PayloadEntryProxy(this, key); return PayloadEntryProxy(this, key);
} }
...@@ -618,43 +498,134 @@ IPAACA_EXPORT Payload::operator std::map<std::string, std::string>() ...@@ -618,43 +498,134 @@ IPAACA_EXPORT Payload::operator std::map<std::string, std::string>()
} }
IPAACA_EXPORT void Payload::_internal_set(const std::string& k, PayloadDocumentEntry::ptr v, const std::string& writer_name) { IPAACA_EXPORT void Payload::_internal_set(const std::string& k, PayloadDocumentEntry::ptr v, const std::string& writer_name) {
std::map<std::string, PayloadDocumentEntry::ptr> _new; Locker locker(_payload_operation_mode_lock);
std::vector<std::string> _remove; if (_update_on_every_change) {
_new[k] = v; std::map<std::string, PayloadDocumentEntry::ptr> _new;
_iu.lock()->_modify_payload(true, _new, _remove, writer_name ); std::vector<std::string> _remove;
IPAACA_DEBUG(" Setting local payload item \"" << k << "\" to " << v) _new[k] = v;
_document_store[k] = v; _iu.lock()->_modify_payload(true, _new, _remove, writer_name );
mark_revision_change(); IPAACA_DEBUG(" Setting local payload item \"" << k << "\" to " << v)
_document_store[k] = v;
mark_revision_change();
} else {
IPAACA_DEBUG("queueing a payload set operation")
_batch_update_writer_name = writer_name;
_collected_modifications[k] = v;
// revoke deletions of this updated key
//_collected_removals.erase(k);
std::vector<std::string> new_removals;
for (auto& rk: _collected_removals) {
if (rk!=k) new_removals.push_back(rk);
}
_collected_removals = new_removals;
}
} }
IPAACA_EXPORT void Payload::_internal_remove(const std::string& k, const std::string& writer_name) { IPAACA_EXPORT void Payload::_internal_remove(const std::string& k, const std::string& writer_name) {
std::map<std::string, PayloadDocumentEntry::ptr> _new; Locker locker(_payload_operation_mode_lock);
std::vector<std::string> _remove; if (_update_on_every_change) {
_remove.push_back(k); std::map<std::string, PayloadDocumentEntry::ptr> _new;
_iu.lock()->_modify_payload(true, _new, _remove, writer_name ); std::vector<std::string> _remove;
_document_store.erase(k); _remove.push_back(k);
mark_revision_change(); _iu.lock()->_modify_payload(true, _new, _remove, writer_name );
_document_store.erase(k);
mark_revision_change();
} else {
IPAACA_DEBUG("queueing a payload remove operation")
_batch_update_writer_name = writer_name;
_collected_removals.push_back(k);
//_collected_removals.insert(k);
// revoke updates of this deleted key
_collected_modifications.erase(k);
}
} }
IPAACA_EXPORT void Payload::_internal_replace_all(const std::map<std::string, PayloadDocumentEntry::ptr>& new_contents, const std::string& writer_name) IPAACA_EXPORT void Payload::_internal_replace_all(const std::map<std::string, PayloadDocumentEntry::ptr>& new_contents, const std::string& writer_name)
{ {
std::vector<std::string> _remove; Locker locker(_payload_operation_mode_lock);
_iu.lock()->_modify_payload(false, new_contents, _remove, writer_name ); if (_update_on_every_change) {
_document_store = new_contents; std::vector<std::string> _remove;
mark_revision_change(); _iu.lock()->_modify_payload(false, new_contents, _remove, writer_name );
_document_store = new_contents;
mark_revision_change();
} else {
IPAACA_DEBUG("queueing a payload replace_all operation")
_batch_update_writer_name = writer_name;
_collected_modifications.clear();
for (auto& kv: new_contents) {
_collected_modifications[kv.first] = kv.second;
}
// take all existing keys and flag to remove them, unless overridden in current update
for (auto& kv: _document_store) {
if (! new_contents.count(kv.first)) {
_collected_removals.push_back(kv.first);
//_collected_removals.insert(kv.first);
_collected_modifications.erase(kv.first);
}
}
}
} }
IPAACA_EXPORT void Payload::_internal_merge(const std::map<std::string, PayloadDocumentEntry::ptr>& contents_to_merge, const std::string& writer_name) IPAACA_EXPORT void Payload::_internal_merge(const std::map<std::string, PayloadDocumentEntry::ptr>& contents_to_merge, const std::string& writer_name)
{ {
std::vector<std::string> _remove; Locker locker(_payload_operation_mode_lock);
_iu.lock()->_modify_payload(true, contents_to_merge, _remove, writer_name ); if (_update_on_every_change) {
std::vector<std::string> _remove;
_iu.lock()->_modify_payload(true, contents_to_merge, _remove, writer_name );
for (auto& kv: contents_to_merge) {
_document_store[kv.first] = kv.second;
}
mark_revision_change();
} else {
IPAACA_DEBUG("queueing a payload merge operation")
std::set<std::string> updated_keys;
_batch_update_writer_name = writer_name;
for (auto& kv: contents_to_merge) {
_collected_modifications[kv.first] = kv.second;
//_collected_removals.erase(kv.first); // moved here
updated_keys.insert(kv.first);
}
// revoke deletions of updated keys
std::vector<std::string> new_removals;
for (auto& rk: _collected_removals) {
if (! updated_keys.count(rk)) new_removals.push_back(rk);
}
_collected_removals = new_removals;
}
}
IPAACA_EXPORT void Payload::_internal_merge_and_remove(const std::map<std::string, PayloadDocumentEntry::ptr>& contents_to_merge, const std::vector<std::string>& keys_to_remove, const std::string& writer_name)
{
// this function is called by exiting the batch update mode only, so no extra locking here
_iu.lock()->_modify_payload(true, contents_to_merge, keys_to_remove, writer_name );
for (auto& k: keys_to_remove) {
_document_store.erase(k);
}
for (auto& kv: contents_to_merge) { for (auto& kv: contents_to_merge) {
_document_store[kv.first] = kv.second; _document_store[kv.first] = kv.second;
} }
mark_revision_change(); mark_revision_change();
//_document_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 PayloadDocumentEntry::ptr Payload::get_entry(const std::string& k) { IPAACA_EXPORT PayloadDocumentEntry::ptr Payload::get_entry(const std::string& k) {
if (! _update_on_every_change) {
std::stringstream ss;
ss << std::this_thread::get_id();
if (_writing_thread_id == ss.str()) {
IPAACA_DEBUG("Payload locked by current thread, looking for payload key in caches first")
// in batch mode, read from cached writed first!
// case 1: deleted key
if (std::find(_collected_removals.begin(), _collected_removals.end(), k) != _collected_removals.end()) {
IPAACA_DEBUG("Key removed, returning null")
for (auto& cr : _collected_removals) {
IPAACA_DEBUG(" cached removal: " << cr)
}
return PayloadDocumentEntry::create_null();
}
// case 2: updated key - use last known state!
auto it = _collected_modifications.find(k);
if (it!=_collected_modifications.end()) {
IPAACA_DEBUG("Key updated, returning current version")
return it->second;
}
// case 3: key not in the caches yet, just continue below
}
}
if (_document_store.count(k)>0) return _document_store[k]; if (_document_store.count(k)>0) return _document_store[k];
else return PayloadDocumentEntry::create_null(); // contains Document with 'null' value else return PayloadDocumentEntry::create_null(); // contains Document with 'null' value
} }
...@@ -667,10 +638,6 @@ IPAACA_EXPORT void Payload::set(const std::map<std::string, std::string>& all_el ...@@ -667,10 +638,6 @@ IPAACA_EXPORT void Payload::set(const std::map<std::string, std::string>& all_el
{ {
std::map<std::string, PayloadDocumentEntry::ptr> newmap; std::map<std::string, PayloadDocumentEntry::ptr> newmap;
for (auto& kv: all_elems) { for (auto& kv: all_elems) {
/*PayloadDocumentEntry::ptr newit = PayloadDocumentEntry::create_null();
newit->document.SetString(kv.second, newit->document.GetAllocator());
newit->update_json_source();
newmap[kv.first] = newit;*/
newmap[kv.first] = PayloadDocumentEntry::from_unquoted_string_value(kv.second); newmap[kv.first] = PayloadDocumentEntry::from_unquoted_string_value(kv.second);
} }
_internal_replace_all(newmap); _internal_replace_all(newmap);
...@@ -725,6 +692,12 @@ IPAACA_EXPORT std::pair<std::string, PayloadEntryProxy> PayloadIterator::operato ...@@ -725,6 +692,12 @@ IPAACA_EXPORT std::pair<std::string, PayloadEntryProxy> PayloadIterator::operato
if (raw_iterator == _payload->_document_store.end()) throw PayloadIteratorInvalidError(); if (raw_iterator == _payload->_document_store.end()) throw PayloadIteratorInvalidError();
return std::pair<std::string, PayloadEntryProxy>(raw_iterator->first, PayloadEntryProxy(_payload, raw_iterator->first)); return std::pair<std::string, PayloadEntryProxy>(raw_iterator->first, PayloadEntryProxy(_payload, raw_iterator->first));
} }
IPAACA_EXPORT std::shared_ptr<std::pair<std::string, PayloadEntryProxy> > PayloadIterator::operator->()
{
if (_payload->revision_changed(reference_payload_revision)) throw PayloadIteratorInvalidError();
if (raw_iterator == _payload->_document_store.end()) throw PayloadIteratorInvalidError();
return std::make_shared<std::pair<std::string, PayloadEntryProxy> >(raw_iterator->first, PayloadEntryProxy(_payload, raw_iterator->first));
}
IPAACA_EXPORT bool PayloadIterator::operator==(const PayloadIterator& ref) IPAACA_EXPORT bool PayloadIterator::operator==(const PayloadIterator& ref)
{ {
...@@ -738,4 +711,92 @@ IPAACA_EXPORT bool PayloadIterator::operator!=(const PayloadIterator& ref) ...@@ -738,4 +711,92 @@ IPAACA_EXPORT bool PayloadIterator::operator!=(const PayloadIterator& ref)
} }
//}}} //}}}
// PayloadEntryProxyMapIterator//{{{
IPAACA_EXPORT PayloadEntryProxyMapIterator::PayloadEntryProxyMapIterator(PayloadEntryProxy* proxy_, RawIterator&& raw_iter)
: proxy(proxy_), raw_iterator(std::move(raw_iter))
{
}
IPAACA_EXPORT PayloadEntryProxyMapIterator& PayloadEntryProxyMapIterator::operator++()
{
//IPAACA_DEBUG("Map iterator incrementing");
raw_iterator++;
return *this;
}
IPAACA_EXPORT std::pair<std::string, PayloadEntryProxy> PayloadEntryProxyMapIterator::operator*()
{
std::string key = raw_iterator->name.GetString();
//IPAACA_DEBUG("Deref map iterator key '" << key << "'");
//IPAACA_DEBUG(" of proxy " << (off_t) proxy << "");
return std::pair<std::string, PayloadEntryProxy>(key, (*proxy)[key] ); // generates child Proxy
}
IPAACA_EXPORT std::shared_ptr<std::pair<std::string, PayloadEntryProxy> > PayloadEntryProxyMapIterator::operator->()
{
std::string key = raw_iterator->name.GetString();
return std::make_shared<std::pair<std::string, PayloadEntryProxy> >(key, (*proxy)[key] ); // generates child Proxy
}
IPAACA_EXPORT bool PayloadEntryProxyMapIterator::operator==(const PayloadEntryProxyMapIterator& other_iter)
{
return raw_iterator==other_iter.raw_iterator;
}
IPAACA_EXPORT bool PayloadEntryProxyMapIterator::operator!=(const PayloadEntryProxyMapIterator& other_iter)
{
return raw_iterator!=other_iter.raw_iterator;
}
//}}}
// PayloadEntryProxyMapDecorator//{{{
PayloadEntryProxyMapIterator PayloadEntryProxyMapDecorator::begin()
{
return PayloadEntryProxyMapIterator(proxy, proxy->json_value->MemberBegin());
}
PayloadEntryProxyMapIterator PayloadEntryProxyMapDecorator::end()
{
return PayloadEntryProxyMapIterator(proxy, proxy->json_value->MemberEnd());
}
//}}}
// PayloadEntryProxyListIterator//{{{
IPAACA_EXPORT PayloadEntryProxyListIterator::PayloadEntryProxyListIterator(PayloadEntryProxy* proxy_, size_t idx, size_t size_)
: proxy(proxy_), current_idx(idx), size(size_)
{
}
IPAACA_EXPORT PayloadEntryProxyListIterator& PayloadEntryProxyListIterator::operator++()
{
if (current_idx!=size) current_idx++;
return *this;
}
IPAACA_EXPORT PayloadEntryProxy PayloadEntryProxyListIterator::operator*()
{
return (*proxy)[current_idx];
}
IPAACA_EXPORT std::shared_ptr<PayloadEntryProxy> PayloadEntryProxyListIterator::operator->()
{
return std::make_shared<PayloadEntryProxy>((*proxy)[current_idx]);
}
IPAACA_EXPORT bool PayloadEntryProxyListIterator::operator==(const PayloadEntryProxyListIterator& other_iter)
{
return (proxy==other_iter.proxy) && (current_idx==other_iter.current_idx);
}
IPAACA_EXPORT bool PayloadEntryProxyListIterator::operator!=(const PayloadEntryProxyListIterator& other_iter)
{
return (current_idx!=other_iter.current_idx) || (proxy!=other_iter.proxy);
}
//}}}
// PayloadEntryProxyListDecorator//{{{
PayloadEntryProxyListIterator PayloadEntryProxyListDecorator::begin()
{
return PayloadEntryProxyListIterator(proxy, 0, proxy->json_value->Size());
}
PayloadEntryProxyListIterator PayloadEntryProxyListDecorator::end()
{
size_t size = proxy->json_value->Size();
return PayloadEntryProxyListIterator(proxy, size, size);
}
//}}}
} // of namespace ipaaca } // of namespace ipaaca
...@@ -3,8 +3,9 @@ ...@@ -3,8 +3,9 @@
* "Incremental Processing Architecture * "Incremental Processing Architecture
* for Artificial Conversational Agents". * for Artificial Conversational Agents".
* *
* Copyright (c) 2009-2013 Sociable Agents Group * Copyright (c) 2009-2022 Social Cognitive Systems Group
* CITEC, Bielefeld University * (formerly the Sociable Agents Group)
* CITEC, Bielefeld University
* *
* http://opensource.cit-ec.de/projects/ipaaca/ * http://opensource.cit-ec.de/projects/ipaaca/
* http://purl.org/net/ipaaca * http://purl.org/net/ipaaca
...@@ -32,8 +33,20 @@ ...@@ -32,8 +33,20 @@
#include <ipaaca/ipaaca.h> #include <ipaaca/ipaaca.h>
#include <cctype>
#include <string>
#include <algorithm>
namespace ipaaca { namespace ipaaca {
std::string str_trim(const std::string &s)
{
auto wsfront = std::find_if_not(s.begin(), s.end(), [](int c){ return std::isspace(c); } );
auto wsback = std::find_if_not(s.rbegin(), s.rend(), [](int c){ return std::isspace(c); } ).base();
return (wsback<=wsfront ? std::string() : std::string(wsfront, wsback));
}
std::string str_join(const std::set<std::string>& set,const std::string& sep) std::string str_join(const std::set<std::string>& set,const std::string& sep)
{ {
if(set.size()==0) if(set.size()==0)
...@@ -74,28 +87,34 @@ std::string str_join(const std::vector<std::string>& vec,const std::string& sep) ...@@ -74,28 +87,34 @@ std::string str_join(const std::vector<std::string>& vec,const std::string& sep)
return tmp; return tmp;
} }
void str_split_wipe(const std::string& str, std::vector<std::string>& tokens, const std::string& delimiters ) int str_split_wipe(const std::string& str, std::vector<std::string>& tokens, const std::string& delimiters )
{ {
tokens.clear(); tokens.clear();
std::string::size_type lastPos = str.find_first_not_of(delimiters, 0); std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
std::string::size_type pos = str.find_first_of(delimiters, lastPos); std::string::size_type pos = str.find_first_of(delimiters, lastPos);
int count = 0;
while (std::string::npos != pos || std::string::npos != lastPos) while (std::string::npos != pos || std::string::npos != lastPos)
{ {
count++;
tokens.push_back(str.substr(lastPos, pos - lastPos)); tokens.push_back(str.substr(lastPos, pos - lastPos));
lastPos = str.find_first_not_of(delimiters, pos); lastPos = str.find_first_not_of(delimiters, pos);
pos = str.find_first_of(delimiters, lastPos); pos = str.find_first_of(delimiters, lastPos);
} }
return count;
} }
void str_split_append(const std::string& str, std::vector<std::string>& tokens, const std::string& delimiters ) int str_split_append(const std::string& str, std::vector<std::string>& tokens, const std::string& delimiters )
{ {
std::string::size_type lastPos = str.find_first_not_of(delimiters, 0); std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
std::string::size_type pos = str.find_first_of(delimiters, lastPos); std::string::size_type pos = str.find_first_of(delimiters, lastPos);
int count = 0;
while (std::string::npos != pos || std::string::npos != lastPos) while (std::string::npos != pos || std::string::npos != lastPos)
{ {
count++;
tokens.push_back(str.substr(lastPos, pos - lastPos)); tokens.push_back(str.substr(lastPos, pos - lastPos));
lastPos = str.find_first_not_of(delimiters, pos); lastPos = str.find_first_not_of(delimiters, pos);
pos = str.find_first_of(delimiters, lastPos); pos = str.find_first_of(delimiters, lastPos);
} }
return count;
} }
} // namespace ipaaca } // namespace ipaaca
......
/*
* This file is part of IPAACA, the
* "Incremental Processing Architecture
* for Artificial Conversational Agents".
*
* Copyright (c) 2009-2022 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.
*/
/**
* \file ipaaca-tester.cc
*
* \brief Multifunction tester component, C++ version
*
* This file is not used in the ipaaca library, but produces
* a separate program, if enabled in CMakeLists.txt
*
* \author Ramin Yaghoubzadeh (ryaghoubzadeh@uni-bielefeld.de)
* \date January, 2017
*/
#include <ipaaca/ipaaca.h>
#include <cstdio>
#include <iomanip>
#include <thread>
#include <chrono>
#if _WIN32 || _WIN64
double get_time_as_secs() { return 0.0; } // TODO implement time function for Windows when required
#else
#include <sys/time.h>
double get_time_as_secs() {
struct timeval tv;
if (gettimeofday(&tv, NULL)) return 0.0;
return (0.001 * ((double)tv.tv_sec * 1000000.0 + tv.tv_usec));
}
#endif
class TesterCpp {
public:
void handle_iu_inbuf(std::shared_ptr<ipaaca::IUInterface> iu, ipaaca::IUEventType etype, bool local)
{
std::cout << std::fixed << std::setprecision(3) << get_time_as_secs() << " ";
std::cout << ipaaca::iu_event_type_to_str(etype) << " category=" << iu->category() << " uid=" << iu->uid() << std::endl;
//
auto links = iu->get_all_links();
if (links.size()>0) {
std::cout << "links={" << std::endl;
for (auto kv : links) {
std::cout << "\t" << kv.first << ": [";
bool first = true;
for (const auto& lnk : kv.second) {
if (first) { first=false; } else { std::cout << ", "; }
std::cout << lnk;
}
std::cout << "]";
}
std::cout << "}" << std::endl;
}
//
std::cout << "payload={" << std::endl;
for (auto kv : iu->payload()) {
std::cout << "\t'" << kv.first << "': " << ((std::string) kv.second) << ',' << std::endl;
}
std::cout << "}" << std::endl;
if (etype == IU_ADDED) {
std::cout << "Will send a modification to a received new IU" << std::endl;
int cnt=5;
while(cnt>0) {
try {
iu->payload()["seen_by_cpp"] = true;
cnt = 0;
} catch(...) {
std::cout << "... failed, but we try more than once ..." << std::endl;
cnt--;
std::this_thread::sleep_for(std::chrono::milliseconds(20));
}
}
}
}
int run()
{
ipaaca::OutputBuffer::ptr ob = ipaaca::OutputBuffer::create("testerCpp");
ipaaca::InputBuffer::ptr ib = ipaaca::InputBuffer::create("testerCpp", std::set<std::string>{"testcategory"}); // MQTT requires # as a wildcard!
ib->set_resend(true);
ib->register_handler(IPAACA_BIND_CLASS_HANDLER(&TesterCpp::handle_iu_inbuf, this));
std::cout << "Listening for all IU events and sending a Message after 1 sec ..." << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
auto msg = ipaaca::IU::create("testcategory");
msg->payload()["hello"] = "world";
ob->add(msg);
int i = 0;
while(true) {
std::this_thread::sleep_for(std::chrono::seconds(5));
auto msg = ipaaca::Message::create("testcate2");
msg->payload()["num"] = ++i;
ob->add(msg);
}
return 0;
}
};
int main(int argc, char** argv)
{
/*
auto config = ipaaca::get_global_config(true);
for (auto it = config->begin(); it!=config->end(); ++it ) {
std::cout << it->first << "=" << it->second << std::endl;
}
exit(1);
*/
ipaaca::__ipaaca_static_option_log_level = IPAACA_LOG_LEVEL_DEBUG;
TesterCpp tester;
tester.run();
}
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* "Incremental Processing Architecture * "Incremental Processing Architecture
* for Artificial Conversational Agents". * for Artificial Conversational Agents".
* *
* Copyright (c) 2009-2015 Social Cognitive Systems Group * Copyright (c) 2009-2022 Social Cognitive Systems Group
* (formerly the Sociable Agents Group) * (formerly the Sociable Agents Group)
* CITEC, Bielefeld University * CITEC, Bielefeld University
* *
...@@ -38,7 +38,7 @@ namespace ipaaca { ...@@ -38,7 +38,7 @@ namespace ipaaca {
// UUID generation // UUID generation
IPAACA_EXPORT std::string generate_uuid_string()//{{{ IPAACA_EXPORT std::string generate_uuid_string()//{{{
{ {
#ifdef WIN32 #if _WIN32 || _WIN64
// Windows // Windows
UUID uuid; UUID uuid;
RPC_STATUS stat; RPC_STATUS stat;
...@@ -51,6 +51,7 @@ IPAACA_EXPORT std::string generate_uuid_string()//{{{ ...@@ -51,6 +51,7 @@ IPAACA_EXPORT std::string generate_uuid_string()//{{{
RpcStringFree(&uuid_str); RpcStringFree(&uuid_str);
return result; return result;
} }
throw UUIDGenerationError();
} else { } else {
throw UUIDGenerationError(); throw UUIDGenerationError();
} }
...@@ -74,18 +75,12 @@ IPAACA_EXPORT std::string generate_uuid_string()//{{{ ...@@ -74,18 +75,12 @@ IPAACA_EXPORT std::string generate_uuid_string()//{{{
IPAACA_EXPORT std::string __ipaaca_static_option_default_payload_type("JSON"); IPAACA_EXPORT std::string __ipaaca_static_option_default_payload_type("JSON");
IPAACA_EXPORT std::string __ipaaca_static_option_default_channel("default"); IPAACA_EXPORT std::string __ipaaca_static_option_default_channel("default");
IPAACA_EXPORT unsigned int __ipaaca_static_option_log_level(IPAACA_LOG_LEVEL_WARNING);
/* IPAACA_EXPORT std::string __ipaaca_static_option_rsb_host("");
void init_inprocess_too() { IPAACA_EXPORT std::string __ipaaca_static_option_rsb_port("");
//ParticipantConfig config = getFactory().getDefaultParticipantConfig(); IPAACA_EXPORT std::string __ipaaca_static_option_rsb_transport("");
ParticipantConfig config = ParticipantConfig::fromFile("rsb.cfg"); IPAACA_EXPORT std::string __ipaaca_static_option_rsb_socketserver("");
//ParticipantConfig::Transport inprocess = config.getTransport("inprocess");
//inprocess.setEnabled(true);
//config.addTransport(inprocess);
getFactory().setDefaultParticipantConfig(config);
}
*/
} // of namespace ipaaca } // of namespace ipaaca
......
...@@ -3,8 +3,9 @@ ...@@ -3,8 +3,9 @@
* "Incremental Processing Architecture * "Incremental Processing Architecture
* for Artificial Conversational Agents". * for Artificial Conversational Agents".
* *
* Copyright (c) 2009-2013 Sociable Agents Group * Copyright (c) 2009-2022 Social Cognitive Systems Group
* CITEC, Bielefeld University * (formerly the Sociable Agents Group)
* CITEC, Bielefeld University
* *
* http://opensource.cit-ec.de/projects/ipaaca/ * http://opensource.cit-ec.de/projects/ipaaca/
* http://purl.org/net/ipaaca * http://purl.org/net/ipaaca
...@@ -29,7 +30,16 @@ ...@@ -29,7 +30,16 @@
* Forschungsgemeinschaft (DFG) in the context of the German * Forschungsgemeinschaft (DFG) in the context of the German
* Excellence Initiative. * Excellence Initiative.
*/ */
/**
* \file util/notifier.cc
*
* \brief Component notification (i.e. module-level introspection).
*
* \author Ramin Yaghoubzadeh (ryaghoubzadeh@uni-bielefeld.de)
* \date March, 2015
*/
#include <ipaaca/util/notifier.h> #include <ipaaca/util/notifier.h>
namespace ipaaca { namespace ipaaca {
...@@ -71,20 +81,19 @@ ComponentNotifier::ptr ComponentNotifier::create(const std::string& componentNam ...@@ -71,20 +81,19 @@ ComponentNotifier::ptr ComponentNotifier::create(const std::string& componentNam
void ComponentNotifier::handle_iu_event(IUInterface::ptr iu, IUEventType event_type, bool local) void ComponentNotifier::handle_iu_event(IUInterface::ptr iu, IUEventType event_type, bool local)
{ {
//std::cout << "handle_iu_event: got an event" << std::endl;
if ((event_type == IU_ADDED) || (event_type == IU_UPDATED) || (event_type == IU_MESSAGE)) { if ((event_type == IU_ADDED) || (event_type == IU_UPDATED) || (event_type == IU_MESSAGE)) {
Locker locker(lock); Locker locker(lock);
IPAACA_DEBUG("Received a componentNotify")
std::string cName = iu->payload()[_IPAACA_COMP_NOTIF_NAME]; std::string cName = iu->payload()[_IPAACA_COMP_NOTIF_NAME];
std::string cState = iu->payload()[_IPAACA_COMP_NOTIF_STATE]; std::string cState = iu->payload()[_IPAACA_COMP_NOTIF_STATE];
if (cName != name) { if (cName != name) {
//std::cout << " handle_iu_event: calling notification handlers" << std::endl;
// call all registered notification handlers // call all registered notification handlers
for (std::vector<IUEventHandlerFunction>::iterator it = _handlers.begin(); it != _handlers.end(); ++it) { for (std::vector<IUEventHandlerFunction>::iterator it = _handlers.begin(); it != _handlers.end(); ++it) {
(*it)(iu, event_type, local); (*it)(iu, event_type, local);
} }
// send own info only if the remote component is a newly initialized one // send own info only if the remote component is a newly initialized one
if (cState=="new") { if (cState=="new") {
//std::cout << " handle_iu_event: Submitting own notification to new remote end" << std::endl; //IPAACA_DEBUG("Submitting own componentNotify for new remote component")
submit_notify(_IPAACA_COMP_NOTIF_STATE_OLD); submit_notify(_IPAACA_COMP_NOTIF_STATE_OLD);
} }
} }
...@@ -106,14 +115,14 @@ void ComponentNotifier::submit_notify(const std::string& current_state) ...@@ -106,14 +115,14 @@ void ComponentNotifier::submit_notify(const std::string& current_state)
iu->payload()[_IPAACA_COMP_NOTIF_SEND_CATS] = send_categories; iu->payload()[_IPAACA_COMP_NOTIF_SEND_CATS] = send_categories;
iu->payload()[_IPAACA_COMP_NOTIF_RECV_CATS] = recv_categories; iu->payload()[_IPAACA_COMP_NOTIF_RECV_CATS] = recv_categories;
out_buf->add(iu); out_buf->add(iu);
//LOG_IPAACA_CONSOLE( "Sending a ComponentNotify: " << name << " " << function << " " << current_state << " " << send_categories << " " << recv_categories ) IPAACA_DEBUG( "Sending a componentNotify: " << name << ": " << current_state << " (" << function << ", " << send_categories << ", " << recv_categories << ")" )
} }
void ComponentNotifier::initialize() { void ComponentNotifier::initialize() {
Locker locker(lock); Locker locker(lock);
if (!initialized) { if (!initialized) {
initialized = true; initialized = true;
in_buf->register_handler(boost::bind(&ComponentNotifier::handle_iu_event, this, _1, _2, _3)); in_buf->register_handler(std::bind(&ComponentNotifier::handle_iu_event, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
submit_notify(_IPAACA_COMP_NOTIF_STATE_NEW); submit_notify(_IPAACA_COMP_NOTIF_STATE_NEW);
} }
} }
......
...@@ -3,13 +3,16 @@ cmake_minimum_required (VERSION 2.6) ...@@ -3,13 +3,16 @@ cmake_minimum_required (VERSION 2.6)
# project name # project name
project (ipaaca_cpp_test) project (ipaaca_cpp_test)
# use C++11 (starting with proto v2 / ipaaca-c++ release 12)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
## use the following line to enable console debug messages in ipaaca ## use the following line to enable console debug messages in ipaaca
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DIPAACA_DEBUG_MESSAGES") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DIPAACA_DEBUG_MESSAGES")
# find cmake modules locally too # find cmake modules locally too
set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMakeModules) set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMakeModules)
find_package(Boost COMPONENTS system filesystem thread regex REQUIRED) find_package(Boost COMPONENTS system filesystem thread regex unit_test_framework REQUIRED)
link_directories(${Boost_LIBRARY_DIRS}) link_directories(${Boost_LIBRARY_DIRS})
include_directories(${Boost_INCLUDE_DIRS}) include_directories(${Boost_INCLUDE_DIRS})
...@@ -17,6 +20,9 @@ find_package(Protobuf REQUIRED) ...@@ -17,6 +20,9 @@ find_package(Protobuf REQUIRED)
link_directories(${PROTOBUF_LIBRARY_DIRS}) link_directories(${PROTOBUF_LIBRARY_DIRS})
include_directories(${PROTOBUF_INCLUDE_DIRS}) include_directories(${PROTOBUF_INCLUDE_DIRS})
# for boost unit_test to create main()
add_definitions(-DBOOST_TEST_DYN_LINK)
#set(RSBLIBS rsc rsbcore) #set(RSBLIBS rsc rsbcore)
set(LIBS ${LIBS} ipaaca ) set(LIBS ${LIBS} ipaaca )
...@@ -72,3 +78,7 @@ install ( ...@@ -72,3 +78,7 @@ install (
ARCHIVE DESTINATION lib ARCHIVE DESTINATION lib
) )
enable_testing()
add_test(TestIpaacaCpp testipaaca)
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* "Incremental Processing Architecture * "Incremental Processing Architecture
* for Artificial Conversational Agents". * for Artificial Conversational Agents".
* *
* Copyright (c) 2009-2013 Sociable Agents Group * Copyright (c) 2009-2022 Sociable Agents Group
* CITEC, Bielefeld University * CITEC, Bielefeld University
* *
* http://opensource.cit-ec.de/projects/ipaaca/ * http://opensource.cit-ec.de/projects/ipaaca/
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* "Incremental Processing Architecture * "Incremental Processing Architecture
* for Artificial Conversational Agents". * for Artificial Conversational Agents".
* *
* Copyright (c) 2009-2013 Sociable Agents Group * Copyright (c) 2009-2022 Sociable Agents Group
* CITEC, Bielefeld University * CITEC, Bielefeld University
* *
* http://opensource.cit-ec.de/projects/ipaaca/ * http://opensource.cit-ec.de/projects/ipaaca/
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* "Incremental Processing Architecture * "Incremental Processing Architecture
* for Artificial Conversational Agents". * for Artificial Conversational Agents".
* *
* Copyright (c) 2009-2013 Sociable Agents Group * Copyright (c) 2009-2022 Sociable Agents Group
* CITEC, Bielefeld University * CITEC, Bielefeld University
* *
* http://opensource.cit-ec.de/projects/ipaaca/ * http://opensource.cit-ec.de/projects/ipaaca/
...@@ -33,121 +33,90 @@ ...@@ -33,121 +33,90 @@
#include <ipaaca/ipaaca.h> #include <ipaaca/ipaaca.h>
#include <typeinfo> #include <typeinfo>
using namespace ipaaca; #define BOOST_TEST_MODULE TestIpaacaCpp
#include <boost/test/unit_test.hpp>
const char RECV_CATEGORY[] = "WORD"; using namespace ipaaca;
const char SEND_CATEGORY[] = "TEXT";
class TextSender { class TestReceiver {
protected:
OutputBuffer::ptr _ob;
InputBuffer::ptr _ib;
public: public:
TextSender(); InputBuffer::ptr _ib;
void outbuffer_handle_iu_event(IUInterface::ptr iu, IUEventType event_type, bool local); std::string received_info;
TestReceiver();
void inbuffer_handle_iu_event(IUInterface::ptr iu, IUEventType event_type, bool local); void inbuffer_handle_iu_event(IUInterface::ptr iu, IUEventType event_type, bool local);
IUInterface::ptr find_last_iu();
void publish_text_to_print(const std::string& text, const std::string& parent_iu_uid="");
}; };
TextSender::TextSender() { TestReceiver::TestReceiver()
_ob = OutputBuffer::create("TextSenderOut"); {
_ob->register_handler(boost::bind(&TextSender::outbuffer_handle_iu_event, this, _1, _2, _3)); _ib = ipaaca::InputBuffer::create("TestReceiver", "cppTestCategory");
_ib = InputBuffer::create("TextSenderIn", RECV_CATEGORY); _ib->register_handler(boost::bind(&TestReceiver::inbuffer_handle_iu_event, this, _1, _2, _3));
_ib->register_handler(boost::bind(&TextSender::inbuffer_handle_iu_event, this, _1, _2, _3)); received_info = "NOTHING RECEIVED YET";
} }
void TextSender::outbuffer_handle_iu_event(IUInterface::ptr iu, IUEventType event_type, bool local) void TestReceiver::inbuffer_handle_iu_event(IUInterface::ptr iu, IUEventType event_type, bool local)
{ {
std::cout << "(own IU event " << iu_event_type_to_str(event_type) << " " << iu->uid() << ")" << std::endl; if (event_type == IU_ADDED) {
if (event_type == IU_UPDATED) { received_info = (std::string) iu->payload()["word"];
std::set<std::string> parent_uids = iu->get_links("GRIN"); {
if (parent_uids.size() > 0) { ipaaca::Locker locker(iu->payload());
std::string parent_uid = *(parent_uids.begin()); iu->payload()["replyVector"] = std::vector<double> { 1.0, 2.0, 3.0 };
std::cout << "updating parent ..." << std::endl; iu->payload()["replyComment"] = "OK";
std::set<std::string> next_uids = iu->get_links("SUCCESSOR");
if (next_uids.size() > 0) {
std::string next_uid = *(next_uids.begin());
IUInterface::ptr next_iu = _ob->get(next_uid);
std::set<std::string> next_letter_grin_links = next_iu->get_links("GRIN");
if (next_letter_grin_links.count(parent_uid) == 0) {
// next letter belongs to new word
IUInterface::ptr parent_iu = _ib->get(parent_uid);
parent_iu->payload()["STATE"] = "REALIZED";
} else {
IUInterface::ptr parent_iu = _ib->get(parent_uid);
parent_iu->payload()["STATE"] = "STARTED";
}
} else {
// there are no more letters, this is the end of the final word
IUInterface::ptr parent_iu = _ib->get(parent_uid);
parent_iu->payload()["STATE"] = "REALIZED";
}
std::cout << " ... done." << std::endl;
} }
} else {
} }
} }
void TextSender::inbuffer_handle_iu_event(IUInterface::ptr iu, IUEventType event_type, bool local)
{ class TestSender {
if (event_type == IU_LINKSUPDATED) { public:
std::cout << "links updated" << std::endl; OutputBuffer::ptr _ob;
} else if (event_type == IU_ADDED) { std::vector<double> double_vec;
std::string word = iu->payload()["WORD"]; std::string comment;
std::cout << "Received new word: " << word << std::endl; long num_replies;
publish_text_to_print(word, iu->uid()); TestSender();
} else if (event_type == IU_RETRACTED) { void publish_one_message();
std::string retracted_uid = iu->uid(); void outbuffer_handle_iu_event(IUInterface::ptr iu, IUEventType event_type, bool local);
} else { };
std::cout << "(IU event " << iu_event_type_to_str(event_type) << " " << iu->uid() << ")" << std::endl;
} TestSender::TestSender() {
_ob = OutputBuffer::create("TestSender");
_ob->register_handler(boost::bind(&TestSender::outbuffer_handle_iu_event, this, _1, _2, _3));
comment = "NO COMMENT YET";
num_replies = 0;
} }
IUInterface::ptr TextSender::find_last_iu() { void TestSender::outbuffer_handle_iu_event(IUInterface::ptr iu, IUEventType event_type, bool local)
std::set<IUInterface::ptr> ius = _ob->get_ius(); {
for (std::set<IUInterface::ptr>::iterator it = ius.begin(); it!=ius.end(); ++it) { if (event_type == IU_UPDATED) {
if ((*it)->get_links("SUCCESSOR").size() == 0) return *it; num_replies++;
double_vec = iu->payload()["replyVector"];
comment = (std::string) iu->payload()["replyComment"];
} }
return IUInterface::ptr();
} }
void TextSender::publish_text_to_print(const std::string& text, const std::string& parent_iu_uid) { void TestSender::publish_one_message()
IUInterface::ptr previous_iu = find_last_iu(); {
if (previous_iu) { ipaaca::IU::ptr iu = ipaaca::IU::create("cppTestCategory");
// insert a blank if we already have words in the buffer iu->payload()["word"] = "OK";
IU::ptr iu = IU::create( SEND_CATEGORY ); _ob->add(iu);
iu->payload()["CONTENT"] = " ";
_ob->add(iu);
previous_iu->add_link( "SUCCESSOR", iu->uid() );
iu->add_link( "PREDECESSOR", previous_iu->uid() );
if (parent_iu_uid != "") iu->add_link( "GRIN", parent_iu_uid );
previous_iu = iu;
}
for (int i=0; i<text.size(); ++i) {
IU::ptr iu = IU::create( SEND_CATEGORY );
iu->payload()["CONTENT"] = std::string(1, text.at(i));
_ob->add(iu);
if (previous_iu) {
previous_iu->add_link( "SUCCESSOR", iu->uid() );
iu->add_link( "PREDECESSOR", previous_iu->uid() );
if (parent_iu_uid != "") iu->add_link( "GRIN", parent_iu_uid );
}
if (previous_iu) std::cout << "previous IU: " << *previous_iu << std::endl;
previous_iu = iu;
}
} }
int main() { BOOST_AUTO_TEST_SUITE (testIpaacaCpp)
TextSender sender;
BOOST_AUTO_TEST_CASE( testIpaacaCpp01 )
{
TestSender sender;
TestReceiver receiver;
std::cout << "Publishing one message and waiting 1s for replies from other module." << std::endl;
sender.publish_one_message();
sleep(1); sleep(1);
sender.publish_text_to_print("(INIT)"); std::cout << "Checking for changes." << std::endl;
std::cout << "Press Ctrl-C to cancel..." << std::endl; BOOST_CHECK( receiver.received_info == "OK" );
while (true) sleep(1); BOOST_CHECK( sender.num_replies == 1 );
BOOST_CHECK( sender.comment == "OK" );
BOOST_CHECK( sender.double_vec.size() == 3 );
std::cout << "Complete." << std::endl;
} }
int old_main() { BOOST_AUTO_TEST_SUITE_END( )
std::cerr << "TODO: implement Ipaaca C++ test cases." << std::endl;
return 0;
}
...@@ -6,3 +6,4 @@ dist ...@@ -6,3 +6,4 @@ dist
privateprops privateprops
.project .project
.classpath .classpath
/bin/
...@@ -6,5 +6,6 @@ run.jvmargs= -Xms128m -Xmx512m -Xss5M ...@@ -6,5 +6,6 @@ run.jvmargs= -Xms128m -Xmx512m -Xss5M
rebuild.list= rebuild.list=
publish.resolver=asap.sftp.publish publish.resolver=asap.sftp.publish
dist.dir=../../dist dist.dir=../../dist
javac.source=1.6 javac.source=1.8
javac.target=1.6 javac.target=1.8
...@@ -6,8 +6,9 @@ ...@@ -6,8 +6,9 @@
<dependencies> <dependencies>
<dependency org="slf4j" name="slf4j-api" rev="latest.release" /> <dependency org="slf4j" name="slf4j-api" rev="latest.release" />
<dependency org="google" name="guava" rev="latest.release" /> <dependency org="google" name="guava" rev="latest.release" />
<dependency org="google" name="protobuf-java" rev="latest.release" /> <dependency org="google" name="protobuf-java" rev="2.6.1" />
<dependency org="rsb" name="rsb" rev="latest.release" /> <dependency org="rsb" name="rsb" rev="latest.release" />
<dependency org="lombok" name="lombok" rev="latest.release" /> <dependency org="lombok" name="lombok" rev="latest.release" />
<dependency org="apache" name="commons-lang" rev="latest.release" />
</dependencies> </dependencies>
</ivy-module> </ivy-module>
[transport.spread]
host = localhost # default type is string
port = 4803 # types can be specified in angle brackets
enabled = true
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
package ipaaca; package ipaaca;
import ipaaca.protobuf.Ipaaca.IU;
import ipaaca.protobuf.Ipaaca.PayloadItem; import ipaaca.protobuf.Ipaaca.PayloadItem;
import java.util.ArrayList; import java.util.ArrayList;
...@@ -57,10 +58,13 @@ public abstract class AbstractIU ...@@ -57,10 +58,13 @@ public abstract class AbstractIU
protected Payload payload; protected Payload payload;
protected String category; protected String category;
protected boolean committed = false; protected boolean committed = false;
protected boolean retracted = false;
private String uid; private String uid;
protected int revision; protected long revision;
private boolean readOnly = false; private boolean readOnly = false;
public abstract IU.AccessMode getAccessMode();
protected SetMultimap<String, String> links = HashMultimap.create(); protected SetMultimap<String, String> links = HashMultimap.create();
private final SetMultimap<String, String> EMPTYLINKS = HashMultimap.create(); private final SetMultimap<String, String> EMPTYLINKS = HashMultimap.create();
...@@ -146,7 +150,7 @@ public abstract class AbstractIU ...@@ -146,7 +150,7 @@ public abstract class AbstractIU
this.readOnly = readOnly; this.readOnly = readOnly;
} }
public void setRevision(int revision) public void setRevision(long revision)
{ {
this.revision = revision; this.revision = revision;
} }
...@@ -186,7 +190,7 @@ public abstract class AbstractIU ...@@ -186,7 +190,7 @@ public abstract class AbstractIU
return buffer; return buffer;
} }
public int getRevision() public long getRevision()
{ {
return revision; return revision;
} }
...@@ -201,6 +205,11 @@ public abstract class AbstractIU ...@@ -201,6 +205,11 @@ public abstract class AbstractIU
return committed; return committed;
} }
public boolean isRetracted()
{
return retracted;
}
public void setBuffer(Buffer buffer) public void setBuffer(Buffer buffer)
{ {
this.buffer = buffer; this.buffer = buffer;
...@@ -218,6 +227,8 @@ public abstract class AbstractIU ...@@ -218,6 +227,8 @@ public abstract class AbstractIU
public abstract void commit(); public abstract void commit();
public abstract void retract();
// XXX: might not be valid for all types of IUs // XXX: might not be valid for all types of IUs
public abstract void commit(String writerName); public abstract void commit(String writerName);
......
...@@ -38,6 +38,8 @@ import java.util.List; ...@@ -38,6 +38,8 @@ import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import ipaaca.Initializer;
/** /**
* Base class for InputBuffer and OutputBuffer. * Base class for InputBuffer and OutputBuffer.
*/ */
...@@ -85,6 +87,7 @@ public abstract class Buffer ...@@ -85,6 +87,7 @@ public abstract class Buffer
*/ */
public Buffer(String owningComponentName) public Buffer(String owningComponentName)
{ {
Initializer.initializeIpaacaRsb();
this.owningComponentName = owningComponentName; this.owningComponentName = owningComponentName;
uniqueName = "undef-" + uuid; uniqueName = "undef-" + uuid;
} }
...@@ -107,6 +110,11 @@ public abstract class Buffer ...@@ -107,6 +110,11 @@ public abstract class Buffer
{ {
eventHandlers.add(handler); eventHandlers.add(handler);
} }
public void removeHandler(IUEventHandler handler)
{
eventHandlers.remove(handler);
}
public void registerHandler(HandlerFunctor func) { public void registerHandler(HandlerFunctor func) {
IUEventHandler handler; IUEventHandler handler;
......