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 1840 additions and 1122 deletions
/*
* 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.
*/
#include <ipaaca/ipaaca.h>
namespace ipaaca {
// static library Initializer
IPAACA_EXPORT bool Initializer::_initialized = false;
IPAACA_EXPORT bool Initializer::initialized() { return _initialized; }
IPAACA_EXPORT void Initializer::initialize_ipaaca_rsb_if_needed()
{
initialize_backend();
}
IPAACA_EXPORT void Initializer::initialize_backend()//{{{
{
if (_initialized) return;
override_env_with_cmdline_set_variables();
_initialized = true;
}//}}}
IPAACA_EXPORT void Initializer::dump_current_default_config()//{{{
{
IPAACA_INFO("--- Dumping current global configuration ---")
auto cfg = ipaaca::get_global_config();
for (auto it = cfg->data_cbegin(); it != cfg->data_cend(); ++it) {
IPAACA_INFO("--- " << it->first << " = \"" << it->second << "\"")
}
IPAACA_INFO("-------------- End of config ---------------")
}//}}}
IPAACA_EXPORT void Initializer::override_env_with_cmdline_set_variables()//{{{
{
// set RSB host and port iff provided using cmdline arguments
if (__ipaaca_static_option_rsb_host!="") {
IPAACA_INFO("Overriding RSB host with " << __ipaaca_static_option_rsb_host)
IPAACA_SETENV("RSB_TRANSPORT_SPREAD_HOST", __ipaaca_static_option_rsb_host.c_str())
IPAACA_SETENV("RSB_TRANSPORT_SOCKET_HOST", __ipaaca_static_option_rsb_host.c_str());
}
if (__ipaaca_static_option_rsb_port!="") {
IPAACA_INFO("Overriding RSB port with " << __ipaaca_static_option_rsb_port)
IPAACA_SETENV("RSB_TRANSPORT_SPREAD_PORT", __ipaaca_static_option_rsb_port.c_str());
IPAACA_SETENV("RSB_TRANSPORT_SOCKET_PORT", __ipaaca_static_option_rsb_port.c_str());
}
if (__ipaaca_static_option_rsb_transport!="") {
if (__ipaaca_static_option_rsb_transport == "spread") {
IPAACA_INFO("Overriding RSB transport mode - using 'spread' ")
IPAACA_SETENV("RSB_TRANSPORT_SPREAD_ENABLED", "1");
IPAACA_SETENV("RSB_TRANSPORT_SOCKET_ENABLED", "0");
} else if (__ipaaca_static_option_rsb_transport == "socket") {
IPAACA_INFO("Overriding RSB transport mode - using 'socket' ")
IPAACA_SETENV("RSB_TRANSPORT_SPREAD_ENABLED", "0");
IPAACA_SETENV("RSB_TRANSPORT_SOCKET_ENABLED", "1");
if (__ipaaca_static_option_rsb_socketserver!="") {
const std::string& srv = __ipaaca_static_option_rsb_socketserver;
if ((srv=="1")||(srv=="0")||(srv=="auto")) {
IPAACA_INFO("Overriding RSB transport.socket.server with " << srv)
IPAACA_SETENV("RSB_TRANSPORT_SOCKET_SERVER", srv.c_str());
} else {
IPAACA_INFO("Unknown RSB transport.socket.server mode " << srv << " - using config default ")
}
}
} else {
IPAACA_INFO("Unknown RSB transport mode " << __ipaaca_static_option_rsb_transport << " - using config default ")
}
}
}//}}}
} // of namespace ipaaca
/*
* This file is part of IPAACA, the
* "Incremental Processing Architecture
* for Artificial Conversational Agents".
*
* Copyright (c) 2009-2015 Social Cognitive Systems Group
* (formerly the Sociable Agents Group)
* CITEC, Bielefeld University
*
* http://opensource.cit-ec.de/projects/ipaaca/
* http://purl.org/net/ipaaca
*
* This file may be licensed under the terms of of the
* GNU Lesser General Public License Version 3 (the ``LGPL''),
* or (at your option) any later version.
*
* Software distributed under the License is distributed
* on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
* express or implied. See the LGPL for the specific language
* governing rights and limitations.
*
* You should have received a copy of the LGPL along with this
* program. If not, go to http://www.gnu.org/licenses/lgpl.html
* or write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The development of this software was supported by the
* Excellence Cluster EXC 277 Cognitive Interaction Technology.
* The Excellence Cluster EXC 277 is a grant of the Deutsche
* Forschungsgemeinschaft (DFG) in the context of the German
* Excellence Initiative.
*/
#include <ipaaca/ipaaca.h>
namespace ipaaca {
using namespace rsb;
using namespace rsb::filter;
using namespace rsb::converter;
using namespace rsb::patterns;
// static library Initializer
IPAACA_EXPORT bool Initializer::_initialized = false;
IPAACA_EXPORT bool Initializer::initialized() { return _initialized; }
IPAACA_EXPORT void Initializer::initialize_ipaaca_rsb_if_needed()//{{{
{
if (_initialized) return;
//IPAACA_INFO("Calling initialize_updated_default_config()")
initialize_updated_default_config();
// RYT FIXME This configuration stuff has been simply removed in rsb!
//ParticipantConfig config = ParticipantConfig::fromConfiguration();
//getFactory().setDefaultParticipantConfig(config);
//IPAACA_INFO("Creating and registering Converters")
boost::shared_ptr<IUConverter> iu_converter(new IUConverter());
converterRepository<std::string>()->registerConverter(iu_converter);
boost::shared_ptr<MessageConverter> message_converter(new MessageConverter());
converterRepository<std::string>()->registerConverter(message_converter);
boost::shared_ptr<IUPayloadUpdateConverter> payload_update_converter(new IUPayloadUpdateConverter());
converterRepository<std::string>()->registerConverter(payload_update_converter);
boost::shared_ptr<IULinkUpdateConverter> link_update_converter(new IULinkUpdateConverter());
converterRepository<std::string>()->registerConverter(link_update_converter);
boost::shared_ptr<ProtocolBufferConverter<protobuf::IUCommission> > iu_commission_converter(new ProtocolBufferConverter<protobuf::IUCommission> ());
converterRepository<std::string>()->registerConverter(iu_commission_converter);
// dlw
boost::shared_ptr<ProtocolBufferConverter<protobuf::IUResendRequest> > iu_resendrequest_converter(new ProtocolBufferConverter<protobuf::IUResendRequest> ());
converterRepository<std::string>()->registerConverter(iu_resendrequest_converter);
boost::shared_ptr<ProtocolBufferConverter<protobuf::IURetraction> > iu_retraction_converter(new ProtocolBufferConverter<protobuf::IURetraction> ());
converterRepository<std::string>()->registerConverter(iu_retraction_converter);
boost::shared_ptr<IntConverter> int_converter(new IntConverter());
converterRepository<std::string>()->registerConverter(int_converter);
//IPAACA_INFO("Initialization complete.")
_initialized = true;
//IPAACA_TODO("initialize all converters")
}//}}}
IPAACA_EXPORT void Initializer::dump_current_default_config()//{{{
{
IPAACA_INFO("--- Dumping current default participant configuration ---")
rsb::ParticipantConfig config = getFactory().getDefaultParticipantConfig();
std::set<rsb::ParticipantConfig::Transport> transports = config.getTransports();
for (std::set<rsb::ParticipantConfig::Transport>::const_iterator it=transports.begin(); it!=transports.end(); ++it) {
IPAACA_INFO( "Active transport: " << it->getName() )
}
IPAACA_INFO("--- End of configuration dump ---")
//ParticipantConfig::Transport inprocess = config.getTransport("inprocess");
//inprocess.setEnabled(true);
//config.addTransport(inprocess);
}//}}}
IPAACA_EXPORT void Initializer::initialize_updated_default_config()//{{{
{
// quick hack to iterate through the pwd parents
// and find the closest rsb plugin dir
//
// but only if not yet defined
const char* plugin_path = getenv("RSB_PLUGINS_CPP_PATH");
if (!plugin_path) {
#ifdef WIN32
LOG_IPAACA_CONSOLE("WARNING: RSB_PLUGINS_CPP_PATH not set - in Windows it has to be specified.")
//throw NotImplementedError();
#else
LOG_IPAACA_CONSOLE("RSB_PLUGINS_CPP_PATH not set; looking here and up to 7 dirs up.")
std::string pathstr = "./";
for (int i=0; i< 8 /* depth EIGHT (totally arbitrary..) */ ; i++) {
std::string where_str = pathstr+"deps/lib/rsb*/plugins";
const char* where = where_str.c_str();
glob_t g;
glob(where, 0, NULL, &g);
if (g.gl_pathc>0) {
const char* found_path = g.gl_pathv[0];
LOG_IPAACA_CONSOLE("Found an RSB plugin dir which will be used automatically: " << found_path)
setenv("RSB_PLUGINS_CPP_PATH", found_path, 1);
break;
} // else keep going
globfree(&g);
pathstr += "../";
}
#endif
} else {
LOG_IPAACA_CONSOLE("RSB_PLUGINS_CPP_PATH already defined: " << plugin_path)
}
}//}}}
// RSB backend Converters
// IUConverter//{{{
IPAACA_EXPORT IUConverter::IUConverter()
: Converter<std::string> (IPAACA_SYSTEM_DEPENDENT_CLASS_NAME("ipaaca::IU"), "ipaaca-iu", true)
{
}
IPAACA_EXPORT std::string IUConverter::serialize(const AnnotatedData& data, std::string& wire)
{
//std::cout << "serialize" << std::endl;
// Ensure that DATA actually holds a datum of the data-type we expect.
assert(data.first == getDataType()); // "ipaaca::IU"
// NOTE: a dynamic_pointer_cast cannot be used from void*
boost::shared_ptr<const IU> obj = boost::static_pointer_cast<const IU> (data.second);
boost::shared_ptr<protobuf::IU> pbo(new protobuf::IU());
// transfer obj data to pbo
pbo->set_uid(obj->uid());
pbo->set_revision(obj->revision());
pbo->set_category(obj->category());
pbo->set_payload_type(obj->payload_type());
pbo->set_owner_name(obj->owner_name());
pbo->set_committed(obj->committed());
ipaaca::protobuf::IU_AccessMode a_m;
switch(obj->access_mode()) {
case IU_ACCESS_PUSH:
a_m = ipaaca::protobuf::IU_AccessMode_PUSH;
break;
case IU_ACCESS_REMOTE:
a_m = ipaaca::protobuf::IU_AccessMode_REMOTE;
break;
case IU_ACCESS_MESSAGE:
a_m = ipaaca::protobuf::IU_AccessMode_MESSAGE;
break;
}
pbo->set_access_mode(a_m);
pbo->set_read_only(obj->read_only());
// TODO JSONIZE
for (std::map<std::string, std::string>::const_iterator it=obj->_payload._store.begin(); it!=obj->_payload._store.end(); ++it) {
protobuf::PayloadItem* item = pbo->add_payload();
item->set_key(it->first);
item->set_value(it->second);
item->set_type("str"); // FIXME other types than str (later)
}
for (LinkMap::const_iterator it=obj->_links._links.begin(); it!=obj->_links._links.end(); ++it) {
protobuf::LinkSet* links = pbo->add_links();
links->set_type(it->first);
for (std::set<std::string>::const_iterator it2=it->second.begin(); it2!=it->second.end(); ++it2) {
links->add_targets(*it2);
}
}
pbo->SerializeToString(&wire);
switch(obj->access_mode()) {
case IU_ACCESS_PUSH:
//std::cout << "Requesting to send as ipaaca-iu" << std::endl;
return "ipaaca-iu";
case IU_ACCESS_MESSAGE:
//std::cout << "Requesting to send as ipaaca-messageiu" << std::endl;
return "ipaaca-messageiu";
default:
//std::cout << "Requesting to send as default" << std::endl;
return getWireSchema();
}
}
IPAACA_EXPORT AnnotatedData IUConverter::deserialize(const std::string& wireSchema, const std::string& wire) {
//std::cout << "deserialize" << std::endl;
assert(wireSchema == getWireSchema()); // "ipaaca-iu"
boost::shared_ptr<protobuf::IU> pbo(new protobuf::IU());
pbo->ParseFromString(wire);
IUAccessMode mode = static_cast<IUAccessMode>(pbo->access_mode());
switch(mode) {
case IU_ACCESS_PUSH:
{
// Create a "remote push IU"
boost::shared_ptr<RemotePushIU> obj = RemotePushIU::create();
// transfer pbo data to obj
obj->_uid = pbo->uid();
obj->_revision = pbo->revision();
obj->_category = pbo->category();
obj->_payload_type = pbo->payload_type();
obj->_owner_name = pbo->owner_name();
obj->_committed = pbo->committed();
obj->_read_only = pbo->read_only();
obj->_access_mode = IU_ACCESS_PUSH;
// TODO JSONIZE
for (int i=0; i<pbo->payload_size(); i++) {
const protobuf::PayloadItem& it = pbo->payload(i);
obj->_payload._store[it.key()] = it.value();
}
for (int i=0; i<pbo->links_size(); i++) {
const protobuf::LinkSet& pls = pbo->links(i);
LinkSet& ls = obj->_links._links[pls.type()];
for (int j=0; j<pls.targets_size(); j++) {
ls.insert(pls.targets(j));
}
}
//return std::make_pair(getDataType(), obj);
return std::make_pair("ipaaca::RemotePushIU", obj);
break;
}
case IU_ACCESS_MESSAGE:
{
// Create a "Message-type IU"
boost::shared_ptr<RemoteMessage> obj = RemoteMessage::create();
//std::cout << "REFCNT after create: " << obj.use_count() << std::endl;
// transfer pbo data to obj
obj->_uid = pbo->uid();
obj->_revision = pbo->revision();
obj->_category = pbo->category();
obj->_payload_type = pbo->payload_type();
obj->_owner_name = pbo->owner_name();
obj->_committed = pbo->committed();
obj->_read_only = pbo->read_only();
obj->_access_mode = IU_ACCESS_MESSAGE;
// TODO JSONIZE
for (int i=0; i<pbo->payload_size(); i++) {
const protobuf::PayloadItem& it = pbo->payload(i);
obj->_payload._store[it.key()] = it.value();
}
for (int i=0; i<pbo->links_size(); i++) {
const protobuf::LinkSet& pls = pbo->links(i);
LinkSet& ls = obj->_links._links[pls.type()];
for (int j=0; j<pls.targets_size(); j++) {
ls.insert(pls.targets(j));
}
}
//return std::make_pair(getDataType(), obj);
return std::make_pair("ipaaca::RemoteMessage", obj);
break;
}
default:
// other cases not handled yet! ( TODO )
throw NotImplementedError();
}
}
//}}}
// MessageConverter//{{{
IPAACA_EXPORT MessageConverter::MessageConverter()
: Converter<std::string> (IPAACA_SYSTEM_DEPENDENT_CLASS_NAME("ipaaca::Message"), "ipaaca-messageiu", true)
{
}
IPAACA_EXPORT std::string MessageConverter::serialize(const AnnotatedData& data, std::string& wire)
{
// Ensure that DATA actually holds a datum of the data-type we expect.
assert(data.first == getDataType()); // "ipaaca::Message"
// NOTE: a dynamic_pointer_cast cannot be used from void*
boost::shared_ptr<const Message> obj = boost::static_pointer_cast<const Message> (data.second);
boost::shared_ptr<protobuf::IU> pbo(new protobuf::IU());
// transfer obj data to pbo
pbo->set_uid(obj->uid());
pbo->set_revision(obj->revision());
pbo->set_category(obj->category());
pbo->set_payload_type(obj->payload_type());
pbo->set_owner_name(obj->owner_name());
pbo->set_committed(obj->committed());
ipaaca::protobuf::IU_AccessMode a_m;
switch(obj->access_mode()) {
case IU_ACCESS_PUSH:
a_m = ipaaca::protobuf::IU_AccessMode_PUSH;
break;
case IU_ACCESS_REMOTE:
a_m = ipaaca::protobuf::IU_AccessMode_REMOTE;
break;
case IU_ACCESS_MESSAGE:
a_m = ipaaca::protobuf::IU_AccessMode_MESSAGE;
break;
}
pbo->set_access_mode(a_m);
pbo->set_read_only(obj->read_only());
// TODO JSONIZE
for (std::map<std::string, std::string>::const_iterator it=obj->_payload._store.begin(); it!=obj->_payload._store.end(); ++it) {
protobuf::PayloadItem* item = pbo->add_payload();
item->set_key(it->first);
item->set_value(it->second);
item->set_type("str"); // FIXME other types than str (later)
}
for (LinkMap::const_iterator it=obj->_links._links.begin(); it!=obj->_links._links.end(); ++it) {
protobuf::LinkSet* links = pbo->add_links();
links->set_type(it->first);
for (std::set<std::string>::const_iterator it2=it->second.begin(); it2!=it->second.end(); ++it2) {
links->add_targets(*it2);
}
}
pbo->SerializeToString(&wire);
switch(obj->access_mode()) {
case IU_ACCESS_PUSH:
return "ipaaca-iu";
case IU_ACCESS_MESSAGE:
return "ipaaca-messageiu";
default:
//std::cout << "Requesting to send as default" << std::endl;
return getWireSchema();
}
}
IPAACA_EXPORT AnnotatedData MessageConverter::deserialize(const std::string& wireSchema, const std::string& wire) {
assert(wireSchema == getWireSchema()); // "ipaaca-iu"
boost::shared_ptr<protobuf::IU> pbo(new protobuf::IU());
pbo->ParseFromString(wire);
IUAccessMode mode = static_cast<IUAccessMode>(pbo->access_mode());
switch(mode) {
case IU_ACCESS_PUSH:
{
// Create a "remote push IU"
boost::shared_ptr<RemotePushIU> obj = RemotePushIU::create();
// transfer pbo data to obj
obj->_uid = pbo->uid();
obj->_revision = pbo->revision();
obj->_category = pbo->category();
obj->_payload_type = pbo->payload_type();
obj->_owner_name = pbo->owner_name();
obj->_committed = pbo->committed();
obj->_read_only = pbo->read_only();
obj->_access_mode = IU_ACCESS_PUSH;
// TODO JSONIZE
for (int i=0; i<pbo->payload_size(); i++) {
const protobuf::PayloadItem& it = pbo->payload(i);
obj->_payload._store[it.key()] = it.value();
}
for (int i=0; i<pbo->links_size(); i++) {
const protobuf::LinkSet& pls = pbo->links(i);
LinkSet& ls = obj->_links._links[pls.type()];
for (int j=0; j<pls.targets_size(); j++) {
ls.insert(pls.targets(j));
}
}
//return std::make_pair(getDataType(), obj);
return std::make_pair("ipaaca::RemotePushIU", obj);
break;
}
case IU_ACCESS_MESSAGE:
{
// Create a "Message-type IU"
boost::shared_ptr<RemoteMessage> obj = RemoteMessage::create();
// transfer pbo data to obj
obj->_uid = pbo->uid();
obj->_revision = pbo->revision();
obj->_category = pbo->category();
obj->_payload_type = pbo->payload_type();
obj->_owner_name = pbo->owner_name();
obj->_committed = pbo->committed();
obj->_read_only = pbo->read_only();
obj->_access_mode = IU_ACCESS_MESSAGE;
// TODO JSONIZE
for (int i=0; i<pbo->payload_size(); i++) {
const protobuf::PayloadItem& it = pbo->payload(i);
obj->_payload._store[it.key()] = it.value();
}
for (int i=0; i<pbo->links_size(); i++) {
const protobuf::LinkSet& pls = pbo->links(i);
LinkSet& ls = obj->_links._links[pls.type()];
for (int j=0; j<pls.targets_size(); j++) {
ls.insert(pls.targets(j));
}
}
//return std::make_pair(getDataType(), obj);
return std::make_pair("ipaaca::RemoteMessage", obj);
break;
}
default:
// other cases not handled yet! ( TODO )
throw NotImplementedError();
}
}
//}}}
// IUPayloadUpdateConverter//{{{
IPAACA_EXPORT IUPayloadUpdateConverter::IUPayloadUpdateConverter()
: Converter<std::string> (IPAACA_SYSTEM_DEPENDENT_CLASS_NAME("ipaaca::IUPayloadUpdate"), "ipaaca-iu-payload-update", true)
{
}
IPAACA_EXPORT std::string IUPayloadUpdateConverter::serialize(const AnnotatedData& data, std::string& wire)
{
assert(data.first == getDataType()); // "ipaaca::IUPayloadUpdate"
boost::shared_ptr<const IUPayloadUpdate> obj = boost::static_pointer_cast<const IUPayloadUpdate> (data.second);
boost::shared_ptr<protobuf::IUPayloadUpdate> pbo(new protobuf::IUPayloadUpdate());
// transfer obj data to pbo
pbo->set_uid(obj->uid);
pbo->set_revision(obj->revision);
pbo->set_writer_name(obj->writer_name);
pbo->set_is_delta(obj->is_delta);
// TODO JSONIZE
for (std::map<std::string, std::string>::const_iterator it=obj->new_items.begin(); it!=obj->new_items.end(); ++it) {
protobuf::PayloadItem* item = pbo->add_new_items();
item->set_key(it->first);
item->set_value(it->second);
item->set_type("str"); // FIXME other types than str (later)
}
// TODO JSONIZE
for (std::vector<std::string>::const_iterator it=obj->keys_to_remove.begin(); it!=obj->keys_to_remove.end(); ++it) {
pbo->add_keys_to_remove(*it);
}
pbo->SerializeToString(&wire);
return getWireSchema();
}
AnnotatedData IUPayloadUpdateConverter::deserialize(const std::string& wireSchema, const std::string& wire) {
assert(wireSchema == getWireSchema()); // "ipaaca-iu-payload-update"
boost::shared_ptr<protobuf::IUPayloadUpdate> pbo(new protobuf::IUPayloadUpdate());
pbo->ParseFromString(wire);
boost::shared_ptr<IUPayloadUpdate> obj(new IUPayloadUpdate());
// transfer pbo data to obj
obj->uid = pbo->uid();
obj->revision = pbo->revision();
obj->writer_name = pbo->writer_name();
obj->is_delta = pbo->is_delta();
// TODO JSONIZE
for (int i=0; i<pbo->new_items_size(); i++) {
const protobuf::PayloadItem& it = pbo->new_items(i);
obj->new_items[it.key()] = it.value();
}
// TODO JSONIZE
for (int i=0; i<pbo->keys_to_remove_size(); i++) {
obj->keys_to_remove.push_back(pbo->keys_to_remove(i));
}
return std::make_pair(getDataType(), obj);
}
//}}}
// IULinkUpdateConverter//{{{
IPAACA_EXPORT IULinkUpdateConverter::IULinkUpdateConverter()
: Converter<std::string> (IPAACA_SYSTEM_DEPENDENT_CLASS_NAME("ipaaca::IULinkUpdate"), "ipaaca-iu-link-update", true)
{
}
IPAACA_EXPORT std::string IULinkUpdateConverter::serialize(const AnnotatedData& data, std::string& wire)
{
assert(data.first == getDataType()); // "ipaaca::IULinkUpdate"
boost::shared_ptr<const IULinkUpdate> obj = boost::static_pointer_cast<const IULinkUpdate> (data.second);
boost::shared_ptr<protobuf::IULinkUpdate> pbo(new protobuf::IULinkUpdate());
// transfer obj data to pbo
pbo->set_uid(obj->uid);
pbo->set_revision(obj->revision);
pbo->set_writer_name(obj->writer_name);
pbo->set_is_delta(obj->is_delta);
for (std::map<std::string, std::set<std::string> >::const_iterator it=obj->new_links.begin(); it!=obj->new_links.end(); ++it) {
protobuf::LinkSet* links = pbo->add_new_links();
links->set_type(it->first);
for (std::set<std::string>::const_iterator it2=it->second.begin(); it2!=it->second.end(); ++it2) {
links->add_targets(*it2);
}
}
for (std::map<std::string, std::set<std::string> >::const_iterator it=obj->links_to_remove.begin(); it!=obj->links_to_remove.end(); ++it) {
protobuf::LinkSet* links = pbo->add_links_to_remove();
links->set_type(it->first);
for (std::set<std::string>::const_iterator it2=it->second.begin(); it2!=it->second.end(); ++it2) {
links->add_targets(*it2);
}
}
pbo->SerializeToString(&wire);
return getWireSchema();
}
AnnotatedData IULinkUpdateConverter::deserialize(const std::string& wireSchema, const std::string& wire) {
assert(wireSchema == getWireSchema()); // "ipaaca-iu-link-update"
boost::shared_ptr<protobuf::IULinkUpdate> pbo(new protobuf::IULinkUpdate());
pbo->ParseFromString(wire);
boost::shared_ptr<IULinkUpdate> obj(new IULinkUpdate());
// transfer pbo data to obj
obj->uid = pbo->uid();
obj->revision = pbo->revision();
obj->writer_name = pbo->writer_name();
obj->is_delta = pbo->is_delta();
for (int i=0; i<pbo->new_links_size(); ++i) {
const protobuf::LinkSet& it = pbo->new_links(i);
for (int j=0; j<it.targets_size(); ++j) {
obj->new_links[it.type()].insert(it.targets(j)); // = vec;
}
}
for (int i=0; i<pbo->links_to_remove_size(); ++i) {
const protobuf::LinkSet& it = pbo->links_to_remove(i);
for (int j=0; j<it.targets_size(); ++j) {
obj->links_to_remove[it.type()].insert(it.targets(j));
}
}
return std::make_pair(getDataType(), obj);
}
//}}}
// IntConverter//{{{
IPAACA_EXPORT IntConverter::IntConverter()
: Converter<std::string> ("int", "int32", true)
{
}
IPAACA_EXPORT std::string IntConverter::serialize(const AnnotatedData& data, std::string& wire)
{
// Ensure that DATA actually holds a datum of the data-type we expect.
assert(data.first == getDataType()); // "int"
// NOTE: a dynamic_pointer_cast cannot be used from void*
boost::shared_ptr<const int> obj = boost::static_pointer_cast<const int> (data.second);
boost::shared_ptr<protobuf::IntMessage> pbo(new protobuf::IntMessage());
// transfer obj data to pbo
pbo->set_value(*obj);
pbo->SerializeToString(&wire);
return getWireSchema();
}
IPAACA_EXPORT AnnotatedData IntConverter::deserialize(const std::string& wireSchema, const std::string& wire) {
assert(wireSchema == getWireSchema()); // "int"
boost::shared_ptr<protobuf::IntMessage> pbo(new protobuf::IntMessage());
pbo->ParseFromString(wire);
boost::shared_ptr<int> obj = boost::shared_ptr<int>(new int(pbo->value()));
return std::make_pair("int", obj);
}
//}}}
} // of namespace ipaaca
/*
* 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.
*/
#include <ipaaca/ipaaca.h>
namespace ipaaca {
IPAACA_EXPORT std::ostream& operator<<(std::ostream& os, const IUInterface& obj)//{{{
{
os << "IUInterface(uid='" << obj.uid() << "'";
os << ", category='" << obj.category() << "'";
os << ", revision=" << obj.revision();
os << ", committed=" << (obj.committed()?"True":"False");
os << ", owner_name='" << obj.owner_name() << "'";
os << ", payload=";
os << obj.const_payload();
os << ", links=";
os << obj._links;
os << ")";
return os;
}
//}}}
// IUInterface//{{{
IPAACA_EXPORT IUInterface::IUInterface()
: _buffer(NULL), _committed(false), _retracted(false)
{
}
IPAACA_EXPORT void IUInterface::_set_uid(const std::string& uid) {
if (_uid != "") {
throw IUAlreadyHasAnUIDError();
}
_uid = uid;
}
IPAACA_EXPORT void IUInterface::_set_buffer(Buffer* buffer) {
if (_buffer) {
throw IUAlreadyInABufferError();
}
_buffer = buffer;
}
IPAACA_EXPORT void IUInterface::_set_owner_name(const std::string& owner_name) {
if (_owner_name != "") {
throw IUAlreadyHasAnOwnerNameError();
}
_owner_name = owner_name;
}
/// set the buffer pointer and the owner names of IU and Payload
IPAACA_EXPORT void IUInterface::_associate_with_buffer(Buffer* buffer) {
_set_buffer(buffer); // will throw if already set
_set_owner_name(buffer->unique_name());
payload()._set_owner_name(buffer->unique_name());
}
/// C++-specific convenience function to add one single link
IPAACA_EXPORT void IUInterface::add_link(const std::string& type, const std::string& target, const std::string& writer_name)
{
LinkMap none;
LinkMap add;
add[type].insert(target);
_modify_links(true, add, none, writer_name);
_add_and_remove_links(add, none);
}
/// C++-specific convenience function to remove one single link
IPAACA_EXPORT void IUInterface::remove_link(const std::string& type, const std::string& target, const std::string& writer_name)
{
LinkMap none;
LinkMap remove;
remove[type].insert(target);
_modify_links(true, none, remove, writer_name);
_add_and_remove_links(none, remove);
}
IPAACA_EXPORT void IUInterface::add_links(const std::string& type, const LinkSet& targets, const std::string& writer_name)
{
LinkMap none;
LinkMap add;
add[type] = targets;
_modify_links(true, add, none, writer_name);
_add_and_remove_links(add, none);
}
IPAACA_EXPORT void IUInterface::remove_links(const std::string& type, const LinkSet& targets, const std::string& writer_name)
{
LinkMap none;
LinkMap remove;
remove[type] = targets;
_modify_links(true, none, remove, writer_name);
_add_and_remove_links(none, remove);
}
IPAACA_EXPORT void IUInterface::modify_links(const LinkMap& add, const LinkMap& remove, const std::string& writer_name)
{
_modify_links(true, add, remove, writer_name);
_add_and_remove_links(add, remove);
}
IPAACA_EXPORT void IUInterface::set_links(const LinkMap& links, const std::string& writer_name)
{
LinkMap none;
_modify_links(false, links, none, writer_name);
_replace_links(links);
}
IPAACA_EXPORT const std::string& IUInterface::channel()
{
if (_buffer == NULL)
throw IUUnpublishedError();
else
return _buffer->channel();
}
//}}}
} // of namespace ipaaca
......@@ -3,7 +3,7 @@
* "Incremental Processing Architecture
* 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)
* CITEC, Bielefeld University
*
......@@ -35,128 +35,14 @@
namespace ipaaca {
using namespace rsb;
using namespace rsb::filter;
using namespace rsb::converter;
using namespace rsb::patterns;
IPAACA_EXPORT std::ostream& operator<<(std::ostream& os, const IUInterface& obj)//{{{
{
os << "IUInterface(uid='" << obj.uid() << "'";
os << ", category='" << obj.category() << "'";
os << ", revision=" << obj.revision();
os << ", committed=" << (obj.committed()?"True":"False");
os << ", owner_name='" << obj.owner_name() << "'";
os << ", payload=";
os << obj.const_payload();
os << ", links=";
os << obj._links;
os << ")";
return os;
}
//}}}
// IUInterface//{{{
IPAACA_EXPORT IUInterface::IUInterface()
: _buffer(NULL), _committed(false), _retracted(false)
{
}
IPAACA_EXPORT void IUInterface::_set_uid(const std::string& uid) {
if (_uid != "") {
throw IUAlreadyHasAnUIDError();
}
_uid = uid;
}
IPAACA_EXPORT void IUInterface::_set_buffer(Buffer* buffer) { //boost::shared_ptr<Buffer> buffer) {
if (_buffer) {
throw IUAlreadyInABufferError();
}
_buffer = buffer;
}
IPAACA_EXPORT void IUInterface::_set_owner_name(const std::string& owner_name) {
if (_owner_name != "") {
throw IUAlreadyHasAnOwnerNameError();
}
_owner_name = owner_name;
}
/// set the buffer pointer and the owner names of IU and Payload
IPAACA_EXPORT void IUInterface::_associate_with_buffer(Buffer* buffer) { //boost::shared_ptr<Buffer> buffer) {
_set_buffer(buffer); // will throw if already set
_set_owner_name(buffer->unique_name());
payload()._set_owner_name(buffer->unique_name());
}
/// C++-specific convenience function to add one single link
IPAACA_EXPORT void IUInterface::add_link(const std::string& type, const std::string& target, const std::string& writer_name)
{
LinkMap none;
LinkMap add;
add[type].insert(target);
_modify_links(true, add, none, writer_name);
_add_and_remove_links(add, none);
}
/// C++-specific convenience function to remove one single link
IPAACA_EXPORT void IUInterface::remove_link(const std::string& type, const std::string& target, const std::string& writer_name)
{
LinkMap none;
LinkMap remove;
remove[type].insert(target);
_modify_links(true, none, remove, writer_name);
_add_and_remove_links(none, remove);
}
IPAACA_EXPORT void IUInterface::add_links(const std::string& type, const LinkSet& targets, const std::string& writer_name)
{
LinkMap none;
LinkMap add;
add[type] = targets;
_modify_links(true, add, none, writer_name);
_add_and_remove_links(add, none);
}
IPAACA_EXPORT void IUInterface::remove_links(const std::string& type, const LinkSet& targets, const std::string& writer_name)
{
LinkMap none;
LinkMap remove;
remove[type] = targets;
_modify_links(true, none, remove, writer_name);
_add_and_remove_links(none, remove);
}
IPAACA_EXPORT void IUInterface::modify_links(const LinkMap& add, const LinkMap& remove, const std::string& writer_name)
{
_modify_links(true, add, remove, writer_name);
_add_and_remove_links(add, remove);
}
IPAACA_EXPORT void IUInterface::set_links(const LinkMap& links, const std::string& writer_name)
{
LinkMap none;
_modify_links(false, links, none, writer_name);
_replace_links(links);
}
IPAACA_HEADER_EXPORT const std::string& IUInterface::channel()
{
if (_buffer == NULL)
throw IUUnpublishedError();
else
return _buffer->channel();
}
//}}}
// IU//{{{
IPAACA_EXPORT IU::ptr IU::create(const std::string& category, IUAccessMode access_mode, bool read_only, const std::string& payload_type)
{
IU::ptr iu = IU::ptr(new IU(category, access_mode, read_only, payload_type)); /* params */ //));
return IU::create(category, payload_type, read_only);
}
IPAACA_EXPORT IU::ptr IU::create(const std::string& category, const std::string& payload_type, bool read_only)
{
IU::ptr iu = IU::ptr(new IU(category, IU_ACCESS_PUSH, read_only, (payload_type=="")?__ipaaca_static_option_default_payload_type:payload_type)); /* params */ //));
iu->_payload.initialize(iu);
return iu;
}
......@@ -166,11 +52,12 @@ IPAACA_EXPORT IU::IU(const std::string& category, IUAccessMode access_mode, bool
_revision = 1;
_uid = ipaaca::generate_uuid_string();
_category = category;
_payload_type = payload_type;
_payload_type = (payload_type=="")?__ipaaca_static_option_default_payload_type:payload_type;
// payload initialization deferred to IU::create(), above
_read_only = read_only;
_access_mode = access_mode;
_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)
......@@ -179,6 +66,9 @@ IPAACA_EXPORT void IU::_modify_links(bool is_delta, const LinkMap& new_links, co
if (_committed) {
_revision_lock.unlock();
throw IUCommittedError();
} else if (_retracted) {
_revision_lock.unlock();
throw IURetractedError();
}
_increase_revision_number();
if (is_published()) {
......@@ -187,37 +77,29 @@ IPAACA_EXPORT void IU::_modify_links(bool is_delta, const LinkMap& new_links, co
_revision_lock.unlock();
}
IPAACA_EXPORT void IU::_publish_resend(IU::ptr iu, const std::string& hidden_scope_name)
{
//_revision_lock.lock();
//if (_committed) {
// _revision_lock.unlock();
// throw IUCommittedError();
//}
//_increase_revision_number();
//if (is_published()) {
//IUInterface* iu, bool is_delta, revision_t revision, const LinkMap& new_links, const LinkMap& links_to_remove, const std::string& writer_name
_buffer->_publish_iu_resend(iu, hidden_scope_name);
//}
//_revision_lock.unlock();
}
IPAACA_EXPORT void IU::_modify_payload(bool is_delta, const std::map<std::string, std::string>& new_items, const std::vector<std::string>& keys_to_remove, const std::string& writer_name)
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("")
_revision_lock.lock();
if (_committed) {
_revision_lock.unlock();
throw IUCommittedError();
} else if (_retracted) {
_revision_lock.unlock();
throw IURetractedError();
}
_increase_revision_number();
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);
IPAACA_DEBUG("... sent.")
}
_revision_lock.unlock();
}
......@@ -233,6 +115,9 @@ IPAACA_EXPORT void IU::_internal_commit(const std::string& writer_name)
if (_committed) {
_revision_lock.unlock();
throw IUCommittedError();
} else if (_retracted) {
_revision_lock.unlock();
throw IURetractedError();
}
_increase_revision_number();
_committed = true;
......@@ -245,7 +130,11 @@ IPAACA_EXPORT void IU::_internal_commit(const std::string& writer_name)
// Message//{{{
Message::ptr Message::create(const std::string& category, IUAccessMode access_mode, bool read_only, const std::string& payload_type)
{
Message::ptr iu = Message::ptr(new Message(category, access_mode, read_only, payload_type)); /* params */ //));
return Message::create(category, (payload_type=="")?__ipaaca_static_option_default_payload_type:payload_type);
}
Message::ptr Message::create(const std::string& category, const std::string& payload_type)
{
Message::ptr iu = Message::ptr(new Message(category, IU_ACCESS_MESSAGE, true, (payload_type=="")?__ipaaca_static_option_default_payload_type:payload_type)); /* params */ //));
iu->_payload.initialize(iu);
return iu;
}
......@@ -261,7 +150,7 @@ void Message::_modify_links(bool is_delta, const LinkMap& new_links, const LinkM
IPAACA_INFO("Info: modifying a Message after sending has no global effects")
}
}
void Message::_modify_payload(bool is_delta, const std::map<std::string, std::string>& new_items, const std::vector<std::string>& keys_to_remove, const std::string& writer_name)
void Message::_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)
{
if (is_published()) {
IPAACA_INFO("Info: modifying a Message after sending has no global effects")
......@@ -281,23 +170,23 @@ void Message::_internal_commit(const std::string& writer_name)
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);
return iu;
}
IPAACA_EXPORT RemotePushIU::RemotePushIU()
{
// nothing
}
IPAACA_EXPORT void RemotePushIU::_modify_links(bool is_delta, const LinkMap& new_links, const LinkMap& links_to_remove, const std::string& writer_name)
{
if (_committed) {
throw IUCommittedError();
}
if (_read_only) {
} else if (_retracted) {
throw IURetractedError();
} else if (_read_only) {
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());
update->uid = _uid;
update->revision = _revision;
......@@ -305,23 +194,24 @@ IPAACA_EXPORT void RemotePushIU::_modify_links(bool is_delta, const LinkMap& new
update->writer_name = _buffer->unique_name();
update->new_links = new_links;
update->links_to_remove = links_to_remove;
boost::shared_ptr<int> result = server->call<int>("updateLinks", update, IPAACA_REMOTE_SERVER_TIMEOUT); // TODO
if (*result == 0) {
int result = server->request_remote_link_update(update); // TODO
if (result == 0) {
throw IUUpdateFailedError();
} else {
_revision = *result;
_revision = result;
}
}
IPAACA_EXPORT void RemotePushIU::_modify_payload(bool is_delta, const std::map<std::string, std::string>& new_items, const std::vector<std::string>& keys_to_remove, const std::string& writer_name)
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) {
throw IUCommittedError();
}
if (_read_only) {
} else if (_retracted) {
throw IURetractedError();
} else if (_read_only) {
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());
update->uid = _uid;
update->revision = _revision;
......@@ -329,11 +219,12 @@ IPAACA_EXPORT void RemotePushIU::_modify_payload(bool is_delta, const std::map<s
update->writer_name = _buffer->unique_name();
update->new_items = new_items;
update->keys_to_remove = keys_to_remove;
boost::shared_ptr<int> result = server->call<int>("updatePayload", update, IPAACA_REMOTE_SERVER_TIMEOUT); // TODO
if (*result == 0) {
update->payload_type = _payload_type;
int result = server->request_remote_payload_update(update);
if (result == 0) {
throw IUUpdateFailedError();
} else {
_revision = *result;
_revision = result;
}
}
......@@ -341,21 +232,23 @@ IPAACA_EXPORT void RemotePushIU::commit()
{
if (_read_only) {
throw IUReadOnlyError();
} else if (_retracted) {
throw IURetractedError();
}
if (_committed) {
// Following python version: ignoring multiple commit
return;
}
RemoteServerPtr server = boost::static_pointer_cast<InputBuffer>(_buffer)->_get_remote_server(_owner_name);
boost::shared_ptr<protobuf::IUCommission> update = boost::shared_ptr<protobuf::IUCommission>(new protobuf::IUCommission());
auto server = ((InputBuffer*)_buffer)->_get_remote_server(_owner_name);
std::shared_ptr<protobuf::IUCommission> update = std::shared_ptr<protobuf::IUCommission>(new protobuf::IUCommission());
update->set_uid(_uid);
update->set_revision(_revision);
update->set_writer_name(_buffer->unique_name());
boost::shared_ptr<int> result = server->call<int>("commit", update, IPAACA_REMOTE_SERVER_TIMEOUT); // TODO
if (*result == 0) {
int result = server->request_remote_commission(update);
if (result == 0) {
throw IUUpdateFailedError();
} else {
_revision = *result;
_revision = result;
}
}
......@@ -375,12 +268,12 @@ IPAACA_EXPORT void RemotePushIU::_apply_update(IUPayloadUpdate::ptr update)
for (std::vector<std::string>::const_iterator it=update->keys_to_remove.begin(); it!=update->keys_to_remove.end(); ++it) {
_payload._remotely_enforced_delitem(*it);
}
for (std::map<std::string, std::string>::const_iterator it=update->new_items.begin(); it!=update->new_items.end(); ++it) {
for (std::map<std::string, PayloadDocumentEntry::ptr>::const_iterator it=update->new_items.begin(); it!=update->new_items.end(); ++it) {
_payload._remotely_enforced_setitem(it->first, it->second);
}
} else {
_payload._remotely_enforced_wipe();
for (std::map<std::string, std::string>::const_iterator it=update->new_items.begin(); it!=update->new_items.end(); ++it) {
for (std::map<std::string, PayloadDocumentEntry::ptr>::const_iterator it=update->new_items.begin(); it!=update->new_items.end(); ++it) {
_payload._remotely_enforced_setitem(it->first, it->second);
}
}
......@@ -399,19 +292,18 @@ IPAACA_EXPORT void RemotePushIU::_apply_retraction()
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);
return iu;
}
IPAACA_EXPORT RemoteMessage::RemoteMessage()
{
// nothing
}
IPAACA_EXPORT void RemoteMessage::_modify_links(bool is_delta, const LinkMap& new_links, const LinkMap& links_to_remove, const std::string& writer_name)
{
IPAACA_INFO("Info: modifying a RemoteMessage only has local effects")
}
IPAACA_EXPORT void RemoteMessage::_modify_payload(bool is_delta, const std::map<std::string, std::string>& new_items, const std::vector<std::string>& keys_to_remove, const std::string& writer_name)
IPAACA_EXPORT void RemoteMessage::_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("Info: modifying a RemoteMessage only has local effects")
}
......@@ -438,12 +330,12 @@ IPAACA_EXPORT void RemoteMessage::_apply_update(IUPayloadUpdate::ptr update)
for (std::vector<std::string>::const_iterator it=update->keys_to_remove.begin(); it!=update->keys_to_remove.end(); ++it) {
_payload._remotely_enforced_delitem(*it);
}
for (std::map<std::string, std::string>::const_iterator it=update->new_items.begin(); it!=update->new_items.end(); ++it) {
for (std::map<std::string, PayloadDocumentEntry::ptr>::const_iterator it=update->new_items.begin(); it!=update->new_items.end(); ++it) {
_payload._remotely_enforced_setitem(it->first, it->second);
}
} else {
_payload._remotely_enforced_wipe();
for (std::map<std::string, std::string>::const_iterator it=update->new_items.begin(); it!=update->new_items.end(); ++it) {
for (std::map<std::string, PayloadDocumentEntry::ptr>::const_iterator it=update->new_items.begin(); it!=update->new_items.end(); ++it) {
_payload._remotely_enforced_setitem(it->first, it->second);
}
}
......
......@@ -3,7 +3,7 @@
* "Incremental Processing Architecture
* 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)
* CITEC, Bielefeld University
*
......@@ -31,158 +31,493 @@
* 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-json.h>
#include "rapidjson/document.h"
#include "rapidjson/prettywriter.h"
#include "rapidjson/filestream.h"
#include <cstdio>
#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 std;
int main(int, char*[]) {
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 RAPIDJSON_HAS_CXX11_RVALUE_REFS
puts("OK - c++11 rvalue refs possible.");
#else
puts("WARNING - no c++11 rvalue refs!");
#endif
#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;
}
//}}}
////////////////////////////////////////////////////////////////////////////
// 1. Parse a JSON text string to a document.
const char json[] = " { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4], \"dict\":{\"s\":\"stringvalue\", \"arr\":[6, 7, \"test\"]} } ";
printf("Original JSON:\n %s\n", json);
Document document; // Default template parameter uses UTF8 and MemoryPoolAllocator.
#if 0
// "normal" parsing, decode strings to new buffers. Can use other input stream via ParseStream().
if (document.Parse(json).HasParseError())
return 1;
#else
// In-situ parsing, decode strings directly in the source string. Source must be string.
{
char buffer[sizeof(json)];
memcpy(buffer, json, sizeof(json));
if (document.ParseInsitu(buffer).HasParseError())
return 1;
int json_testbed_main(int argc, char** argv)//{{{
{
std::string json_source("[\"old\",2,3,4]");
ipaaca::PayloadDocumentEntry::ptr entry = ipaaca::PayloadDocumentEntry::from_json_string_representation(json_source);
std::string newinner("{\"K\":\"V\"}");
ipaaca::PayloadDocumentEntry::ptr entrynew = ipaaca::PayloadDocumentEntry::from_json_string_representation(newinner);
ipaaca::FakeIU::ptr iu = ipaaca::FakeIU::create();
iu->add_fake_payload_item("a", entry);
iu->add_fake_payload_item("b", entrynew);
iu->payload()["c"] = "simpleString";
auto proxy = iu->payload()["a"][3];
std::cout << "IU payload before: " << iu->payload() << std::endl;
std::cout << "Entry before: " << entry << std::endl;
std::cout << "EntryNew before: " << entrynew << std::endl;
/*
proxy.json_value->CopyFrom(entrynew->document, proxy.document_entry->document.GetAllocator());
proxy.document_entry->update_json_source();
*/
proxy = iu->payload()["b"];
std::cout << "Newly written part: " << iu->payload()["a"][3] << std::endl;
iu->payload()["a"][3]["addkey"] = "addvalue";
std::cout << "IU payload after: " << iu->payload() << std::endl;
std::cout << "Entry after: " << entry << std::endl;
std::cout << "EntryNew after: " << entrynew << std::endl;
return 0;
}
//}}}
int fakeiu_main(int argc, char** argv)//{{{
{
//if (argc<2) {
// std::cout << "Please provide json content as the first argument." << std::endl;
// return 0;
//}
//
std::string json_source("[\"old\",2,3,4]");
ipaaca::PayloadDocumentEntry::ptr entry = ipaaca::PayloadDocumentEntry::from_json_string_representation(json_source);
ipaaca::FakeIU::ptr iu = ipaaca::FakeIU::create();
iu->add_fake_payload_item("a", entry);
iu->payload()["b"] = "anotherValue";
iu->payload()["c"] = "yetAnotherValue";
auto a = iu->payload()["a"];
//auto a0 = a[0];
std::cout << "entry as string: " << (std::string) a << std::endl;
std::cout << "entry as long: " << (long) a << std::endl;
std::cout << "entry as double: " << (double) a << std::endl;
std::cout << "entry as bool: " << ((bool) a?"true":"false") << std::endl;
// std::vector
std::cout << "entry as vector<string>: ";
try {
std::vector<std::string> v = a;
std::for_each(v.begin(), v.end(), [](std::string& s) {
std::cout << s << " ";
});
std::cout << std::endl;
} catch (...) {
std::cout << "(n/a)" << std::endl;
}
#endif
printf("\nParsing succeeded.\n");
////////////////////////////////////////////////////////////////////////////
assert(document.IsObject()); // testing dict here
assert(document.HasMember("dict"));
assert(document["dict"].IsObject());
assert(document["dict"].HasMember("s"));
assert(document["dict"]["s"].IsString());
assert(document["dict"].HasMember("arr"));
assert(document["dict"]["arr"].IsArray());
Value& arr = document["dict"]["arr"];
printf("dict.arr size: %d\n", arr.Size());
for (SizeType i = 0; i < arr.Size(); i++) {
if (arr[i].IsInt()) {
printf("a[%d] = %d\n", i, arr[i].GetInt());
} else {
printf("a[%d] = \"%s\"\n", i, arr[i].GetString());
std::cout << "entry as vector<long>: ";
try {
std::vector<long> v = a;
std::for_each(v.begin(), v.end(), [](long& s) {
std::cout << s << " ";
});
std::cout << std::endl;
} catch (...) {
std::cout << "(n/a)" << std::endl;
}
std::cout << "entry as vector<bool>: ";
try {
std::vector<bool> v = a;
std::for_each(v.begin(), v.end(), [](bool s) {
std::cout << (s?"true":"false") << " ";
});
std::cout << std::endl;
} catch (...) {
std::cout << "(n/a)" << std::endl;
}
// std::map
std::cout << "entry as map<string, string>: ";
try {
std::map<std::string, std::string> m = a;
for (auto it = m.begin(); it != m.end(); ++it) {
std::cout << it->first << ":" << it->second << " ";
}
std::cout << std::endl;
} catch (...) {
std::cout << "(n/a)" << std::endl;
}
puts("Putting new dict in array.\n");
Document::AllocatorType& allocator = document.GetAllocator();
Value dict;
dict.SetObject();
dict.AddMember("testkey", "testvalue", allocator);
arr.PushBack(dict, allocator);
puts("Done.\n");
// ->Assertion failed in []:
// Value& nonexisting = document["dict"]["NONEXISTING"];
#if 0
// 2. Access values in document.
printf("\nAccess values in document:\n");
assert(document.IsObject()); // Document is a JSON value represents the root of DOM. Root can be either an object or array.
assert(document.HasMember("hello"));
assert(document["hello"].IsString());
printf("hello = %s\n", document["hello"].GetString());
// Since version 0.2, you can use single lookup to check the existing of member and its value:
Value::MemberIterator hello = document.FindMember("hello");
assert(hello != document.MemberEnd());
assert(hello->value.IsString());
assert(strcmp("world", hello->value.GetString()) == 0);
(void)hello;
assert(document["t"].IsBool()); // JSON true/false are bool. Can also uses more specific function IsTrue().
printf("t = %s\n", document["t"].GetBool() ? "true" : "false");
assert(document["f"].IsBool());
printf("f = %s\n", document["f"].GetBool() ? "true" : "false");
printf("n = %s\n", document["n"].IsNull() ? "null" : "?");
assert(document["i"].IsNumber()); // Number is a JSON type, but C++ needs more specific type.
assert(document["i"].IsInt()); // In this case, IsUint()/IsInt64()/IsUInt64() also return true.
printf("i = %d\n", document["i"].GetInt()); // Alternative (int)document["i"]
assert(document["pi"].IsNumber());
assert(document["pi"].IsDouble());
printf("pi = %g\n", document["pi"].GetDouble());
{
const Value& a = document["a"]; // Using a reference for consecutive access is handy and faster.
assert(a.IsArray());
for (SizeType i = 0; i < a.Size(); i++) // rapidjson uses SizeType instead of size_t.
printf("a[%d] = %d\n", i, a[i].GetInt());
int y = a[0].GetInt();
(void)y;
// Iterating array with iterators
printf("a = ");
for (Value::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr)
printf("%d ", itr->GetInt());
printf("\n");
}
// Iterating object members
static const char* kTypeNames[] = { "Null", "False", "True", "Object", "Array", "String", "Number" };
for (Value::ConstMemberIterator itr = document.MemberBegin(); itr != document.MemberEnd(); ++itr)
printf("Type of member %s is %s\n", itr->name.GetString(), kTypeNames[itr->value.GetType()]);
////////////////////////////////////////////////////////////////////////////
// 3. Modify values in document.
// Change i to a bigger number
{
uint64_t f20 = 1; // compute factorial of 20
for (uint64_t j = 1; j <= 20; j++)
f20 *= j;
document["i"] = f20; // Alternate form: document["i"].SetUint64(f20)
assert(!document["i"].IsInt()); // No longer can be cast as int or uint.
std::cout << "entry as map<string, long>: ";
try {
std::map<std::string, long> m = a;
for (auto it = m.begin(); it != m.end(); ++it) {
std::cout << it->first << ":" << it->second << " ";
}
std::cout << std::endl;
} catch (...) {
std::cout << "(n/a)" << std::endl;
}
// Adding values to array.
{
Value& a = document["a"]; // This time we uses non-const reference.
Document::AllocatorType& allocator = document.GetAllocator();
for (int i = 5; i <= 10; i++)
a.PushBack(i, allocator); // May look a bit strange, allocator is needed for potentially realloc. We normally uses the document's.
// Fluent API
a.PushBack("Lua", allocator).PushBack("Mio", allocator);
}
// Making string values.
// This version of SetString() just store the pointer to the string.
// So it is for literal and string that exists within value's life-cycle.
{
document["hello"] = "rapidjson"; // This will invoke strlen()
// Faster version:
// document["hello"].SetString("rapidjson", 9);
std::cout << "entry as map<string, double>: ";
try {
std::map<std::string, double> m = a;
for (auto it = m.begin(); it != m.end(); ++it) {
std::cout << it->first << ":" << it->second << " ";
}
std::cout << std::endl;
} catch (...) {
std::cout << "(n/a)" << std::endl;
}
// This version of SetString() needs an allocator, which means it will allocate a new buffer and copy the the string into the buffer.
Value author;
{
char buffer[10];
int len = sprintf(buffer, "%s %s", "Milo", "Yip"); // synthetic example of dynamically created string.
author.SetString(buffer, static_cast<size_t>(len), document.GetAllocator());
// Shorter but slower version:
// document["hello"].SetString(buffer, document.GetAllocator());
// Constructor version:
// Value author(buffer, len, document.GetAllocator());
// Value author(buffer, document.GetAllocator());
memset(buffer, 0, sizeof(buffer)); // For demonstration purpose.
}
// Variable 'buffer' is unusable now but 'author' has already made a copy.
document.AddMember("author", author, document.GetAllocator());
assert(author.IsNull()); // Move semantic for assignment. After this variable is assigned as a member, the variable becomes null.
////////////////////////////////////////////////////////////////////////////
std::cout << "entry as map<string, bool>: ";
try {
std::map<std::string, bool> m = a;
for (auto it = m.begin(); it != m.end(); ++it) {
std::cout << it->first << ":" << (it->second?"true":"false") << " ";
}
std::cout << std::endl;
} catch (...) {
std::cout << "(n/a)" << std::endl;
}
std::cout << "Setting value [0] in the object:" << std::endl;
try {
iu->payload()["a"][0] = "CHANGED_BY_USER";
} catch (ipaaca::PayloadAddressingError& e) {
std::cout << " Error - the provided object was not a suitable array" << std::endl;
}
//iu->payload()["a"]["A"] = "set by pep::op=";
std::cout << "Appending two words to key 'b' the currently wrong way:" << std::endl;
auto proxy = iu->payload()["b"];
proxy = (std::string) proxy + " WORD1";
proxy = (std::string) proxy + " WORD2";
std::cout << "Appending two words to key 'c' the compatible way:" << std::endl;
iu->payload()["c"] = (std::string) iu->payload()["c"] + " WORD1";
iu->payload()["c"] = (std::string) iu->payload()["c"] + " WORD2";
std::cout << "Printing final payload using PayloadIterator:" << std::endl;
for (auto it = iu->payload().begin(); it != iu->payload().end(); ++it) {
std::cout << " " << std::left << std::setw(15) << ((*it).first+": ") << (*it).second << std::endl;
}
std::cout << "Final payload (cast to map, printed as strings):" << std::endl;
std::map<std::string, std::string> pl_flat = iu->payload();
for (auto& kv: pl_flat) {
std::cout << " " << std::left << std::setw(15) << (kv.first+": ") << kv.second << std::endl;
}
return 0;
}
//}}}
#endif
int legacy_iu_main(int argc, char** argv)//{{{
{
// produce and fill a new and a legacy IU with identical contents
ipaaca::OutputBuffer::ptr ob = ipaaca::OutputBuffer::create("jsonTestSenderLegacy");
ob->register_handler([](ipaaca::IUInterface::ptr iu, ipaaca::IUEventType event_type, bool local) {
std::cout << "Received remote update, new payload: " << iu->payload() << std::endl;
});
std::cout << "--- Create IUs with category jsonTest" << std::endl;
ipaaca::IU::ptr iu1 = ipaaca::IU::create("jsonTest");
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::cout << "--- Set map" << std::endl;
iu1->payload()["map"] = newmap;
iu1->payload()["array"] = std::vector<std::string>{"aaa", "bbb", "ccc"};
iu2->payload()["map"] = newmap;
iu2->payload()["array"] = std::vector<std::string>{"aaa", "bbb", "ccc"};
std::cout << "--- Publishing IUs with this payload:" << std::endl;
std::cout << iu1->payload() << std::endl;
ob->add(iu1);
ob->add(iu2);
std::cout << "--- Waiting for changes for 5s " << std::endl;
sleep(5);
return 0;
}
//}}}
int iu_main(int argc, char** argv)//{{{
{
ipaaca::InputBuffer::ptr ib = ipaaca::InputBuffer::create("jsonTestReceiver", "jsonTest");
ib->register_handler([](ipaaca::IUInterface::ptr iu, ipaaca::IUEventType event_type, bool local) {
if (event_type==IU_ADDED) {
std::cout << "Received a new IU, payload: " << iu->payload() << std::endl;
std::cout << "Will write something." << std::endl;
//iu->commit();
try {
iu->payload()["list"][0] = "Overridden from C++";
} catch (ipaaca::PayloadAddressingError& e) {
iu->payload()["newKey"] = std::vector<long>{2,4,6,8};
std::cout << " (item ['list'][0] could not be addressed, wrote new key)" << std::endl;
}
}
});
std::cout << "--- Waiting for IUs for 10s " << std::endl;
sleep(10);
return 0;
// 4. Stringify JSON
printf("\nModified JSON with reformatting:\n");
FileStream f(stdout);
PrettyWriter<FileStream> writer(f);
document.Accept(writer); // Accept() traverses the DOM and generates Handler events.
ipaaca::OutputBuffer::ptr ob = ipaaca::OutputBuffer::create("jsonTestSender");
ob->register_handler([](ipaaca::IUInterface::ptr iu, ipaaca::IUEventType event_type, bool local) {
std::cout << "Received remote update, new payload: " << iu->payload() << std::endl;
});
std::cout << "--- Create IU with category jsonTest" << std::endl;
ipaaca::IU::ptr iu = ipaaca::IU::create("jsonTest");
std::map<std::string, long> newmap = { {"fifty", 50}, {"ninety-nine", 99} };
std::cout << "--- Set map" << std::endl;
iu->payload()["map"] = newmap;
std::cout << "--- Publishing IU with this payload:" << std::endl;
std::cout << iu->payload() << std::endl;
ob->add(iu);
std::cout << "--- Waiting for changes for 5s before next write" << std::endl;
sleep(5);
std::cout << "--- Contents of map after 5s" << std::endl;
std::cout << iu->payload()["map"] << std::endl;
//
std::cout << "--- Creating a list" << std::endl;
iu->payload()["list"] = std::vector<long>{1, 0} ;
std::cout << "--- Waiting for changes for 5s " << std::endl;
sleep(5);
std::cout << "--- Final map " << std::endl;
std::cout << iu->payload()["map"] << std::endl;
std::cout << "--- Final list " << std::endl;
std::cout << iu->payload()["list"] << std::endl;
std::cout << "--- Terminating " << std::endl;
return 0;
}
//}}}
int main(int argc, char** argv)
{
ipaaca::CommandLineParser::ptr parser = ipaaca::CommandLineParser::create();
ipaaca::CommandLineOptions::ptr options = parser->parse(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 fakeiu_main(argc, argv);
//return iu_main(argc, argv);
}
/*
* 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.
*/
#include <ipaaca/ipaaca.h>
namespace ipaaca {
IPAACA_EXPORT std::ostream& operator<<(std::ostream& os, const SmartLinkMap& obj)//{{{
{
os << "{";
bool first = true;
for (LinkMap::const_iterator it=obj._links.begin(); it!=obj._links.end(); ++it) {
if (first) { first=false; } else { os << ", "; }
os << "'" << it->first << "': [";
bool firstinner = true;
for (LinkSet::const_iterator it2=it->second.begin(); it2!=it->second.end(); ++it2) {
if (firstinner) { firstinner=false; } else { os << ", "; }
os << "'" << *it2 << "'";
}
os << "]";
}
os << "}";
return os;
}
//}}}
// SmartLinkMap//{{{
IPAACA_EXPORT LinkSet SmartLinkMap::empty_link_set;
IPAACA_EXPORT void SmartLinkMap::_add_and_remove_links(const LinkMap& add, const LinkMap& remove)
{
// remove specified links
for (LinkMap::const_iterator it = remove.begin(); it != remove.end(); ++it ) {
// if link type exists
if (_links.count(it->first) > 0) {
// remove one by one
for (LinkSet::const_iterator it2=it->second.begin(); it2!=it->second.end(); ++it2) {
_links[it->first].erase(*it2);
}
// wipe the type key if no more links are left
if (_links[it->first].size() == 0) {
_links.erase(it->first);
}
}
}
// add specified links
for (LinkMap::const_iterator it = add.begin(); it != add.end(); ++it ) {
for (LinkSet::const_iterator it2=it->second.begin(); it2!=it->second.end(); ++it2) {
_links[it->first].insert(*it2);
}
}
}
IPAACA_EXPORT void SmartLinkMap::_replace_links(const LinkMap& links)
{
_links=links;
}
IPAACA_EXPORT const LinkSet& SmartLinkMap::get_links(const std::string& key)
{
LinkMap::const_iterator it = _links.find(key);
if (it==_links.end()) return empty_link_set;
return it->second;
}
IPAACA_EXPORT const LinkMap& SmartLinkMap::get_all_links()
{
return _links;
}
//}}}
} // of namespace ipaaca
......@@ -3,7 +3,7 @@
* "Incremental Processing Architecture
* 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)
* CITEC, Bielefeld University
*
......
......@@ -3,7 +3,7 @@
* "Incremental Processing Architecture
* 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)
* CITEC, Bielefeld University
*
......@@ -33,195 +33,770 @@
#include <ipaaca/ipaaca.h>
#include <sstream>
namespace ipaaca {
using namespace rsb;
using namespace rsb::filter;
using namespace rsb::converter;
using namespace rsb::patterns;
using namespace rapidjson;
// temporary helper to show rapidjson internal type
std::string value_diagnosis(rapidjson::Value* val)
{
if (!val) return "nullptr";
if (val->IsNull()) return "null";
if (val->IsString()) return "string";
if (val->IsNumber()) return "number";
if (val->IsBool()) return "bool";
if (val->IsArray()) return "array";
if (val->IsObject()) return "object";
return "other";
}
IPAACA_EXPORT std::ostream& operator<<(std::ostream& os, const rapidjson::Value& val)//{{{
{
os << json_value_cast<std::string>(val);
return os;
}
//}}}
IPAACA_EXPORT std::ostream& operator<<(std::ostream& os, const PayloadEntryProxy& proxy)//{{{
{
if (proxy.json_value) os << *(proxy.json_value);
else os << "null";
return os;
}
//}}}
IPAACA_EXPORT std::ostream& operator<<(std::ostream& os, PayloadDocumentEntry::ptr entry)//{{{
{
os << json_value_cast<std::string>(entry->document);
return os;
}
//}}}
IPAACA_EXPORT std::ostream& operator<<(std::ostream& os, const Payload& obj)//{{{
{
os << "{";
bool first = true;
for (std::map<std::string, std::string>::const_iterator it=obj._store.begin(); it!=obj._store.end(); ++it) {
for (auto& kv: obj._document_store) {
if (first) { first=false; } else { os << ", "; }
os << "'" << it->first << "':'" << it->second << "'";
os << "\"" << kv.first << "\":" << kv.second->to_json_string_representation() << "";
}
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//{{{
IPAACA_EXPORT template<> std::string json_value_cast(const rapidjson::Value& v)
{
if (v.IsString()) return v.GetString();
if (v.IsNull()) return "";
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
v.Accept(writer);
return buffer.GetString();
}
IPAACA_EXPORT template<> long json_value_cast(const rapidjson::Value& v)
{
if (v.IsString()) return (long) 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;
// default: return parse of string version (should always be 0 though?)
throw PayloadTypeConversionError();
}
IPAACA_EXPORT template<> int json_value_cast(const rapidjson::Value& v)
{
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)
{
if (v.IsString()) return strict_numerical_interpretation(v.GetString());
if (v.IsDouble()) return v.GetDouble();
if (v.IsInt()) return (double) v.GetInt();
if (v.IsUint()) return (double) v.GetUint();
if (v.IsInt64()) return (double) v.GetInt64();
if (v.IsUint64()) return (double) v.GetUint64();
if (v.IsBool()) return v.GetBool() ? 1.0 : 0.0;
if (v.IsNull()) return 0.0;
throw PayloadTypeConversionError();
}
IPAACA_EXPORT template<> bool json_value_cast(const rapidjson::Value& v)
{
if (v.IsString()) {
std::string s = v.GetString();
return !(s==""); // NEW: only empty string maps to false
}
if (v.IsBool()) return v.GetBool();
if (v.IsNull()) return false;
if (v.IsInt()) return v.GetInt() != 0;
if (v.IsUint()) return v.GetUint() != 0;
if (v.IsInt64()) return v.GetInt64() != 0;
if (v.IsUint64()) return v.GetUint64() != 0;
if (v.IsDouble()) return v.GetDouble() != 0.0;
// NEW: empty structures map to false ('Pythonesque' semantics!)
if (v.IsArray()) return v.Size() > 0;
if (v.IsObject()) return v.MemberCount() > 0;
throw NotImplementedError(); // should never be reached anyway
}
//}}}
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)
{
valueobject.SetInt(newvalue);
}
IPAACA_EXPORT void pack_into_json_value(rapidjson::Value& valueobject, rapidjson::Document::AllocatorType& allocator, double newvalue)
{
valueobject.SetDouble(newvalue);
}
IPAACA_EXPORT void pack_into_json_value(rapidjson::Value& valueobject, rapidjson::Document::AllocatorType& allocator, bool newvalue)
{
valueobject.SetBool(newvalue);
}
IPAACA_EXPORT void pack_into_json_value(rapidjson::Value& valueobject, rapidjson::Document::AllocatorType& allocator, const std::string& newvalue)
{
valueobject.SetString(newvalue.c_str(), allocator);
}
IPAACA_EXPORT void pack_into_json_value(rapidjson::Value& valueobject, rapidjson::Document::AllocatorType& allocator, const char* newvalue)
{
valueobject.SetString(newvalue, allocator);
}
// PayloadDocumentEntry//{{{
IPAACA_EXPORT std::string PayloadDocumentEntry::to_json_string_representation()
{
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
document.Accept(writer);
return buffer.GetString();
}
IPAACA_EXPORT PayloadDocumentEntry::ptr PayloadDocumentEntry::from_json_string_representation(const std::string& json_str)
{
PayloadDocumentEntry::ptr entry = std::make_shared<ipaaca::PayloadDocumentEntry>();
if (entry->document.Parse(json_str.c_str()).HasParseError()) {
throw JsonParsingError();
}
return entry;
}
IPAACA_EXPORT PayloadDocumentEntry::ptr PayloadDocumentEntry::from_unquoted_string_value(const std::string& str)
{
PayloadDocumentEntry::ptr entry = std::make_shared<ipaaca::PayloadDocumentEntry>();
entry->document.SetString(str.c_str(), entry->document.GetAllocator());
return entry;
}
IPAACA_EXPORT PayloadDocumentEntry::ptr PayloadDocumentEntry::create_null()
{
PayloadDocumentEntry::ptr entry = std::make_shared<ipaaca::PayloadDocumentEntry>();
return entry;
}
IPAACA_EXPORT PayloadDocumentEntry::ptr PayloadDocumentEntry::clone()
{
auto entry = PayloadDocumentEntry::create_null();
entry->document.CopyFrom(this->document, entry->document.GetAllocator());
IPAACA_DEBUG("PayloadDocumentEntry cloned for copy-on-write, contents: " << entry)
return entry;
}
IPAACA_EXPORT rapidjson::Value& PayloadDocumentEntry::get_or_create_nested_value_from_proxy_path(PayloadEntryProxy* pep)
{
if (!(pep->parent)) {
return document;
}
rapidjson::Value& parent_value = get_or_create_nested_value_from_proxy_path(pep->parent);
if (pep->addressed_as_array) {
IPAACA_DEBUG("Addressed as array with index " << pep->addressed_index)
if (! parent_value.IsArray()) {
IPAACA_INFO("parent value is not of type Array")
throw PayloadAddressingError();
} else {
long idx = pep->addressed_index;
long s = parent_value.Size();
if (idx<s) {
return parent_value[idx];
} else {
throw PayloadAddressingError();
}
}
} else {
IPAACA_DEBUG("Addressed as dict with key " << pep->addressed_key)
if (! parent_value.IsObject()) {
IPAACA_INFO("parent value is not of type Object")
throw PayloadAddressingError();
} else {
rapidjson::Document::AllocatorType& allocator = document.GetAllocator();
rapidjson::Value key;
key.SetString(pep->addressed_key, allocator);
auto it = parent_value.FindMember(key);
if (it != parent_value.MemberEnd()) {
return parent_value[key];
} else {
rapidjson::Value val;
parent_value.AddMember(key, val, allocator);
rapidjson::Value rkey;
rkey.SetString(pep->addressed_key, allocator);
return parent_value[rkey];
}
}
}
}
//}}}
// PayloadEntryProxy//{{{
IPAACA_EXPORT PayloadEntryProxy::PayloadEntryProxy(Payload* payload, const std::string& key)
: _payload(payload), _key(key)
: _payload(payload), _key(key), parent(nullptr)
{
document_entry = _payload->get_entry(key);
set_json_value(&(document_entry->document), "construction");
}
IPAACA_EXPORT PayloadEntryProxy& PayloadEntryProxy::operator=(const std::string& value)
IPAACA_EXPORT PayloadEntryProxy::PayloadEntryProxy(PayloadEntryProxy* parent_, const std::string& addr_key_)
: parent(parent_), addressed_key(addr_key_), addressed_as_array(false)
{
//std::cout << "operator=(string)" << std::endl;
_payload->set(_key, value);
return *this;
_payload = parent->_payload;
_key = parent->_key;
document_entry = parent->document_entry;
auto it = parent->json_value->FindMember(addr_key_.c_str());
if (it != parent->json_value->MemberEnd()) {
set_json_value(&(parent->json_value->operator[](addr_key_.c_str())), std::string("construction from str addressing with ")+addr_key_);
existent = true;
} else {
set_json_value(nullptr, std::string("null-construction from failed str addressing with ")+addr_key_); // avoid heap construction here
existent = false;
}
}
IPAACA_EXPORT PayloadEntryProxy& PayloadEntryProxy::operator=(const char* value)
IPAACA_EXPORT PayloadEntryProxy::PayloadEntryProxy(PayloadEntryProxy* parent_, size_t addr_idx_)
: parent(parent_), addressed_index(addr_idx_), addressed_as_array(true)
{
//std::cout << "operator=(const char*)" << std::endl;
_payload->set(_key, value);
return *this;
_payload = parent->_payload;
_key = parent->_key;
document_entry = parent->document_entry;
set_json_value(&(parent->json_value->operator[](addr_idx_)), std::string("construction from int addressing with ")+std::to_string(addr_idx_));
existent = true;
}
IPAACA_EXPORT PayloadEntryProxy& PayloadEntryProxy::operator=(double value)
IPAACA_EXPORT PayloadEntryProxy PayloadEntryProxy::operator[](const char* addr_key_)
{
//std::cout << "operator=(double)" << std::endl;
_payload->set(_key, boost::lexical_cast<std::string>(value));
return *this;
return operator[](std::string(addr_key_));
}
IPAACA_EXPORT PayloadEntryProxy& PayloadEntryProxy::operator=(bool value)
IPAACA_EXPORT PayloadEntryProxy PayloadEntryProxy::operator[](const std::string& addr_key_)
{
//std::cout << "operator=(bool)" << std::endl;
_payload->set(_key, boost::lexical_cast<std::string>(value));
if (!json_value) {
IPAACA_INFO("Invalid json_value")
throw PayloadAddressingError();
}
//IPAACA_DEBUG("string addressing with '" << addr_key_ << "' of json object " << (off_t) json_value )
if (! json_value->IsObject()) {
IPAACA_INFO("Expected Object for operator[](string)")
//IPAACA_DEBUG(" But type is: " << value_diagnosis(json_value) )
throw PayloadAddressingError();
}
return PayloadEntryProxy(this, addr_key_);
}
IPAACA_EXPORT PayloadEntryProxy PayloadEntryProxy::operator[](size_t addr_idx_)
{
if (!json_value) {
IPAACA_INFO("Invalid json_value")
throw PayloadAddressingError();
}
if (! json_value->IsArray()) {
IPAACA_INFO("Expected Array for operator[](size_t)")
throw PayloadAddressingError();
}
long s = json_value->Size();
if (addr_idx_>=s) {
IPAACA_INFO("Array out of bounds")
throw PayloadAddressingError();
}
return PayloadEntryProxy(this, addr_idx_);
}
IPAACA_EXPORT PayloadEntryProxy PayloadEntryProxy::operator[](int addr_idx_)
{
if (addr_idx_ < 0) {
IPAACA_INFO("Negative array index")
throw PayloadAddressingError();
}
return operator[]((size_t) addr_idx_);
}
IPAACA_EXPORT PayloadEntryProxy& PayloadEntryProxy::operator=(const PayloadEntryProxy& otherproxy)
{
PayloadDocumentEntry::ptr new_entry = document_entry->clone(); // copy-on-write, no lock required
rapidjson::Value& newval = new_entry->get_or_create_nested_value_from_proxy_path(this);
auto valueptr = otherproxy.json_value;
if (valueptr) { // only set if value is valid, keep default null value otherwise
newval.CopyFrom(*valueptr, new_entry->document.GetAllocator());
}
_payload->set(_key, new_entry);
return *this;
}
IPAACA_EXPORT PayloadEntryProxy::operator std::string()
{
return PayloadEntryProxy::get<std::string>();
return json_value_cast<std::string>(json_value);
}
IPAACA_EXPORT inline PayloadEntryProxy::operator long()
IPAACA_EXPORT PayloadEntryProxy::operator int()
{
return PayloadEntryProxy::get<long>();
return json_value_cast<int>(json_value);
}
IPAACA_EXPORT inline PayloadEntryProxy::operator double()
IPAACA_EXPORT PayloadEntryProxy::operator long()
{
return PayloadEntryProxy::get<double>();
return json_value_cast<long>(json_value);
}
IPAACA_EXPORT inline PayloadEntryProxy::operator bool()
IPAACA_EXPORT PayloadEntryProxy::operator double()
{
return PayloadEntryProxy::get<bool>();
return json_value_cast<double>(json_value);
}
IPAACA_EXPORT inline std::string PayloadEntryProxy::to_str()
IPAACA_EXPORT PayloadEntryProxy::operator bool()
{
return PayloadEntryProxy::get<std::string>();
return json_value_cast<bool>(json_value);
}
IPAACA_EXPORT inline long PayloadEntryProxy::to_long()
IPAACA_EXPORT std::string PayloadEntryProxy::to_str()
{
return PayloadEntryProxy::get<long>();
return json_value_cast<std::string>(json_value);
}
IPAACA_EXPORT inline double PayloadEntryProxy::to_float()
IPAACA_EXPORT int PayloadEntryProxy::to_int()
{
return PayloadEntryProxy::get<double>();
return json_value_cast<int>(json_value);
}
IPAACA_EXPORT inline bool PayloadEntryProxy::to_bool()
IPAACA_EXPORT long PayloadEntryProxy::to_long()
{
return PayloadEntryProxy::get<bool>();
return json_value_cast<long>(json_value);
}
IPAACA_EXPORT double PayloadEntryProxy::to_float()
{
return json_value_cast<double>(json_value);
}
IPAACA_EXPORT double PayloadEntryProxy::to_double()
{
return json_value_cast<double>(json_value);
}
IPAACA_EXPORT bool PayloadEntryProxy::to_bool()
{
return json_value_cast<bool>(json_value);
}
IPAACA_EXPORT PayloadEntryProxyMapDecorator PayloadEntryProxy::as_map()
{
if (json_value && json_value->IsObject()) return PayloadEntryProxyMapDecorator(this);
throw PayloadTypeConversionError();
}
//
// new stuff for protocol v2
//
IPAACA_HEADER_EXPORT template<> std::string PayloadEntryProxy::get<std::string>()
IPAACA_EXPORT PayloadEntryProxyListDecorator PayloadEntryProxy::as_list()
{
return _payload->get(_key);
if (json_value && json_value->IsArray()) return PayloadEntryProxyListDecorator(this);
throw PayloadTypeConversionError();
}
IPAACA_HEADER_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_HEADER_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_HEADER_EXPORT template<> bool PayloadEntryProxy::get<bool>()
IPAACA_EXPORT bool PayloadEntryProxy::is_string()
{
std::string s = operator std::string();
return ((s=="1")||(s=="true")||(s=="True"));
return json_value && json_value->IsString();
}
// complex types
IPAACA_HEADER_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;
l.push_back(PayloadEntryProxy::get<std::string>());
return l;
if (!json_value) return false;
try {
double dummy = json_value_cast<double>(*json_value);
return true;
} catch (PayloadTypeConversionError& ex) {
return false;
}
}
IPAACA_HEADER_EXPORT template<> std::vector<std::string> PayloadEntryProxy::get<std::vector<std::string> >()
IPAACA_EXPORT bool PayloadEntryProxy::is_list()
{
std::vector<std::string> v;
v.push_back(PayloadEntryProxy::get<std::string>());
return v;
return json_value && json_value->IsArray();
}
IPAACA_HEADER_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;
m["__automatic__"] = PayloadEntryProxy::get<std::string>();
return m;
return json_value && json_value->IsObject();
}
//}}}
// 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)
{
//boost::shared_ptr<PayloadEntryProxy> p(new PayloadEntryProxy(this, key));
return PayloadEntryProxy(this, key);
}
IPAACA_EXPORT Payload::operator std::map<std::string, std::string>()
{
return _store;
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] = json_value_cast<std::string>(pair.second->document);
});
return result;
}
IPAACA_EXPORT void Payload::_internal_set(const std::string& k, const std::string& v, const std::string& writer_name) {
std::map<std::string, std::string> _new;
std::vector<std::string> _remove;
_new[k]=v;
_iu.lock()->_modify_payload(true, _new, _remove, writer_name );
_store[k] = v;
IPAACA_EXPORT void Payload::_internal_set(const std::string& k, PayloadDocumentEntry::ptr v, const std::string& writer_name) {
Locker locker(_payload_operation_mode_lock);
if (_update_on_every_change) {
std::map<std::string, PayloadDocumentEntry::ptr> _new;
std::vector<std::string> _remove;
_new[k] = v;
_iu.lock()->_modify_payload(true, _new, _remove, writer_name );
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) {
std::map<std::string, std::string> _new;
std::vector<std::string> _remove;
_remove.push_back(k);
_iu.lock()->_modify_payload(true, _new, _remove, writer_name );
_store.erase(k);
Locker locker(_payload_operation_mode_lock);
if (_update_on_every_change) {
std::map<std::string, PayloadDocumentEntry::ptr> _new;
std::vector<std::string> _remove;
_remove.push_back(k);
_iu.lock()->_modify_payload(true, _new, _remove, writer_name );
_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, std::string>& new_contents, const std::string& writer_name)
IPAACA_EXPORT void Payload::_internal_replace_all(const std::map<std::string, PayloadDocumentEntry::ptr>& new_contents, const std::string& writer_name)
{
std::vector<std::string> _remove;
_iu.lock()->_modify_payload(false, new_contents, _remove, writer_name );
_store = new_contents;
Locker locker(_payload_operation_mode_lock);
if (_update_on_every_change) {
std::vector<std::string> _remove;
_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, std::string>& contents_to_merge, const std::string& writer_name)
IPAACA_EXPORT void Payload::_internal_merge(const std::map<std::string, PayloadDocumentEntry::ptr>& contents_to_merge, const std::string& writer_name)
{
std::vector<std::string> _remove;
_iu.lock()->_modify_payload(true, contents_to_merge, _remove, writer_name );
_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;
//}
Locker locker(_payload_operation_mode_lock);
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 inline std::string Payload::get(const std::string& k) {
if (_store.count(k)>0) return _store[k];
else return IPAACA_PAYLOAD_DEFAULT_STRING_VALUE;
IPAACA_EXPORT void Payload::_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) {
_document_store[kv.first] = kv.second;
}
mark_revision_change();
}
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];
else return PayloadDocumentEntry::create_null(); // contains Document with 'null' value
}
IPAACA_EXPORT std::string Payload::get(const std::string& k) { // DEPRECATED
if (_document_store.count(k)>0) return _document_store[k]->document.GetString();
return "";
}
IPAACA_EXPORT void Payload::set(const std::map<std::string, std::string>& all_elems)
{
std::map<std::string, PayloadDocumentEntry::ptr> newmap;
for (auto& kv: all_elems) {
newmap[kv.first] = PayloadDocumentEntry::from_unquoted_string_value(kv.second);
}
_internal_replace_all(newmap);
}
IPAACA_EXPORT void Payload::_remotely_enforced_wipe()
{
_store.clear();
_document_store.clear();
mark_revision_change();
}
IPAACA_EXPORT void Payload::_remotely_enforced_delitem(const std::string& k)
{
_store.erase(k);
_document_store.erase(k);
mark_revision_change();
}
IPAACA_EXPORT void Payload::_remotely_enforced_setitem(const std::string& k, PayloadDocumentEntry::ptr entry)
{
_document_store[k] = entry;
mark_revision_change();
}
IPAACA_EXPORT PayloadIterator Payload::begin()
{
return PayloadIterator(this, _document_store.begin());
}
IPAACA_EXPORT PayloadIterator Payload::end()
{
return PayloadIterator(this, _document_store.end());
}
//}}}
// PayloadIterator//{{{
IPAACA_EXPORT PayloadIterator::PayloadIterator(Payload* payload, PayloadDocumentStore::iterator&& ref_it)
: _payload(payload), reference_payload_revision(payload->internal_revision), raw_iterator(std::move(ref_it))
{
}
IPAACA_EXPORT PayloadIterator::PayloadIterator(const PayloadIterator& iter)
: _payload(iter._payload), reference_payload_revision(iter.reference_payload_revision), raw_iterator(iter.raw_iterator)
{
}
IPAACA_EXPORT PayloadIterator& PayloadIterator::operator++()
{
if (_payload->revision_changed(reference_payload_revision)) throw PayloadIteratorInvalidError();
++raw_iterator;
return *this;
}
IPAACA_EXPORT 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::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)
{
if (_payload->revision_changed(reference_payload_revision)) throw PayloadIteratorInvalidError();
return (raw_iterator==ref.raw_iterator);
}
IPAACA_EXPORT void Payload::_remotely_enforced_setitem(const std::string& k, const std::string& v)
IPAACA_EXPORT bool PayloadIterator::operator!=(const PayloadIterator& ref)
{
_store[k] = v;
if (_payload->revision_changed(reference_payload_revision)) throw PayloadIteratorInvalidError();
return (raw_iterator!=ref.raw_iterator);
}
//}}}
// 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
......@@ -3,8 +3,9 @@
* "Incremental Processing Architecture
* for Artificial Conversational Agents".
*
* Copyright (c) 2009-2013 Sociable Agents Group
* CITEC, Bielefeld University
* 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
......@@ -32,8 +33,20 @@
#include <ipaaca/ipaaca.h>
#include <cctype>
#include <string>
#include <algorithm>
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)
{
if(set.size()==0)
......@@ -74,28 +87,34 @@ std::string str_join(const std::vector<std::string>& vec,const std::string& sep)
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();
std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
std::string::size_type pos = str.find_first_of(delimiters, lastPos);
int count = 0;
while (std::string::npos != pos || std::string::npos != lastPos)
{
count++;
tokens.push_back(str.substr(lastPos, pos - lastPos));
lastPos = str.find_first_not_of(delimiters, pos);
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 pos = str.find_first_of(delimiters, lastPos);
int count = 0;
while (std::string::npos != pos || std::string::npos != lastPos)
{
count++;
tokens.push_back(str.substr(lastPos, pos - lastPos));
lastPos = str.find_first_not_of(delimiters, pos);
pos = str.find_first_of(delimiters, lastPos);
}
return count;
}
} // 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 @@
* "Incremental Processing Architecture
* 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)
* CITEC, Bielefeld University
*
......@@ -38,7 +38,7 @@ namespace ipaaca {
// UUID generation
IPAACA_EXPORT std::string generate_uuid_string()//{{{
{
#ifdef WIN32
#if _WIN32 || _WIN64
// Windows
UUID uuid;
RPC_STATUS stat;
......@@ -51,6 +51,7 @@ IPAACA_EXPORT std::string generate_uuid_string()//{{{
RpcStringFree(&uuid_str);
return result;
}
throw UUIDGenerationError();
} else {
throw UUIDGenerationError();
}
......@@ -72,17 +73,14 @@ IPAACA_EXPORT std::string generate_uuid_string()//{{{
#endif
}//}}}
/*
void init_inprocess_too() {
//ParticipantConfig config = getFactory().getDefaultParticipantConfig();
ParticipantConfig config = ParticipantConfig::fromFile("rsb.cfg");
//ParticipantConfig::Transport inprocess = config.getTransport("inprocess");
//inprocess.setEnabled(true);
//config.addTransport(inprocess);
getFactory().setDefaultParticipantConfig(config);
}
*/
IPAACA_EXPORT std::string __ipaaca_static_option_default_payload_type("JSON");
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("");
IPAACA_EXPORT std::string __ipaaca_static_option_rsb_port("");
IPAACA_EXPORT std::string __ipaaca_static_option_rsb_transport("");
IPAACA_EXPORT std::string __ipaaca_static_option_rsb_socketserver("");
} // of namespace ipaaca
......
[transport.spread]
host = localhost
port = 4803
enabled = 1
......@@ -3,8 +3,9 @@
* "Incremental Processing Architecture
* for Artificial Conversational Agents".
*
* Copyright (c) 2009-2013 Sociable Agents Group
* CITEC, Bielefeld University
* 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
......@@ -29,7 +30,16 @@
* Forschungsgemeinschaft (DFG) in the context of the German
* 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>
namespace ipaaca {
......@@ -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)
{
//std::cout << "handle_iu_event: got an event" << std::endl;
if ((event_type == IU_ADDED) || (event_type == IU_UPDATED) || (event_type == IU_MESSAGE)) {
Locker locker(lock);
IPAACA_DEBUG("Received a componentNotify")
std::string cName = iu->payload()[_IPAACA_COMP_NOTIF_NAME];
std::string cState = iu->payload()[_IPAACA_COMP_NOTIF_STATE];
if (cName != name) {
//std::cout << " handle_iu_event: calling notification handlers" << std::endl;
// call all registered notification handlers
for (std::vector<IUEventHandlerFunction>::iterator it = _handlers.begin(); it != _handlers.end(); ++it) {
(*it)(iu, event_type, local);
}
// send own info only if the remote component is a newly initialized one
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);
}
}
......@@ -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_RECV_CATS] = recv_categories;
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() {
Locker locker(lock);
if (!initialized) {
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);
}
}
......
......@@ -3,13 +3,16 @@ cmake_minimum_required (VERSION 2.6)
# project name
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
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DIPAACA_DEBUG_MESSAGES")
# find cmake modules locally too
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})
include_directories(${Boost_INCLUDE_DIRS})
......@@ -17,6 +20,9 @@ find_package(Protobuf REQUIRED)
link_directories(${PROTOBUF_LIBRARY_DIRS})
include_directories(${PROTOBUF_INCLUDE_DIRS})
# for boost unit_test to create main()
add_definitions(-DBOOST_TEST_DYN_LINK)
#set(RSBLIBS rsc rsbcore)
set(LIBS ${LIBS} ipaaca )
......@@ -72,3 +78,7 @@ install (
ARCHIVE DESTINATION lib
)
enable_testing()
add_test(TestIpaacaCpp testipaaca)
CONFIG = -DIPAACA_DEBUG_MESSAGES
#IPAACASOURCES = ../../src/ipaaca.cc ipaaca.pb.cc
#TEXTSOURCES = ${IPAACASOURCES} testipaaca.cc
TEXTSOURCES = testipaaca.cc
CCFLAGS=-I../../build -I../../../../deps/include -I../../../../dist/include -I. -I../../src -I/usr/local/include -I/opt/local/include ${CONFIG}
BOOSTLIBS = -L/opt/local/lib -lboost_regex-mt -lboost_date_time-mt -lboost_thread-mt
PROTOLIBS = -L/opt/local/lib -lprotobuf
#LIBS = ${BOOSTLIBS} ${PROTOLIBS} -L/usr/local/lib -lrsc -lrsbcore
#LIBS = -L../../../../deps/lib -L../../../../dist/lib -lipaaca
LIBS = -L../../build -L../../../../deps/lib -L../../../../dist/lib -lipaaca
#COMPILER = gfilt
COMPILER = gcc
all: testipaaca
testipaaca:
${COMPILER} ${CCFLAGS} -o testipaaca ${TEXTSOURCES} ${LIBS}
protoc:
protoc --proto_path=../../../proto ../../../proto/ipaaca.proto --cpp_out=.
clean:
rm -f testipaaca ipaaca.pb.h ipaaca.pb.cc
......@@ -3,7 +3,7 @@
* "Incremental Processing Architecture
* for Artificial Conversational Agents".
*
* Copyright (c) 2009-2013 Sociable Agents Group
* Copyright (c) 2009-2022 Sociable Agents Group
* CITEC, Bielefeld University
*
* http://opensource.cit-ec.de/projects/ipaaca/
......
......@@ -3,7 +3,7 @@
* "Incremental Processing Architecture
* for Artificial Conversational Agents".
*
* Copyright (c) 2009-2013 Sociable Agents Group
* Copyright (c) 2009-2022 Sociable Agents Group
* CITEC, Bielefeld University
*
* http://opensource.cit-ec.de/projects/ipaaca/
......
......@@ -3,7 +3,7 @@
* "Incremental Processing Architecture
* for Artificial Conversational Agents".
*
* Copyright (c) 2009-2013 Sociable Agents Group
* Copyright (c) 2009-2022 Sociable Agents Group
* CITEC, Bielefeld University
*
* http://opensource.cit-ec.de/projects/ipaaca/
......@@ -33,121 +33,90 @@
#include <ipaaca/ipaaca.h>
#include <typeinfo>
using namespace ipaaca;
#define BOOST_TEST_MODULE TestIpaacaCpp
#include <boost/test/unit_test.hpp>
const char RECV_CATEGORY[] = "WORD";
const char SEND_CATEGORY[] = "TEXT";
using namespace ipaaca;
class TextSender {
protected:
OutputBuffer::ptr _ob;
InputBuffer::ptr _ib;
class TestReceiver {
public:
TextSender();
void outbuffer_handle_iu_event(IUInterface::ptr iu, IUEventType event_type, bool local);
InputBuffer::ptr _ib;
std::string received_info;
TestReceiver();
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() {
_ob = OutputBuffer::create("TextSenderOut");
_ob->register_handler(boost::bind(&TextSender::outbuffer_handle_iu_event, this, _1, _2, _3));
_ib = InputBuffer::create("TextSenderIn", RECV_CATEGORY);
_ib->register_handler(boost::bind(&TextSender::inbuffer_handle_iu_event, this, _1, _2, _3));
TestReceiver::TestReceiver()
{
_ib = ipaaca::InputBuffer::create("TestReceiver", "cppTestCategory");
_ib->register_handler(boost::bind(&TestReceiver::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_UPDATED) {
std::set<std::string> parent_uids = iu->get_links("GRIN");
if (parent_uids.size() > 0) {
std::string parent_uid = *(parent_uids.begin());
std::cout << "updating parent ..." << std::endl;
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;
if (event_type == IU_ADDED) {
received_info = (std::string) iu->payload()["word"];
{
ipaaca::Locker locker(iu->payload());
iu->payload()["replyVector"] = std::vector<double> { 1.0, 2.0, 3.0 };
iu->payload()["replyComment"] = "OK";
}
} else {
}
}
void TextSender::inbuffer_handle_iu_event(IUInterface::ptr iu, IUEventType event_type, bool local)
{
if (event_type == IU_LINKSUPDATED) {
std::cout << "links updated" << std::endl;
} else if (event_type == IU_ADDED) {
std::string word = iu->payload()["WORD"];
std::cout << "Received new word: " << word << std::endl;
publish_text_to_print(word, iu->uid());
} else if (event_type == IU_RETRACTED) {
std::string retracted_uid = iu->uid();
} else {
std::cout << "(IU event " << iu_event_type_to_str(event_type) << " " << iu->uid() << ")" << std::endl;
}
class TestSender {
public:
OutputBuffer::ptr _ob;
std::vector<double> double_vec;
std::string comment;
long num_replies;
TestSender();
void publish_one_message();
void outbuffer_handle_iu_event(IUInterface::ptr iu, IUEventType event_type, bool local);
};
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() {
std::set<IUInterface::ptr> ius = _ob->get_ius();
for (std::set<IUInterface::ptr>::iterator it = ius.begin(); it!=ius.end(); ++it) {
if ((*it)->get_links("SUCCESSOR").size() == 0) return *it;
void TestSender::outbuffer_handle_iu_event(IUInterface::ptr iu, IUEventType event_type, bool local)
{
if (event_type == IU_UPDATED) {
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) {
IUInterface::ptr previous_iu = find_last_iu();
if (previous_iu) {
// insert a blank if we already have words in the buffer
IU::ptr iu = IU::create( SEND_CATEGORY );
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;
}
void TestSender::publish_one_message()
{
ipaaca::IU::ptr iu = ipaaca::IU::create("cppTestCategory");
iu->payload()["word"] = "OK";
_ob->add(iu);
}
int main() {
TextSender sender;
BOOST_AUTO_TEST_SUITE (testIpaacaCpp)
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);
sender.publish_text_to_print("(INIT)");
std::cout << "Press Ctrl-C to cancel..." << std::endl;
while (true) sleep(1);
std::cout << "Checking for changes." << std::endl;
BOOST_CHECK( receiver.received_info == "OK" );
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() {
std::cerr << "TODO: implement Ipaaca C++ test cases." << std::endl;
return 0;
}
BOOST_AUTO_TEST_SUITE_END( )
......@@ -6,3 +6,4 @@ dist
privateprops
.project
.classpath
/bin/
......@@ -6,5 +6,6 @@ run.jvmargs= -Xms128m -Xmx512m -Xss5M
rebuild.list=
publish.resolver=asap.sftp.publish
dist.dir=../../dist
javac.source=1.6
javac.target=1.6
javac.source=1.8
javac.target=1.8