diff --git a/ipaacalib/cpp/CMakeLists.txt b/ipaacalib/cpp/CMakeLists.txt index 688725b7a861ba801a9b2fd3b1f73c67f78b87cb..2f6243105a687126e0ef5e586c78e04507b4b0e7 100644 --- a/ipaacalib/cpp/CMakeLists.txt +++ b/ipaacalib/cpp/CMakeLists.txt @@ -13,6 +13,9 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DIPAACA_DEBUG_MESSAGES") # !! NOTE: at the moment required in any ipaaca cpp project in Windows !! set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DIPAACA_EXPOSE_FULL_RSB_API") +## use the following line to enable building mock IUs (FakeIU) +#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DIPAACA_BUILD_MOCK_OBJECTS") + # find cmake modules locally too set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMakeModules ) diff --git a/ipaacalib/cpp/build.properties b/ipaacalib/cpp/build.properties index b3fc60b1bde07852dd520ae90e3f491771ce32f8..7eaaa9bdcb2851bae4780e6705ed08f054e0b1be 100644 --- a/ipaacalib/cpp/build.properties +++ b/ipaacalib/cpp/build.properties @@ -4,4 +4,6 @@ resource.path=${shared.resources}/; rebuild.list= publish.resolver=asap.sftp.publish dist.dir=../../dist +deps.dir=../../deps +test.binary=testipaaca diff --git a/ipaacalib/cpp/include/ipaaca/ipaaca-buffers.h b/ipaacalib/cpp/include/ipaaca/ipaaca-buffers.h index e0a26c13e7e668977d5e86daea651a3ac5ec54ff..f5e4476bf447dc078f95af09af8fc42fc380605c 100644 --- a/ipaacalib/cpp/include/ipaaca/ipaaca-buffers.h +++ b/ipaacalib/cpp/include/ipaaca/ipaaca-buffers.h @@ -44,7 +44,7 @@ IPAACA_HEADER_EXPORT class IUStore: public std::map<std::string, boost::shared_p { }; /// Store for RemotePushIUs (used in InputBuffer) -IPAACA_HEADER_EXPORT class RemotePushIUStore: public std::map<std::string, boost::shared_ptr<RemotePushIU> > // TODO genericize to all remote IU types +IPAACA_HEADER_EXPORT class RemotePushIUStore: public std::map<std::string, boost::shared_ptr<RemotePushIU> > { }; @@ -142,7 +142,6 @@ IPAACA_HEADER_EXPORT class IUEventHandler {//{{{ public: IPAACA_HEADER_EXPORT IUEventHandler(IUEventHandlerFunction function, IUEventType event_mask, const std::string& category); IPAACA_HEADER_EXPORT IUEventHandler(IUEventHandlerFunction function, IUEventType event_mask, const std::set<std::string>& categories); - //void call(Buffer* buffer, const std::string& uid, bool local, IUEventType event_type, const std::string& category); IPAACA_HEADER_EXPORT void call(Buffer* buffer, boost::shared_ptr<IUInterface> iu, bool local, IUEventType event_type, const std::string& category); typedef boost::shared_ptr<IUEventHandler> ptr; };//}}} @@ -160,7 +159,6 @@ IPAACA_HEADER_EXPORT class Buffer { //: public boost::enable_shared_from_this<Bu friend class CallbackIUCommission; friend class CallbackIUResendRequest; protected: - //Lock _handler_lock; IPAACA_MEMBER_VAR_EXPORT std::string _uuid; IPAACA_MEMBER_VAR_EXPORT std::string _basename; IPAACA_MEMBER_VAR_EXPORT std::string _unique_name; @@ -174,7 +172,6 @@ IPAACA_HEADER_EXPORT class Buffer { //: public boost::enable_shared_from_this<Bu IPAACA_HEADER_EXPORT _IPAACA_ABSTRACT_ virtual void _send_iu_link_update(IUInterface* iu, bool is_delta, revision_t revision, const LinkMap& new_links, const LinkMap& links_to_remove, const std::string& writer_name="undef") = 0; IPAACA_HEADER_EXPORT _IPAACA_ABSTRACT_ virtual void _send_iu_payload_update(IUInterface* iu, bool is_delta, revision_t revision, const std::map<std::string, PayloadDocumentEntry::ptr>& new_items, const std::vector<std::string>& keys_to_remove, const std::string& writer_name="undef") = 0; IPAACA_HEADER_EXPORT _IPAACA_ABSTRACT_ virtual void _send_iu_commission(IUInterface* iu, revision_t revision, const std::string& writer_name="undef") = 0; -// IPAACA_HEADER_EXPORT _IPAACA_ABSTRACT_ virtual void _send_iu_resendrequest(IUInterface* iu, revision_t revision, const std::string& writer_name="undef") = 0; IPAACA_HEADER_EXPORT void _allocate_unique_name(const std::string& basename, const std::string& function); IPAACA_HEADER_EXPORT inline Buffer(const std::string& basename, const std::string& function) { _allocate_unique_name(basename, function); @@ -228,7 +225,6 @@ IPAACA_HEADER_EXPORT class Buffer { //: public boost::enable_shared_from_this<Bu * */ IPAACA_HEADER_EXPORT void register_handler(IUEventHandlerFunction function, IUEventType event_mask = IU_ALL_EVENTS, const std::string& category=""); - //_IPAACA_ABSTRACT_ virtual void add(boost::shared_ptr<IUInterface> iu) = 0; IPAACA_HEADER_EXPORT _IPAACA_ABSTRACT_ virtual boost::shared_ptr<IUInterface> get(const std::string& iu_uid) = 0; IPAACA_HEADER_EXPORT _IPAACA_ABSTRACT_ virtual std::set<boost::shared_ptr<IUInterface> > get_ius() = 0; @@ -253,7 +249,6 @@ IPAACA_HEADER_EXPORT class OutputBuffer: public Buffer { //, public boost::enabl friend class OutputBufferRsbAdaptor; protected: protected: - //OutputBufferRsbAdaptor _rsb; IPAACA_MEMBER_VAR_EXPORT IUStore _iu_store; IPAACA_MEMBER_VAR_EXPORT Lock _iu_id_counter_lock; #ifdef IPAACA_EXPOSE_FULL_RSB_API @@ -263,29 +258,23 @@ IPAACA_HEADER_EXPORT class OutputBuffer: public Buffer { //, public boost::enabl IPAACA_HEADER_EXPORT rsb::Informer<rsb::AnyType>::Ptr _get_informer(const std::string& category); #endif protected: - // informing functions IPAACA_HEADER_EXPORT void _send_iu_link_update(IUInterface* iu, bool is_delta, revision_t revision, const LinkMap& new_links, const LinkMap& links_to_remove, const std::string& writer_name="undef") _IPAACA_OVERRIDE_; IPAACA_HEADER_EXPORT void _publish_iu_resend(boost::shared_ptr<IU> iu, const std::string& hidden_scope_name) _IPAACA_OVERRIDE_; - IPAACA_HEADER_EXPORT void _send_iu_payload_update(IUInterface* iu, bool is_delta, revision_t revision, const std::map<std::string, PayloadDocumentEntry::ptr>& new_items, const std::vector<std::string>& keys_to_remove, const std::string& writer_name="undef") _IPAACA_OVERRIDE_; IPAACA_HEADER_EXPORT void _send_iu_commission(IUInterface* iu, revision_t revision, const std::string& writer_name) _IPAACA_OVERRIDE_; - //IPAACA_HEADER_EXPORT void _send_iu_resendrequest(IUInterface* iu, revision_t revision, const std::string& writer_name); - // remote access functions - // _remote_update_links(IULinkUpdate) - // _remote_update_payload(IUPayloadUpdate) - // _remote_commit(protobuf::IUCommission) IPAACA_HEADER_EXPORT void _publish_iu(boost::shared_ptr<IU> iu); - + /// mark and send IU retraction on own IU (removal from buffer is in remove(IU)) IPAACA_HEADER_EXPORT void _retract_iu(boost::shared_ptr<IU> iu); + /// mark and send retraction for all unretracted IUs (without removal, used in ~OutputBuffer) + IPAACA_HEADER_EXPORT void _retract_all_internal(); protected: /// \b Note: constructor is protected. Use create() IPAACA_HEADER_EXPORT OutputBuffer(const std::string& basename, const std::string& channel=""); // empty string auto-replaced with __ipaaca_static_option_default_channel IPAACA_HEADER_EXPORT void _initialize_server(); public: IPAACA_HEADER_EXPORT static boost::shared_ptr<OutputBuffer> create(const std::string& basename); - IPAACA_HEADER_EXPORT ~OutputBuffer() { - IPAACA_IMPLEMENT_ME - } + /// OutputBuffer destructor will retract all IUs that are still live + IPAACA_HEADER_EXPORT ~OutputBuffer(); IPAACA_HEADER_EXPORT void add(boost::shared_ptr<IU> iu); IPAACA_HEADER_EXPORT boost::shared_ptr<IU> remove(const std::string& iu_uid); IPAACA_HEADER_EXPORT boost::shared_ptr<IU> remove(boost::shared_ptr<IU> iu); @@ -308,12 +297,11 @@ IPAACA_HEADER_EXPORT class InputBuffer: public Buffer { //, public boost::enable friend class IU; friend class RemotePushIU; friend class InputBufferRsbAdaptor; - //InputBufferRsbAdaptor _rsb; #ifdef IPAACA_EXPOSE_FULL_RSB_API protected: IPAACA_MEMBER_VAR_EXPORT std::map<std::string, rsb::ListenerPtr> _listener_store; IPAACA_MEMBER_VAR_EXPORT std::map<std::string, rsb::patterns::RemoteServerPtr> _remote_server_store; - IPAACA_MEMBER_VAR_EXPORT RemotePushIUStore _iu_store; // TODO genericize + IPAACA_MEMBER_VAR_EXPORT RemotePushIUStore _iu_store; IPAACA_HEADER_EXPORT rsb::patterns::RemoteServerPtr _get_remote_server(const std::string& unique_server_name); IPAACA_HEADER_EXPORT rsb::ListenerPtr _create_category_listener_if_needed(const std::string& category); IPAACA_HEADER_EXPORT void _handle_iu_events(rsb::EventPtr event); @@ -362,8 +350,6 @@ IPAACA_HEADER_EXPORT class InputBuffer: public Buffer { //, public boost::enable IPAACA_HEADER_EXPORT static boost::shared_ptr<InputBuffer> create(const std::string& basename, const std::set<std::string>& category_interests); /// Create InputBuffer from name and vector of category interests IPAACA_HEADER_EXPORT static boost::shared_ptr<InputBuffer> create(const std::string& basename, const std::vector<std::string>& category_interests); - // /// Create InputBuffer from name and initializer_list of category interests - // IPAACA_HEADER_EXPORT static boost::shared_ptr<InputBuffer> create(const std::string& basename, const std::initializer_list<std::string>& category_interests); /// Convenience function: create InputBuffer from name and one category interest IPAACA_HEADER_EXPORT static boost::shared_ptr<InputBuffer> create(const std::string& basename, const std::string& category_interest1); /// Convenience function: create InputBuffer from name and two category interests [DEPRECATED] diff --git a/ipaacalib/cpp/include/ipaaca/ipaaca-definitions.h b/ipaacalib/cpp/include/ipaaca/ipaaca-definitions.h index 42e4f1024d5e37feba5b932bd4695f80185fc99a..e91b9c31b966b34c9100aa64b403d5199f3d073f 100644 --- a/ipaacalib/cpp/include/ipaaca/ipaaca-definitions.h +++ b/ipaacalib/cpp/include/ipaaca/ipaaca-definitions.h @@ -49,9 +49,6 @@ #error "Please do not include this file directly, use ipaaca.h instead" #endif -// LAST FIXME LAST -//typedef boost::shared_ptr<rapidjson::Document> JsonDocPtr; - typedef uint32_t revision_t; /// Type of the IU event. Realized as an integer to enable bit masks for filters. One of: IU_ADDED, IU_COMMITTED, IU_DELETED, IU_RETRACTED, IU_UPDATED, IU_LINKSUPDATED, IU_MESSAGE @@ -139,7 +136,7 @@ IPAACA_HEADER_EXPORT class IUPublishedError: public Exception//{{{ { public: IPAACA_HEADER_EXPORT inline ~IUPublishedError() throw() { } - IPAACA_HEADER_EXPORT inline IUPublishedError() { //boost::shared_ptr<IU> iu) { + IPAACA_HEADER_EXPORT inline IUPublishedError() { _description = "IUPublishedError"; } };//}}} @@ -148,16 +145,25 @@ IPAACA_HEADER_EXPORT class IUCommittedError: public Exception//{{{ { public: IPAACA_HEADER_EXPORT inline ~IUCommittedError() throw() { } - IPAACA_HEADER_EXPORT inline IUCommittedError() { //boost::shared_ptr<IU> iu) { + IPAACA_HEADER_EXPORT inline IUCommittedError() { _description = "IUCommittedError"; } };//}}} +/// IU had already been retracted +IPAACA_HEADER_EXPORT class IURetractedError: public Exception//{{{ +{ + public: + IPAACA_HEADER_EXPORT inline ~IURetractedError() throw() { } + IPAACA_HEADER_EXPORT inline IURetractedError() { + _description = "IURetractedError"; + } +};//}}} /// Remote IU update failed because it had been modified in the mean time IPAACA_HEADER_EXPORT class IUUpdateFailedError: public Exception//{{{ { public: IPAACA_HEADER_EXPORT inline ~IUUpdateFailedError() throw() { } - IPAACA_HEADER_EXPORT inline IUUpdateFailedError() { //boost::shared_ptr<IU> iu) { + IPAACA_HEADER_EXPORT inline IUUpdateFailedError() { _description = "IUUpdateFailedError"; } };//}}} @@ -166,7 +172,7 @@ IPAACA_HEADER_EXPORT class IUResendRequestFailedError: public Exception//{{{ { public: IPAACA_HEADER_EXPORT inline ~IUResendRequestFailedError() throw() { } - IPAACA_HEADER_EXPORT inline IUResendRequestFailedError() { //boost::shared_ptr<IU> iu) { + IPAACA_HEADER_EXPORT inline IUResendRequestFailedError() { _description = "IUResendRequestFailedError"; } };//}}} @@ -175,7 +181,7 @@ IPAACA_HEADER_EXPORT class IUReadOnlyError: public Exception//{{{ { public: IPAACA_HEADER_EXPORT inline ~IUReadOnlyError() throw() { } - IPAACA_HEADER_EXPORT inline IUReadOnlyError() { //boost::shared_ptr<IU> iu) { + IPAACA_HEADER_EXPORT inline IUReadOnlyError() { _description = "IUReadOnlyError"; } };//}}} @@ -184,7 +190,7 @@ IPAACA_HEADER_EXPORT class IUAlreadyInABufferError: public Exception//{{{ { public: IPAACA_HEADER_EXPORT inline ~IUAlreadyInABufferError() throw() { } - IPAACA_HEADER_EXPORT inline IUAlreadyInABufferError() { //boost::shared_ptr<IU> iu) { + IPAACA_HEADER_EXPORT inline IUAlreadyInABufferError() { _description = "IUAlreadyInABufferError"; } };//}}} @@ -193,7 +199,7 @@ IPAACA_HEADER_EXPORT class IUUnpublishedError: public Exception//{{{ { public: IPAACA_HEADER_EXPORT inline ~IUUnpublishedError() throw() { } - IPAACA_HEADER_EXPORT inline IUUnpublishedError() { //boost::shared_ptr<IU> iu) { + IPAACA_HEADER_EXPORT inline IUUnpublishedError() { _description = "IUUnpublishedError"; } };//}}} @@ -202,7 +208,7 @@ IPAACA_HEADER_EXPORT class IUAlreadyHasAnUIDError: public Exception//{{{ { public: IPAACA_HEADER_EXPORT inline ~IUAlreadyHasAnUIDError() throw() { } - IPAACA_HEADER_EXPORT inline IUAlreadyHasAnUIDError() { //boost::shared_ptr<IU> iu) { + IPAACA_HEADER_EXPORT inline IUAlreadyHasAnUIDError() { _description = "IUAlreadyHasAnUIDError"; } };//}}} @@ -211,7 +217,7 @@ IPAACA_HEADER_EXPORT class IUAlreadyHasAnOwnerNameError: public Exception//{{{ { public: IPAACA_HEADER_EXPORT inline ~IUAlreadyHasAnOwnerNameError() throw() { } - IPAACA_HEADER_EXPORT inline IUAlreadyHasAnOwnerNameError() { //boost::shared_ptr<IU> iu) { + IPAACA_HEADER_EXPORT inline IUAlreadyHasAnOwnerNameError() { _description = "IUAlreadyHasAnOwnerNameError"; } };//}}} @@ -220,7 +226,7 @@ IPAACA_HEADER_EXPORT class UUIDGenerationError: public Exception//{{{ { public: IPAACA_HEADER_EXPORT inline ~UUIDGenerationError() throw() { } - IPAACA_HEADER_EXPORT inline UUIDGenerationError() { //boost::shared_ptr<IU> iu) { + IPAACA_HEADER_EXPORT inline UUIDGenerationError() { _description = "UUIDGenerationError"; } };//}}} @@ -229,7 +235,7 @@ IPAACA_HEADER_EXPORT class NotImplementedError: public Exception//{{{ { public: IPAACA_HEADER_EXPORT inline ~NotImplementedError() throw() { } - IPAACA_HEADER_EXPORT inline NotImplementedError() { //boost::shared_ptr<IU> iu) { + IPAACA_HEADER_EXPORT inline NotImplementedError() { _description = "NotImplementedError"; } };//}}} @@ -238,7 +244,7 @@ IPAACA_HEADER_EXPORT class PayloadTypeConversionError: public Exception//{{{ { public: IPAACA_HEADER_EXPORT inline ~PayloadTypeConversionError() throw() { } - IPAACA_HEADER_EXPORT inline PayloadTypeConversionError() { //boost::shared_ptr<IU> iu) { + IPAACA_HEADER_EXPORT inline PayloadTypeConversionError() { _description = "PayloadTypeConversionError"; } };//}}} @@ -247,7 +253,7 @@ IPAACA_HEADER_EXPORT class PayloadAddressingError: public Exception//{{{ { public: IPAACA_HEADER_EXPORT inline ~PayloadAddressingError() throw() { } - IPAACA_HEADER_EXPORT inline PayloadAddressingError() { //boost::shared_ptr<IU> iu) { + IPAACA_HEADER_EXPORT inline PayloadAddressingError() { _description = "PayloadAddressingError"; } };//}}} @@ -256,7 +262,7 @@ IPAACA_HEADER_EXPORT class JsonParsingError: public Exception//{{{ { public: IPAACA_HEADER_EXPORT inline ~JsonParsingError() throw() { } - IPAACA_HEADER_EXPORT inline JsonParsingError() { //boost::shared_ptr<IU> iu) { + IPAACA_HEADER_EXPORT inline JsonParsingError() { _description = "JsonParsingError"; } };//}}} @@ -265,7 +271,7 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxyInvalidatedError: public Exception// { public: IPAACA_HEADER_EXPORT inline ~PayloadEntryProxyInvalidatedError() throw() { } - IPAACA_HEADER_EXPORT inline PayloadEntryProxyInvalidatedError() { //boost::shared_ptr<IU> iu) { + IPAACA_HEADER_EXPORT inline PayloadEntryProxyInvalidatedError() { _description = "PayloadEntryProxyInvalidatedError"; } };//}}} @@ -274,7 +280,7 @@ IPAACA_HEADER_EXPORT class PayloadIteratorInvalidError: public Exception//{{{ { public: IPAACA_HEADER_EXPORT inline ~PayloadIteratorInvalidError() throw() { } - IPAACA_HEADER_EXPORT inline PayloadIteratorInvalidError() { //boost::shared_ptr<IU> iu) { + IPAACA_HEADER_EXPORT inline PayloadIteratorInvalidError() { _description = "PayloadIteratorInvalidError"; } };//}}} @@ -291,11 +297,18 @@ IPAACA_HEADER_EXPORT class Initializer /// Initialize the backend [DEPRECATED] (old name, use initialize_backend() instead) [[deprecated("Use initialize_backend() instead")]] IPAACA_HEADER_EXPORT static void initialize_ipaaca_rsb_if_needed(); - /// Explicitly initialize the backend. No effect if already initialized. Automatically called during first Buffer construction. + /// Explicitly initialize the backend (usually not required). No effect if already initialized. Automatically called during first Buffer construction. IPAACA_HEADER_EXPORT static void initialize_backend(); IPAACA_HEADER_EXPORT static bool initialized(); IPAACA_HEADER_EXPORT static void dump_current_default_config(); protected: + /** Perform rsb pre-setup before the implicit initialization + * (when first instantiating something). Pre-setup includes + * finding the RSB plugin dir, looking through several parent + * directories for a path "deps/lib/rsb*"/plugins. The path + * can also be set directly (env var RSB_PLUGINS_CPP_PATH), + * which disables the automatic search. + */ IPAACA_HEADER_EXPORT static void auto_configure_rsb(); IPAACA_MEMBER_VAR_EXPORT static bool _initialized; }; @@ -323,10 +336,8 @@ IPAACA_HEADER_EXPORT class Initializer IPAACA_HEADER_EXPORT class CommandLineOptions { public: IPAACA_HEADER_EXPORT inline CommandLineOptions() - //: _unconsumed_argc(0), _unconsumed_argv(nullptr) { } IPAACA_HEADER_EXPORT inline ~CommandLineOptions() { - //if (_unconsumed_argv) delete[] _unconsumed_argv; } IPAACA_MEMBER_VAR_EXPORT std::map<std::string, std::string> param_opts; IPAACA_MEMBER_VAR_EXPORT std::map<std::string, bool> param_set; @@ -338,13 +349,7 @@ IPAACA_HEADER_EXPORT class CommandLineOptions { IPAACA_HEADER_EXPORT bool is_set(const std::string& o); IPAACA_HEADER_EXPORT void dump(); public: - //IPAACA_HEADER_EXPORT inline int unconsumed_argc() { return _unconsumed_argc; } - //IPAACA_HEADER_EXPORT inline char** unconsumed_argv() { return _unconsumed_argv; } - protected: - //IPAACA_MEMBER_VAR_EXPORT int _unconsumed_argc; - //IPAACA_MEMBER_VAR_EXPORT char** _unconsumed_argv; - public: - typedef boost::shared_ptr<CommandLineOptions> ptr; + typedef boost::shared_ptr<CommandLineOptions> ptr; }; /** @@ -398,7 +403,8 @@ class CommandLineParser { * The remaining options are packaged into a CommandLineOptions object. */ IPAACA_HEADER_EXPORT CommandLineOptions::ptr parse(int argc, char* const* argv); - typedef boost::shared_ptr<CommandLineParser> ptr; + public: + typedef boost::shared_ptr<CommandLineParser> ptr; }; //}}} // in ipaaca-string-utils.cc diff --git a/ipaacalib/cpp/include/ipaaca/ipaaca-forwards.h b/ipaacalib/cpp/include/ipaaca/ipaaca-forwards.h index 0d91d66fcb604b9bea353a8af46ba55b8eec49a3..f490dd9eb6a6d44356c133aa13201423981c7956 100644 --- a/ipaacalib/cpp/include/ipaaca/ipaaca-forwards.h +++ b/ipaacalib/cpp/include/ipaaca/ipaaca-forwards.h @@ -53,7 +53,6 @@ * forward declarations */ class PayloadDocumentEntry; -//class PayloadDocumentStore; class PayloadBatchUpdateLock; class PayloadEntryProxy; diff --git a/ipaacalib/cpp/include/ipaaca/ipaaca-internal.h b/ipaacalib/cpp/include/ipaaca/ipaaca-internal.h index b5609fde3d2a301c1c76fe9fe1067e74d4f05c4a..311d768a2f537e36b14d02f2bdc665e8efe53048 100644 --- a/ipaacalib/cpp/include/ipaaca/ipaaca-internal.h +++ b/ipaacalib/cpp/include/ipaaca/ipaaca-internal.h @@ -59,8 +59,6 @@ #ifdef IPAACA_EXPOSE_FULL_RSB_API -// ??? ///IPAACA_HEADER_EXPORT inline std::string json_to_string(PayloadDocumentEntry::ptr entry); - IPAACA_HEADER_EXPORT class CallbackIUPayloadUpdate: public rsb::patterns::Server::Callback<IUPayloadUpdate, int> {//{{{ protected: IPAACA_MEMBER_VAR_EXPORT Buffer* _buffer; diff --git a/ipaacalib/cpp/include/ipaaca/ipaaca-ius.h b/ipaacalib/cpp/include/ipaaca/ipaaca-ius.h index f4fc8fc6044e9c1cd70ca39250f98695a9a1c986..7d7bc93ac2b2ccb909dc4fbe47dfbb3591f8662e 100644 --- a/ipaacalib/cpp/include/ipaaca/ipaaca-ius.h +++ b/ipaacalib/cpp/include/ipaaca/ipaaca-ius.h @@ -95,6 +95,8 @@ IPAACA_HEADER_EXPORT class IUInterface {//{{{ IPAACA_HEADER_EXPORT void _add_and_remove_links(const LinkMap& add, const LinkMap& remove) { _links._add_and_remove_links(add, remove); } IPAACA_HEADER_EXPORT void _replace_links(const LinkMap& links) { _links._replace_links(links); } public: + /// Return whether IU has been retracted + IPAACA_HEADER_EXPORT inline bool retracted() const { return _retracted; } /// Return whether IU has already been published (is in a Buffer). IPAACA_HEADER_EXPORT inline bool is_published() { return (_buffer != 0); } /// Return auto-generated UID string (set during IU construction) @@ -174,7 +176,6 @@ IPAACA_HEADER_EXPORT class IU: public IUInterface {//{{{ IPAACA_HEADER_EXPORT IU(const std::string& category, IUAccessMode access_mode=IU_ACCESS_PUSH, bool read_only=false, const std::string& payload_type="" ); // __ipaaca_static_option_default_payload_type public: IPAACA_HEADER_EXPORT inline ~IU() { - //IPAACA_IMPLEMENT_ME } [[deprecated("Please use the new argument order: category, payload_type, read_only")]] IPAACA_HEADER_EXPORT static boost::shared_ptr<IU> create(const std::string& category, IUAccessMode access_mode, bool read_only=false, const std::string& payload_type="" ); @@ -184,9 +185,6 @@ IPAACA_HEADER_EXPORT class IU: public IUInterface {//{{{ IPAACA_HEADER_EXPORT void commit() _IPAACA_OVERRIDE_; protected: IPAACA_HEADER_EXPORT virtual void _modify_links(bool is_delta, const LinkMap& new_links, const LinkMap& links_to_remove, const std::string& writer_name = "") _IPAACA_OVERRIDE_; - - //IPAACA_HEADER_EXPORT virtual void _publish_resend(boost::shared_ptr<IU> iu, const std::string& hidden_scope_name); - IPAACA_HEADER_EXPORT virtual void _modify_payload(bool is_delta, const std::map<std::string, PayloadDocumentEntry::ptr>& new_items, const std::vector<std::string>& keys_to_remove, const std::string& writer_name = "") _IPAACA_OVERRIDE_; protected: IPAACA_HEADER_EXPORT virtual void _internal_commit(const std::string& writer_name = ""); @@ -217,7 +215,6 @@ IPAACA_HEADER_EXPORT class Message: public IU {//{{{ IPAACA_HEADER_EXPORT Message(const std::string& category, IUAccessMode access_mode=IU_ACCESS_MESSAGE, bool read_only=true, const std::string& payload_type="" ); public: IPAACA_HEADER_EXPORT inline ~Message() { - //IPAACA_IMPLEMENT_ME } [[deprecated("Please use the new argument order: category, payload_type")]] IPAACA_HEADER_EXPORT static boost::shared_ptr<Message> create(const std::string& category, IUAccessMode access_mode, bool read_only=true, const std::string& payload_type="" ); @@ -245,7 +242,6 @@ IPAACA_HEADER_EXPORT class RemotePushIU: public IUInterface {//{{{ IPAACA_HEADER_EXPORT static boost::shared_ptr<RemotePushIU> create(); public: IPAACA_HEADER_EXPORT inline ~RemotePushIU() { - //IPAACA_IMPLEMENT_ME } IPAACA_HEADER_EXPORT inline Payload& payload() _IPAACA_OVERRIDE_ { return _payload; } IPAACA_HEADER_EXPORT inline const Payload& const_payload() const _IPAACA_OVERRIDE_ { return _payload; } @@ -274,7 +270,6 @@ IPAACA_HEADER_EXPORT class RemoteMessage: public IUInterface {//{{{ IPAACA_HEADER_EXPORT static boost::shared_ptr<RemoteMessage> create(); public: IPAACA_HEADER_EXPORT inline ~RemoteMessage() { - //IPAACA_IMPLEMENT_ME } IPAACA_HEADER_EXPORT inline Payload& payload() _IPAACA_OVERRIDE_ { return _payload; } IPAACA_HEADER_EXPORT inline const Payload& const_payload() const _IPAACA_OVERRIDE_ { return _payload; } @@ -290,6 +285,7 @@ IPAACA_HEADER_EXPORT class RemoteMessage: public IUInterface {//{{{ typedef boost::shared_ptr<RemoteMessage> ptr; };//}}} +#ifdef IPAACA_BUILD_MOCK_OBJECTS /// Mock IU for testing purposes. [INTERNAL] IPAACA_HEADER_EXPORT class FakeIU: public IUInterface {//{{{ friend class Buffer; @@ -318,5 +314,6 @@ IPAACA_HEADER_EXPORT class FakeIU: public IUInterface {//{{{ public: typedef boost::shared_ptr<FakeIU> ptr; };//}}} +#endif #endif diff --git a/ipaacalib/cpp/include/ipaaca/ipaaca-payload.h b/ipaacalib/cpp/include/ipaaca/ipaaca-payload.h index dcf33e81d3d7ecebff94ff721e1e669b1ca0e17d..f346f3f5b80384a12004500cf4e5c869a40f5b83 100644 --- a/ipaacalib/cpp/include/ipaaca/ipaaca-payload.h +++ b/ipaacalib/cpp/include/ipaaca/ipaaca-payload.h @@ -111,12 +111,6 @@ IPAACA_HEADER_EXPORT template<typename T> void pack_into_json_value(rapidjson::V valueobject.AddMember(key, newv, allocator); } } -/*IPAACA_HEADER_EXPORT template<> void pack_into_json_value(rapidjson::Value&, rapidjson::Document::AllocatorType&, const std::vector<std::string>&); -IPAACA_HEADER_EXPORT template<> void pack_into_json_value(rapidjson::Value&, rapidjson::Document::AllocatorType&, const std::list<std::string>&); -IPAACA_HEADER_EXPORT template<> void pack_into_json_value(rapidjson::Value&, rapidjson::Document::AllocatorType&, const std::map<std::string, std::string>&); -*/ - -// FIXME TODO locking / invalidating proxy on first write of a payload entry /// Single payload entry wrapping a rapidjson::Document with some conversion glue. Also handles copy-on-write Document cloning. <b>Internal type</b> - users generally do not see this. IPAACA_HEADER_EXPORT class PayloadDocumentEntry//{{{ @@ -125,18 +119,15 @@ IPAACA_HEADER_EXPORT class PayloadDocumentEntry//{{{ public: IPAACA_MEMBER_VAR_EXPORT ipaaca::Lock lock; IPAACA_MEMBER_VAR_EXPORT bool modified; - //IPAACA_MEMBER_VAR_EXPORT std::string json_source; IPAACA_MEMBER_VAR_EXPORT rapidjson::Document document; IPAACA_HEADER_EXPORT inline PayloadDocumentEntry(): modified(false) { } IPAACA_HEADER_EXPORT inline ~PayloadDocumentEntry() { } - //IPAACA_HEADER_EXPORT PayloadDocumentEntry(const std::string& source): modified(false), json_source(source), {}; IPAACA_HEADER_EXPORT std::string to_json_string_representation(); IPAACA_HEADER_EXPORT static std::shared_ptr<PayloadDocumentEntry> from_json_string_representation(const std::string& input); IPAACA_HEADER_EXPORT static std::shared_ptr<PayloadDocumentEntry> from_unquoted_string_value(const std::string& input); IPAACA_HEADER_EXPORT static std::shared_ptr<PayloadDocumentEntry> create_null(); IPAACA_HEADER_EXPORT std::shared_ptr<PayloadDocumentEntry> clone(); IPAACA_HEADER_EXPORT rapidjson::Value& get_or_create_nested_value_from_proxy_path(PayloadEntryProxy* pep); - //IPAACA_HEADER_EXPORT void update_json_source(); typedef std::shared_ptr<PayloadDocumentEntry> ptr; }; //}}} @@ -144,22 +135,6 @@ IPAACA_HEADER_EXPORT class PayloadDocumentEntry//{{{ typedef std::map<std::string, PayloadDocumentEntry::ptr> PayloadDocumentStore; -#if 0 -/** \brief Lock to accumulate payload changes into one single update transaction - * - */ -IPAACA_HEADER_EXPORT class PayloadBatchUpdateLock: public ipaaca::Lock -{ - friend class Payload; - protected: - Payload* _payload; - public: - IPAACA_HEADER_EXPORT inline PayloadBatchUpdateLock(): Lock() { } - IPAACA_HEADER_EXPORT void on_lock() override; - IPAACA_HEADER_EXPORT void on_unlock() override; -}; -#endif - /** \brief Central class containing the user-set payload of any IUInterface class (IU, Message, RemotePushIU or RemoteMessage) * * Obtained by calling payload() on any IUInterface derived object. Created during IU creation. @@ -178,17 +153,11 @@ IPAACA_HEADER_EXPORT class Payload: public Lock //{{{ friend class PayloadEntryProxy; friend class PayloadIterator; friend class FakeIU; - //friend class PayloadBatchUpdateLock; protected: IPAACA_MEMBER_VAR_EXPORT std::string _owner_name; - //IPAACA_MEMBER_VAR_EXPORT rapidjson::Document _json_document; - //IPAACA_MEMBER_VAR_EXPORT std::map<std::string, rapidjson::Document> _json_store; IPAACA_MEMBER_VAR_EXPORT PayloadDocumentStore _document_store; IPAACA_MEMBER_VAR_EXPORT boost::weak_ptr<IUInterface> _iu; - //IPAACA_MEMBER_VAR_EXPORT PayloadBatchUpdateLock _batch_update_lock; - // IPAACA_MEMBER_VAR_EXPORT Lock _payload_operation_mode_lock; //< enforcing atomicity wrt the bool flag below - // IPAACA_MEMBER_VAR_EXPORT bool _update_on_every_change; //< true: batch update not active; false: collecting updates (payload locked) IPAACA_MEMBER_VAR_EXPORT std::map<std::string, PayloadDocumentEntry::ptr> _collected_modifications; IPAACA_MEMBER_VAR_EXPORT std::vector<std::string> _collected_removals; @@ -199,13 +168,11 @@ IPAACA_HEADER_EXPORT class Payload: public Lock //{{{ /// inherited from ipaaca::Lock, finishing batch update collection mode IPAACA_HEADER_EXPORT void on_unlock() override; protected: - //IPAACA_HEADER_EXPORT ipaaca::Locker&& batch_update() { return std::move(ipaaca::Locker(*this); } IPAACA_HEADER_EXPORT void initialize(boost::shared_ptr<IUInterface> iu); IPAACA_HEADER_EXPORT inline void _set_owner_name(const std::string& name) { _owner_name = name; } IPAACA_HEADER_EXPORT void _remotely_enforced_wipe(); IPAACA_HEADER_EXPORT void _remotely_enforced_delitem(const std::string& k); IPAACA_HEADER_EXPORT void _remotely_enforced_setitem(const std::string& k, PayloadDocumentEntry::ptr entry); - //IPAACA_HEADER_EXPORT void _internal_replace_all(const std::map<std::string, PayloadDocumentEntry::ptr>& new_contents, const std::string& writer_name=""); IPAACA_HEADER_EXPORT void _internal_replace_all(const std::map<std::string, PayloadDocumentEntry::ptr>& new_contents, const std::string& writer_name=""); IPAACA_HEADER_EXPORT void _internal_merge(const std::map<std::string, PayloadDocumentEntry::ptr>& contents_to_merge, const std::string& writer_name=""); IPAACA_HEADER_EXPORT void _internal_set(const std::string& k, PayloadDocumentEntry::ptr v, const std::string& writer_name=""); @@ -221,11 +188,6 @@ IPAACA_HEADER_EXPORT class Payload: public Lock //{{{ IPAACA_HEADER_EXPORT operator std::map<std::string, std::string>(); /// remove a single payload entry IPAACA_HEADER_EXPORT inline void remove(const std::string& k) { _internal_remove(k); } - // FIXME: json: these two must support a bunch of standard types, not [only] json (users touch them) - // to be more precise: types of map<string, T> with T several interesting things (string, list<string>, etc.) - //IPAACA_HEADER_EXPORT inline void set(const std::map<std::string, const rapidjson::Document&>& all_elems) { _internal_replace_all(all_elems); } - //IPAACA_HEADER_EXPORT inline void merge(const std::map<std::string, const rapidjson::Document&>& elems_to_merge) { _internal_merge(elems_to_merge); } - // legacy / convenience setter /// Legacy / convenience function: set the whole payload map from a map string->string (all JSON types are also set as string, no interpretation) IPAACA_HEADER_EXPORT void set(const std::map<std::string, std::string>& all_elems); protected: @@ -235,7 +197,7 @@ IPAACA_HEADER_EXPORT class Payload: public Lock //{{{ public: [[deprecated("Use operator[] and operator std::string() instead")]] /// Read a single entry as string [DEPRECATED] (use string conversion in PayloadEntryProxy instead) - IPAACA_HEADER_EXPORT std::string get(const std::string& k); // DEPRECATED + IPAACA_HEADER_EXPORT std::string get(const std::string& k); protected: IPAACA_MEMBER_VAR_EXPORT unsigned long internal_revision; IPAACA_MEMBER_VAR_EXPORT inline void mark_revision_change() { internal_revision++; } @@ -267,7 +229,6 @@ IPAACA_HEADER_EXPORT class PayloadIterator//{{{ IPAACA_MEMBER_VAR_EXPORT Payload* _payload; IPAACA_MEMBER_VAR_EXPORT unsigned long reference_payload_revision; IPAACA_MEMBER_VAR_EXPORT PayloadDocumentStore::iterator raw_iterator; - //IPAACA_MEMBER_VAR_EXPORT bool is_end; protected: IPAACA_HEADER_EXPORT PayloadIterator(Payload* payload, PayloadDocumentStore::iterator&& pl_iter ); //, bool is_end); public: @@ -277,7 +238,6 @@ IPAACA_HEADER_EXPORT class PayloadIterator//{{{ IPAACA_HEADER_EXPORT std::shared_ptr<std::pair<std::string, PayloadEntryProxy> > operator->(); IPAACA_HEADER_EXPORT bool operator==(const PayloadIterator& ref); IPAACA_HEADER_EXPORT bool operator!=(const PayloadIterator& ref); - // constructor to create a new top-most parent proxy (from a payload key) }; //}}} @@ -352,7 +312,7 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxyListDecorator//{{{ * * <code>for (auto val: iu->payload()["my_list"].as_list()) { ... }</code> // as_list is required to select list-type iteration (value type in iteration remains variant) * - * <code>for (auto k_v_map: iu->payload()["my_map"].as_map()) { ... }</code> // as_map is required to select map-type iteration (value type in iteration is a pair, second part remains variant) + * <code>for (auto k_v_pair: iu->payload()["my_map"].as_map()) { ... }</code> // as_map is required to select map-type iteration (value type in iteration is a pair, second part remains variant) * * \b Examples (writing): * @@ -382,13 +342,9 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{ /// Select list-style iteration for this proxy (to select iterator content type). Will throw if not actually list-type. See example in the class description. IPAACA_HEADER_EXPORT PayloadEntryProxyListDecorator as_list(); protected: - //IPAACA_MEMBER_VAR_EXPORT rapidjson::Document* _json_parent_node; - //IPAACA_MEMBER_VAR_EXPORT rapidjson::Document* _json_node; IPAACA_MEMBER_VAR_EXPORT Payload* _payload; IPAACA_MEMBER_VAR_EXPORT std::string _key; - // // new json stuff / hierarchical navigation - // IPAACA_MEMBER_VAR_EXPORT PayloadEntryProxy* parent; ///< Parent proxy (up to document root -> then null) IPAACA_MEMBER_VAR_EXPORT PayloadDocumentEntry::ptr document_entry; // contains lock and json Doc IPAACA_MEMBER_VAR_EXPORT bool existent; ///< Whether Value exists already (or else 'blindly' navigated) @@ -397,9 +353,6 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{ IPAACA_MEMBER_VAR_EXPORT std::string addressed_key; ///< Key that was used in map-style access /// currently navigated value in json tree (or a new Null value) IPAACA_MEMBER_VAR_EXPORT rapidjson::Value* json_value; ///< json value that corresponds to the current navigation (or nullptr) -/* protected: - IPAACA_HEADER_EXPORT void connect_to_existing_parents(); -*/ protected: // constructor to create a new top-most parent proxy (from a payload key) IPAACA_HEADER_EXPORT PayloadEntryProxy(Payload* payload, const std::string& key); @@ -440,7 +393,6 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{ 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); pack_into_json_value(newval, new_entry->document.GetAllocator(), t); - //new_entry->update_json_source(); _payload->set(_key, new_entry); return *this; } @@ -473,11 +425,6 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{ /// Copy value from below other json node, preserving types IPAACA_HEADER_EXPORT PayloadEntryProxy& operator=(const PayloadEntryProxy& otherproxy); - //IPAACA_HEADER_EXPORT PayloadEntryProxy& operator=(const std::string& value); - //IPAACA_HEADER_EXPORT PayloadEntryProxy& operator=(const char* value); - //IPAACA_HEADER_EXPORT PayloadEntryProxy& operator=(double value); - //IPAACA_HEADER_EXPORT PayloadEntryProxy& operator=(bool value); - /// Conversion to std::string (explicit or implicit) IPAACA_HEADER_EXPORT operator std::string(); /// Conversion to long (explicit or implicit) @@ -513,7 +460,7 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{ } return result; } - // FIXME why are these needed again? + // TODO maybe remove these deprecated converters later /// [DECPRECATED] use normal type conversion syntax instead [[deprecated("Use operator std::string() instead (i.e. explicit or implicit cast)")]] IPAACA_HEADER_EXPORT std::string to_str(); @@ -527,15 +474,6 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{ /// [DECPRECATED] use normal type conversion syntax instead [[deprecated("Use operator bool() instead (i.e. explicit or implicit cast)")]] IPAACA_HEADER_EXPORT bool to_bool(); - // getters (not needed since conversions are enough?) - //IPAACA_HEADER_EXPORT template<typename T> T get() { return json_value_cast<T>(json_value); } - // setters - //IPAACA_HEADER_EXPORT template<typename T> PayloadEntryProxy& set(T t); - /*{ - pack_into_json_value<T>(t); - connect_to_existing_parents(); - _payload->set(key, document_entry->document); - }*/ /// Append a supported type to a list-type payload value IPAACA_HEADER_EXPORT template<typename T> void push_back(T t) { @@ -603,18 +541,6 @@ IPAACA_HEADER_EXPORT class PayloadEntryProxy//{{{ _payload->set(_key, new_entry); } }; -// Available interpretations of payload entries (or children thereof) below. -// Usage of standard complex data structures (vector etc.) currently entails -// casting all entries to a uniform type (a-priori choice: std::string). -/* -IPAACA_HEADER_EXPORT template<> long PayloadEntryProxy::get(); -IPAACA_HEADER_EXPORT template<> double PayloadEntryProxy::get(); -IPAACA_HEADER_EXPORT template<> bool PayloadEntryProxy::get(); -IPAACA_HEADER_EXPORT template<> std::string PayloadEntryProxy::get(); -IPAACA_HEADER_EXPORT template<> std::vector<std::string> PayloadEntryProxy::get(); -IPAACA_HEADER_EXPORT template<> std::list<std::string> PayloadEntryProxy::get(); -IPAACA_HEADER_EXPORT template<> std::map<std::string, std::string> PayloadEntryProxy::get(); -*/ //}}} diff --git a/ipaacalib/cpp/include/ipaaca/ipaaca.h b/ipaacalib/cpp/include/ipaaca/ipaaca.h index 04f62ee0d2b2c45b079747a732007be22451c30e..16d3844a8e0dc7a970c2318512a7ba0b692b10cb 100644 --- a/ipaacalib/cpp/include/ipaaca/ipaaca.h +++ b/ipaacalib/cpp/include/ipaaca/ipaaca.h @@ -67,9 +67,9 @@ IU payload contents: Payload, PayloadEntryProxy #define IPAACA_PROTOCOL_VERSION_MINOR 0 /// running release number of ipaaca-c++ -#define IPAACA_CPP_RELEASE_NUMBER 12 +#define IPAACA_CPP_RELEASE_NUMBER 13 /// date of last release number increment -#define IPAACA_CPP_RELEASE_DATE "2015-01-15" +#define IPAACA_CPP_RELEASE_DATE "2015-12-04" #ifndef __FUNCTION_NAME__ #ifdef WIN32 // Windows @@ -209,6 +209,11 @@ IPAACA_MEMBER_VAR_EXPORT extern std::string __ipaaca_static_option_default_chann /// Current console log level (defaults to warning), one of: IPAACA_LOG_LEVEL_CRITICAL, IPAACA_LOG_LEVEL_ERROR, IPAACA_LOG_LEVEL_WARNING, IPAACA_LOG_LEVEL_INFO, IPAACA_LOG_LEVEL_DEBUG, IPAACA_LOG_LEVEL_NONE IPAACA_MEMBER_VAR_EXPORT extern unsigned int __ipaaca_static_option_log_level; +/// RSB host to connect to (defaults to "" = do not set, use global config) +IPAACA_MEMBER_VAR_EXPORT extern std::string __ipaaca_static_option_rsb_spread_host; +/// RSB port to connect to (defaults to "" = do not set, use global config) +IPAACA_MEMBER_VAR_EXPORT extern std::string __ipaaca_static_option_rsb_spread_port; + IPAACA_MEMBER_VAR_EXPORT Lock& logger_lock(); #ifdef WIN32 @@ -218,6 +223,21 @@ IPAACA_MEMBER_VAR_EXPORT Lock& logger_lock(); #define LOG_IPAACA_CONSOLE(msg) { ipaaca::Locker logging_locker(ipaaca::logger_lock()); timeval logging_tim; gettimeofday(&logging_tim, NULL); double logging_t1=logging_tim.tv_sec+(logging_tim.tv_usec/1000000.0); std::cout << "[LOG] " << std::setprecision(15) << logging_t1 << " : " << msg << std::endl; } #endif +#ifdef WIN32 +#define IPAACA_SIMPLE_TIMER_BEGIN(N) ; +#define IPAACA_SIMPLE_TIMER_END(N, NAME) LOG_IPAACA_CONSOLE(NAME << " - time elapsed: Windows - IMPLEMENT ME") +#else +/// use IPAACA_SIMPLE_TIMER_BEGIN(mysymbol) to start time profiling at a line in code +/// Several blocks can be defined in the same stack frame if different symbols are chosen +#define IPAACA_SIMPLE_TIMER_BEGIN(N) struct timeval _ipaaca_timer_tvstart_ ## N; \ + gettimeofday(&_ipaaca_timer_tvstart_ ## N, NULL); +/// use IPAACA_SIMPLE_TIMER_END(mysymbol, "message") to print time elapsed since correpsonding _BEGIN +#define IPAACA_SIMPLE_TIMER_END(N, NAME) struct timeval _ipaaca_timer_tvend_ ## N; \ + gettimeofday(&_ipaaca_timer_tvend_ ## N, NULL); \ + long _ipaaca_timer_usecs_ ## N = (_ipaaca_timer_tvend_ ## N.tv_sec*1000000 + _ipaaca_timer_tvend_ ## N.tv_usec) - (_ipaaca_timer_tvstart_ ## N.tv_sec*1000000 + _ipaaca_timer_tvstart_ ## N.tv_usec); \ + LOG_IPAACA_CONSOLE(NAME << " - ̨Ìus elapsed: " << _ipaaca_timer_usecs_ ## N) +#endif + #include <ipaaca/ipaaca-payload.h> #include <ipaaca/ipaaca-buffers.h> #include <ipaaca/ipaaca-ius.h> diff --git a/ipaacalib/cpp/include/ipaaca/util/notifier.h b/ipaacalib/cpp/include/ipaaca/util/notifier.h index c16a4dfc35be4729f4d447d405ac3ea658118be8..52ad449050fc97d279149c13b21e106291d3c603 100644 --- a/ipaacalib/cpp/include/ipaaca/util/notifier.h +++ b/ipaacalib/cpp/include/ipaaca/util/notifier.h @@ -3,8 +3,9 @@ * "Incremental Processing Architecture * for Artificial Conversational Agents". * - * Copyright (c) 2009-2013 Sociable Agents Group - * CITEC, Bielefeld University + * 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 diff --git a/ipaacalib/cpp/src/ipaaca-buffers.cc b/ipaacalib/cpp/src/ipaaca-buffers.cc index 8c99b7d3b2a6db1c952694645bf61e0de70a4ca0..33efa991d9e55533282ca3c22223731574ac736c 100644 --- a/ipaacalib/cpp/src/ipaaca-buffers.cc +++ b/ipaacalib/cpp/src/ipaaca-buffers.cc @@ -118,8 +118,6 @@ IPAACA_EXPORT IUEventHandler::IUEventHandler(IUEventHandlerFunction function, IU IPAACA_EXPORT void IUEventHandler::call(Buffer* buffer, boost::shared_ptr<IUInterface> iu, bool local, IUEventType event_type, const std::string& category) { if (_condition_met(event_type, category)) { - //IUInterface::ptr iu = buffer->get(uid); - //if (iu) { #if VERBOSE_HANDLERS == 1 std::cout << "[" << pthread_self() << " handler ENTER]" << std::endl; #endif @@ -127,7 +125,6 @@ IPAACA_EXPORT void IUEventHandler::call(Buffer* buffer, boost::shared_ptr<IUInte #if VERBOSE_HANDLERS == 1 std::cout << "[" << pthread_self() << " handler EXIT]" << std::endl; #endif - //} } } //}}} @@ -141,20 +138,19 @@ IPAACA_EXPORT void Buffer::_allocate_unique_name(const std::string& basename, co } IPAACA_EXPORT void Buffer::register_handler(IUEventHandlerFunction function, IUEventType event_mask, const std::set<std::string>& categories) { - std::cout << "register_handler " << function << " " << event_mask << " " << categories << std::endl; + IPAACA_DEBUG("register_handler " << function << " " << event_mask << " " << categories) IUEventHandler::ptr handler = IUEventHandler::ptr(new IUEventHandler(function, event_mask, categories)); _event_handlers.push_back(handler); } IPAACA_EXPORT void Buffer::register_handler(IUEventHandlerFunction function, IUEventType event_mask, const std::string& category) { - std::cout << "register_handler " << function << " " << event_mask << " " << category << std::endl; + IPAACA_DEBUG("register_handler " << function << " " << event_mask << " " << category) IUEventHandler::ptr handler = IUEventHandler::ptr(new IUEventHandler(function, event_mask, category)); _event_handlers.push_back(handler); } IPAACA_EXPORT void Buffer::call_iu_event_handlers(boost::shared_ptr<IUInterface> iu, bool local, IUEventType event_type, const std::string& category) { - //IPAACA_INFO("handling an event " << ipaaca::iu_event_type_to_str(event_type) << " for IU " << iu->uid()) - //std::cout << "handling an event " << ipaaca::iu_event_type_to_str(event_type) << " for IU " << iu->uid() << std::endl; + //IPAACA_DEBUG("handling an event " << ipaaca::iu_event_type_to_str(event_type) << " for IU " << iu->uid()) for (std::vector<IUEventHandler::ptr>::iterator it = _event_handlers.begin(); it != _event_handlers.end(); ++it) { (*it)->call(this, iu, local, event_type, category); } @@ -165,13 +161,10 @@ IPAACA_EXPORT void Buffer::call_iu_event_handlers(boost::shared_ptr<IUInterface> IPAACA_EXPORT CallbackIUPayloadUpdate::CallbackIUPayloadUpdate(Buffer* buffer): _buffer(buffer) { } IPAACA_EXPORT CallbackIULinkUpdate::CallbackIULinkUpdate(Buffer* buffer): _buffer(buffer) { } IPAACA_EXPORT CallbackIUCommission::CallbackIUCommission(Buffer* buffer): _buffer(buffer) { } -// dlw IPAACA_EXPORT CallbackIUResendRequest::CallbackIUResendRequest(Buffer* buffer): _buffer(buffer) { } IPAACA_EXPORT boost::shared_ptr<int> CallbackIUPayloadUpdate::call(const std::string& methodName, boost::shared_ptr<IUPayloadUpdate> update) { - IPAACA_INFO("") - //std::cout << "-- Received a modify_payload with " << update->new_items.size() << " keys to merge." << std::endl; IUInterface::ptr iui = _buffer->get(update->uid); if (! iui) { IPAACA_WARNING("Remote InBuffer tried to spuriously write non-existent IU " << update->uid) @@ -180,13 +173,25 @@ IPAACA_EXPORT boost::shared_ptr<int> CallbackIUPayloadUpdate::call(const std::st IU::ptr iu = boost::static_pointer_cast<IU>(iui); iu->_revision_lock.lock(); if ((update->revision != 0) && (update->revision != iu->_revision)) { - IPAACA_INFO("Remote write operation failed because request was out of date; IU " << update->uid) - IPAACA_INFO(" Referred-to revision was " << update->revision << " while local one is " << iu->_revision) + IPAACA_WARNING("Remote write operation failed because request was out of date; IU " << update->uid) + IPAACA_WARNING(" Referred-to revision was " << update->revision << " while local one is " << iu->_revision) + iu->_revision_lock.unlock(); + return boost::shared_ptr<int>(new int(0)); + } else if (iu->committed()) { + iu->_revision_lock.unlock(); + return boost::shared_ptr<int>(new int(0)); + } else if (iu->retracted()) { + iu->_revision_lock.unlock(); + return boost::shared_ptr<int>(new int(0)); + } else if (iu->committed()) { + iu->_revision_lock.unlock(); + return boost::shared_ptr<int>(new int(0)); + } else if (iu->retracted()) { iu->_revision_lock.unlock(); return boost::shared_ptr<int>(new int(0)); } if (update->is_delta) { - // FIXME FIXME this is an unsolved problem atm: deletes in a delta update are + // FIXME TODO this is an unsolved problem atm: deletions in a delta update are // sent individually. We should have something like _internal_merge_and_remove for (std::vector<std::string>::const_iterator it=update->keys_to_remove.begin(); it!=update->keys_to_remove.end(); ++it) { iu->payload()._internal_remove(*it, update->writer_name); //_buffer->unique_name()); @@ -196,7 +201,6 @@ IPAACA_EXPORT boost::shared_ptr<int> CallbackIUPayloadUpdate::call(const std::st } else { iu->payload()._internal_replace_all(update->new_items, update->writer_name); //_buffer->unique_name()); } - //std::cout << "-- Calling update handler due to remote write." << std::endl; _buffer->call_iu_event_handlers(iu, true, IU_UPDATED, iu->category()); revision_t revision = iu->revision(); iu->_revision_lock.unlock(); @@ -213,7 +217,19 @@ IPAACA_EXPORT boost::shared_ptr<int> CallbackIULinkUpdate::call(const std::strin IU::ptr iu = boost::static_pointer_cast<IU>(iui); iu->_revision_lock.lock(); if ((update->revision != 0) && (update->revision != iu->_revision)) { - IPAACA_INFO("Remote write operation failed because request was out of date; IU " << update->uid) + IPAACA_WARNING("Remote write operation failed because request was out of date; IU " << update->uid) + iu->_revision_lock.unlock(); + return boost::shared_ptr<int>(new int(0)); + } else if (iu->committed()) { + iu->_revision_lock.unlock(); + return boost::shared_ptr<int>(new int(0)); + } else if (iu->retracted()) { + iu->_revision_lock.unlock(); + return boost::shared_ptr<int>(new int(0)); + } else if (iu->committed()) { + iu->_revision_lock.unlock(); + return boost::shared_ptr<int>(new int(0)); + } else if (iu->retracted()) { iu->_revision_lock.unlock(); return boost::shared_ptr<int>(new int(0)); } @@ -237,11 +253,14 @@ IPAACA_EXPORT boost::shared_ptr<int> CallbackIUCommission::call(const std::strin IU::ptr iu = boost::static_pointer_cast<IU>(iui); iu->_revision_lock.lock(); if ((update->revision() != 0) && (update->revision() != iu->_revision)) { - IPAACA_INFO("Remote write operation failed because request was out of date; IU " << update->uid()) + IPAACA_WARNING("Remote write operation failed because request was out of date; IU " << update->uid()) iu->_revision_lock.unlock(); return boost::shared_ptr<int>(new int(0)); - } - if (iu->committed()) { + } else if (iu->committed()) { + iu->_revision_lock.unlock(); + return boost::shared_ptr<int>(new int(0)); + } else if (iu->retracted()) { + iu->_revision_lock.unlock(); return boost::shared_ptr<int>(new int(0)); } else { } @@ -251,7 +270,6 @@ IPAACA_EXPORT boost::shared_ptr<int> CallbackIUCommission::call(const std::strin iu->_revision_lock.unlock(); return boost::shared_ptr<int>(new int(revision)); } -/** dlw */ IPAACA_EXPORT boost::shared_ptr<int> CallbackIUResendRequest::call(const std::string& methodName, boost::shared_ptr<protobuf::IUResendRequest> update) { IUInterface::ptr iui = _buffer->get(update->uid()); @@ -261,12 +279,8 @@ IPAACA_EXPORT boost::shared_ptr<int> CallbackIUResendRequest::call(const std::st } IU::ptr iu = boost::static_pointer_cast<IU>(iui); if ((update->has_hidden_scope_name() == true)&&(update->hidden_scope_name().compare("") != 0)){ - //_buffer->call_iu_event_handlers(iu, true, IU_UPDATED, update->hidden_scope_name()); revision_t revision = iu->revision(); - _buffer->_publish_iu_resend(iu, update->hidden_scope_name()); - //iu->_publish_resend(iu, update->hidden_scope_name()); - return boost::shared_ptr<int>(new int(revision)); } else { revision_t revision = 0; @@ -280,25 +294,17 @@ IPAACA_EXPORT boost::shared_ptr<int> CallbackIUResendRequest::call(const std::st IPAACA_EXPORT OutputBuffer::OutputBuffer(const std::string& basename, const std::string& channel) :Buffer(basename, "OB") { - //IPAACA_INFO("Entering ...") _id_prefix = _basename + "-" + _uuid + "-IU-"; _channel = (channel=="") ? __ipaaca_static_option_default_channel: channel; _initialize_server(); - //IPAACA_INFO("... exiting.") } IPAACA_EXPORT void OutputBuffer::_initialize_server() { - //IPAACA_INFO("Entering ...") _server = getFactory().createLocalServer( Scope( _unique_name ) ); - //_server = getFactory().createServer( Scope( _unique_name ) ); - //IPAACA_INFO("Registering methods") _server->registerMethod("updatePayload", Server::CallbackPtr(new CallbackIUPayloadUpdate(this))); _server->registerMethod("updateLinks", Server::CallbackPtr(new CallbackIULinkUpdate(this))); _server->registerMethod("commit", Server::CallbackPtr(new CallbackIUCommission(this))); - // dlw _server->registerMethod("resendRequest", Server::CallbackPtr(new CallbackIUResendRequest(this))); - - //IPAACA_INFO("... exiting.") } IPAACA_EXPORT OutputBuffer::ptr OutputBuffer::create(const std::string& basename) { @@ -362,11 +368,6 @@ IPAACA_EXPORT void OutputBuffer::_send_iu_commission(IUInterface* iu, revision_t informer->publish(data); } - - - - - IPAACA_EXPORT void OutputBuffer::add(IU::ptr iu) { if (_iu_store.count(iu->uid()) > 0) { @@ -374,12 +375,14 @@ IPAACA_EXPORT void OutputBuffer::add(IU::ptr iu) } if (iu->is_published()) { throw IUPublishedError(); + } else if (iu->retracted()) { + throw IURetractedError(); } if (iu->access_mode() != IU_ACCESS_MESSAGE) { // (for Message-type IUs: do not actually store them) _iu_store[iu->uid()] = iu; } - iu->_associate_with_buffer(this); //shared_from_this()); + iu->_associate_with_buffer(this); _publish_iu(iu); } @@ -397,17 +400,14 @@ IPAACA_EXPORT void OutputBuffer::_publish_iu_resend(IU::ptr iu, const std::strin informer->publish(iu_data); } - - - IPAACA_EXPORT Informer<AnyType>::Ptr OutputBuffer::_get_informer(const std::string& category) { if (_informer_store.count(category) > 0) { return _informer_store[category]; } else { - //IPAACA_INFO("Making new informer for category " << category) + //IPAACA_INFO("Creating new informer for category " << category << " on channel " << _channel) std::string scope_string = "/ipaaca/channel/" + _channel + "/category/" + category; - IPAACA_INFO("Adding informer on " << scope_string) + IPAACA_INFO("Creating new informer for " << scope_string) Informer<AnyType>::Ptr informer = getFactory().createInformer<AnyType> ( Scope(scope_string)); _informer_store[category] = informer; @@ -433,6 +433,8 @@ IPAACA_EXPORT boost::shared_ptr<IU> OutputBuffer::remove(IU::ptr iu) IPAACA_EXPORT void OutputBuffer::_retract_iu(IU::ptr iu) { + if (iu->_retracted) return; // ignore subsequent retractions + iu->_retracted = true; Informer<protobuf::IURetraction>::DataPtr data(new protobuf::IURetraction()); data->set_uid(iu->uid()); data->set_revision(iu->revision()); @@ -440,6 +442,19 @@ IPAACA_EXPORT void OutputBuffer::_retract_iu(IU::ptr iu) informer->publish(data); } +IPAACA_EXPORT void OutputBuffer::_retract_all_internal() +{ + for (IUStore::iterator it=_iu_store.begin(); it!=_iu_store.end(); ++it) { + if (!(it->second->_retracted)) { + _retract_iu(it->second); + } + } +} + +IPAACA_EXPORT OutputBuffer::~OutputBuffer() +{ + _retract_all_internal(); +} //}}} @@ -448,7 +463,6 @@ IPAACA_EXPORT InputBuffer::InputBuffer(const BufferConfiguration& bufferconfigur :Buffer(bufferconfiguration.get_basename(), "IB") { _channel = bufferconfiguration.get_channel(); - for (std::vector<std::string>::const_iterator it=bufferconfiguration.get_category_interests().begin(); it!=bufferconfiguration.get_category_interests().end(); ++it) { _create_category_listener_if_needed(*it); } @@ -459,7 +473,6 @@ IPAACA_EXPORT InputBuffer::InputBuffer(const std::string& basename, const std::s :Buffer(basename, "IB") { _channel = __ipaaca_static_option_default_channel; - for (std::set<std::string>::const_iterator it=category_interests.begin(); it!=category_interests.end(); ++it) { _create_category_listener_if_needed(*it); } @@ -470,29 +483,16 @@ IPAACA_EXPORT InputBuffer::InputBuffer(const std::string& basename, const std::v :Buffer(basename, "IB") { _channel = __ipaaca_static_option_default_channel; - for (std::vector<std::string>::const_iterator it=category_interests.begin(); it!=category_interests.end(); ++it) { _create_category_listener_if_needed(*it); } _create_category_listener_if_needed(_uuid); triggerResend = false; } -/*IPAACA_EXPORT InputBuffer::InputBuffer(const std::string& basename, const std::initializer_list<std::string>& category_interests) -:Buffer(basename, "IB") -{ - _channel = __ipaaca_static_option_default_channel; - - for (std::initializer_list<std::string>::const_iterator it=category_interests.begin(); it!=category_interests.end(); ++it) { - _create_category_listener_if_needed(*it); - } - _create_category_listener_if_needed(_uuid); - triggerResend = false; -}*/ IPAACA_EXPORT InputBuffer::InputBuffer(const std::string& basename, const std::string& category_interest1) :Buffer(basename, "IB") { _channel = __ipaaca_static_option_default_channel; - _create_category_listener_if_needed(category_interest1); _create_category_listener_if_needed(_uuid); triggerResend = false; @@ -501,7 +501,6 @@ IPAACA_EXPORT InputBuffer::InputBuffer(const std::string& basename, const std::s :Buffer(basename, "IB") { _channel = __ipaaca_static_option_default_channel; - _create_category_listener_if_needed(category_interest1); _create_category_listener_if_needed(category_interest2); _create_category_listener_if_needed(_uuid); @@ -511,7 +510,6 @@ IPAACA_EXPORT InputBuffer::InputBuffer(const std::string& basename, const std::s :Buffer(basename, "IB") { _channel = __ipaaca_static_option_default_channel; - _create_category_listener_if_needed(category_interest1); _create_category_listener_if_needed(category_interest2); _create_category_listener_if_needed(category_interest3); @@ -522,7 +520,6 @@ IPAACA_EXPORT InputBuffer::InputBuffer(const std::string& basename, const std::s :Buffer(basename, "IB") { _channel = __ipaaca_static_option_default_channel; - _create_category_listener_if_needed(category_interest1); _create_category_listener_if_needed(category_interest2); _create_category_listener_if_needed(category_interest3); @@ -567,7 +564,6 @@ IPAACA_EXPORT InputBuffer::ptr InputBuffer::create(const std::string& basename, return InputBuffer::ptr(new InputBuffer(basename, category_interest1, category_interest2, category_interest3, category_interest4)); } - IPAACA_EXPORT void InputBuffer::set_resend(bool resendActive) { triggerResend = resendActive; @@ -578,21 +574,19 @@ IPAACA_EXPORT bool InputBuffer::get_resend() return triggerResend; } - IPAACA_EXPORT IUInterface::ptr InputBuffer::get(const std::string& iu_uid) { - RemotePushIUStore::iterator it = _iu_store.find(iu_uid); // TODO genericize + RemotePushIUStore::iterator it = _iu_store.find(iu_uid); if (it==_iu_store.end()) return IUInterface::ptr(); return it->second; } IPAACA_EXPORT std::set<IUInterface::ptr> InputBuffer::get_ius() { std::set<IUInterface::ptr> set; - for (RemotePushIUStore::iterator it=_iu_store.begin(); it!=_iu_store.end(); ++it) set.insert(it->second); // TODO genericize + for (RemotePushIUStore::iterator it=_iu_store.begin(); it!=_iu_store.end(); ++it) set.insert(it->second); return set; } - IPAACA_EXPORT RemoteServerPtr InputBuffer::_get_remote_server(const std::string& unique_server_name) { std::map<std::string, RemoteServerPtr>::iterator it = _remote_server_store.find(unique_server_name); @@ -608,11 +602,10 @@ IPAACA_EXPORT ListenerPtr InputBuffer::_create_category_listener_if_needed(const if (it!=_listener_store.end()) { return it->second; } - //IPAACA_INFO("Creating a new listener for category " << category) std::string scope_string = "/ipaaca/channel/" + _channel + "/category/" + category; + IPAACA_INFO("Creating new listener for " << scope_string) ListenerPtr listener = getFactory().createListener( Scope(scope_string) ); - IPAACA_INFO("Adding listener on " << scope_string) HandlerPtr event_handler = HandlerPtr( new EventFunctionHandler( boost::bind(&InputBuffer::_handle_iu_events, this, _1) @@ -640,7 +633,8 @@ IPAACA_EXPORT void InputBuffer::_trigger_resend_request(EventPtr event) { uid = update->uid(); writerName = update->writer_name(); } else { - std::cout << "_trigger_resend_request: unhandled event type " << type << std::endl; + IPAACA_ERROR("_trigger_resend_request: called for unhandled event type " << type) + return; } if (!writerName.empty()) { @@ -652,8 +646,6 @@ IPAACA_EXPORT void InputBuffer::_trigger_resend_request(EventPtr event) { boost::shared_ptr<int> result = server->call<int>("resendRequest", update, IPAACA_REMOTE_SERVER_TIMEOUT); if (*result == 0) { throw IUResendRequestFailedError(); - } else { - //std::cout << "revision " << *result << std::endl; } } } @@ -670,33 +662,24 @@ IPAACA_EXPORT void InputBuffer::_handle_iu_events(EventPtr event) iu->_set_buffer(this); call_iu_event_handlers(iu, false, IU_ADDED, iu->category() ); } - //IPAACA_INFO( "New RemotePushIU state: " << (*iu) ) } else if (type == "ipaaca::RemoteMessage") { boost::shared_ptr<RemoteMessage> iu = boost::static_pointer_cast<RemoteMessage>(event->getData()); - //_iu_store[iu->uid()] = iu; - //iu->_set_buffer(this); - //std::cout << "REFCNT after cast, before calling handlers: " << iu.use_count() << std::endl; call_iu_event_handlers(iu, false, IU_MESSAGE, iu->category() ); - //_iu_store.erase(iu->uid()); } else { RemotePushIUStore::iterator it; if (type == "ipaaca::IUPayloadUpdate") { boost::shared_ptr<IUPayloadUpdate> update = boost::static_pointer_cast<IUPayloadUpdate>(event->getData()); - //IPAACA_INFO("** writer name: " << update->writer_name) - std::cout << "writer name " << update->writer_name << std::endl; if (update->writer_name == _unique_name) { return; } it = _iu_store.find(update->uid); if (it == _iu_store.end()) { _trigger_resend_request(event); - IPAACA_INFO("Using UPDATED message for an IU that we did not fully receive before") + IPAACA_INFO("UPDATED message for an IU that we did not fully receive before") return; } - it->second->_apply_update(update); call_iu_event_handlers(it->second, false, IU_UPDATED, it->second->category() ); - } else if (type == "ipaaca::IULinkUpdate") { boost::shared_ptr<IULinkUpdate> update = boost::static_pointer_cast<IULinkUpdate>(event->getData()); if (update->writer_name == _unique_name) { @@ -705,13 +688,11 @@ IPAACA_EXPORT void InputBuffer::_handle_iu_events(EventPtr event) it = _iu_store.find(update->uid); if (it == _iu_store.end()) { _trigger_resend_request(event); - IPAACA_INFO("Ignoring LINKSUPDATED message for an IU that we did not fully receive before") + IPAACA_INFO("LINKSUPDATED message for an IU that we did not fully receive before") return; } - it->second->_apply_link_update(update); call_iu_event_handlers(it->second, false, IU_LINKSUPDATED, it->second->category() ); - } else if (type == "ipaaca::protobuf::IUCommission") { boost::shared_ptr<protobuf::IUCommission> update = boost::static_pointer_cast<protobuf::IUCommission>(event->getData()); if (update->writer_name() == _unique_name) { @@ -720,36 +701,31 @@ IPAACA_EXPORT void InputBuffer::_handle_iu_events(EventPtr event) it = _iu_store.find(update->uid()); if (it == _iu_store.end()) { _trigger_resend_request(event); - IPAACA_INFO("Ignoring COMMITTED message for an IU that we did not fully receive before") + IPAACA_INFO("COMMITTED message for an IU that we did not fully receive before") return; } - // it->second->_apply_commission(); it->second->_revision = update->revision(); call_iu_event_handlers(it->second, false, IU_COMMITTED, it->second->category() ); - // - // } else if (type == "ipaaca::protobuf::IURetraction") { boost::shared_ptr<protobuf::IURetraction> update = boost::static_pointer_cast<protobuf::IURetraction>(event->getData()); it = _iu_store.find(update->uid()); if (it == _iu_store.end()) { - _trigger_resend_request(event); IPAACA_INFO("Ignoring RETRACTED message for an IU that we did not fully receive before") return; } - // it->second->_revision = update->revision(); it->second->_apply_retraction(); - // remove from InputBuffer FIXME: this is a crossover between retracted and deleted behavior - _iu_store.erase(it->first); - // and call the handler. IU reference is still valid for this call, although removed from buffer. - call_iu_event_handlers(it->second, false, IU_COMMITTED, it->second->category() ); + auto final_iu_ref = it->second; + ////// remove from InputBuffer? FIXME: unclear issue - resolve in ipaaca3 + ////_iu_store.erase(it->first); + // and call the handler. IU reference is still valid for this call, even if removed from buffer. + call_iu_event_handlers(final_iu_ref, false, IU_RETRACTED, it->second->category() ); // } else { - std::cout << "(Unhandled Event type " << type << " !)" << std::endl; + IPAACA_WARNING("(Unhandled Event type " << type << " !)"); return; } - //IPAACA_INFO( "New RemotePushIU state: " << *(it->second) ) } } //}}} diff --git a/ipaacalib/cpp/src/ipaaca-cmdline-parser.cc b/ipaacalib/cpp/src/ipaaca-cmdline-parser.cc index e08b33ea34b07381ac4b58e5fadced473706f362..4f37698868fc9d945bf09134b71f3ea8f2e4961e 100644 --- a/ipaacalib/cpp/src/ipaaca-cmdline-parser.cc +++ b/ipaacalib/cpp/src/ipaaca-cmdline-parser.cc @@ -3,8 +3,9 @@ * "Incremental Processing Architecture * for Artificial Conversational Agents". * - * Copyright (c) 2009-2013 Sociable Agents Group - * CITEC, Bielefeld University + * 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 @@ -70,9 +71,7 @@ void CommandLineOptions::dump() { } } -// // Command line parser implementation -// CommandLineParser::CommandLineParser() : library_options_handled(true) @@ -91,6 +90,8 @@ void CommandLineParser::initialize_parser_defaults() add_option("ipaaca-default-channel", 0, true, "default"); add_option("ipaaca-enable-logging", 0, true, "WARNING"); add_option("rsb-enable-logging", 0, true, "ERROR"); + add_option("rsb-spread-host", 0, true, ""); // empty = don't set + add_option("rsb-spread-port", 0, true, ""); // empty = don't set } } @@ -109,6 +110,14 @@ bool CommandLineParser::consume_library_option(const std::string& name, bool exp std::string newch = optarg; IPAACA_DEBUG("Setting default channel " << newch) __ipaaca_static_option_default_channel = newch; + } else if (name=="rsb-spread-host") { + std::string newhost = optarg; + IPAACA_DEBUG("Setting RSB Spread host " << newhost) + __ipaaca_static_option_rsb_spread_host = newhost; + } else if (name=="rsb-spread-port") { + std::string newport = optarg; + IPAACA_DEBUG("Setting RSB Spread port " << newport) + __ipaaca_static_option_rsb_spread_port = newport; } else if (name=="ipaaca-enable-logging") { std::string level(optarg); if ((level=="NONE") || (level=="SILENT")) { @@ -173,7 +182,7 @@ void CommandLineParser::add_option(const std::string& optname, char shortoptn, b CommandLineOptions::ptr CommandLineParser::parse(int argc, char* const* argv) { #ifdef WIN32 - LOG_IPAACA_CONSOLE("IMPLEMENT ME: command line parsing for Windows. (req'd: getopt)") + IPAACA_ERROR("IMPLEMENT ME: command line parsing for Windows. (req'd: getopt)") throw NotImplementedError(); #else IPAACA_DEBUG("") diff --git a/ipaacalib/cpp/src/ipaaca-fake.cc b/ipaacalib/cpp/src/ipaaca-fake.cc index c0d27977a0a6574ae9219a3f733a9f1800d7e9a9..a5277ec3e57913b6febf9b70e5b80dc0296e7e5f 100644 --- a/ipaacalib/cpp/src/ipaaca-fake.cc +++ b/ipaacalib/cpp/src/ipaaca-fake.cc @@ -31,6 +31,7 @@ * Excellence Initiative. */ +#ifdef IPAACA_BUILD_MOCK_OBJECTS #include <ipaaca/ipaaca.h> namespace ipaaca { @@ -62,4 +63,5 @@ IPAACA_EXPORT inline void FakeIU::_apply_retraction() { } } // of namespace ipaaca +#endif diff --git a/ipaacalib/cpp/src/ipaaca-internal.cc b/ipaacalib/cpp/src/ipaaca-internal.cc index 1ce8f5f467648919b4728b2ce2e694447c5ba54c..364ca34596d3cbddfa87ae197f1ce82b7e4cb22e 100644 --- a/ipaacalib/cpp/src/ipaaca-internal.cc +++ b/ipaacalib/cpp/src/ipaaca-internal.cc @@ -51,14 +51,9 @@ IPAACA_EXPORT void Initializer::initialize_backend()//{{{ { if (_initialized) return; - //IPAACA_INFO("Calling auto_configure_rsb()") auto_configure_rsb(); - // RYT FIXME This configuration stuff has been simply removed in rsb! - //ParticipantConfig config = ParticipantConfig::fromConfiguration(); - //getFactory().setDefaultParticipantConfig(config); - - //IPAACA_INFO("Creating and registering Converters") + IPAACA_DEBUG("Creating and registering Converters") boost::shared_ptr<IUConverter> iu_converter(new IUConverter()); converterRepository<std::string>()->registerConverter(iu_converter); @@ -84,9 +79,8 @@ IPAACA_EXPORT void Initializer::initialize_backend()//{{{ boost::shared_ptr<IntConverter> int_converter(new IntConverter()); converterRepository<std::string>()->registerConverter(int_converter); - //IPAACA_INFO("Initialization complete.") + IPAACA_DEBUG("Backend / converter initialization complete.") _initialized = true; - //IPAACA_TODO("initialize all converters") }//}}} IPAACA_EXPORT void Initializer::dump_current_default_config()//{{{ { @@ -103,17 +97,23 @@ IPAACA_EXPORT void Initializer::dump_current_default_config()//{{{ }//}}} IPAACA_EXPORT void Initializer::auto_configure_rsb()//{{{ { - // quick hack to iterate through the pwd parents - // and find the closest rsb plugin dir - // - // but only if not yet defined + // set RSB host and port iff provided using cmdline arguments + if (__ipaaca_static_option_rsb_spread_host!="") { + IPAACA_INFO("Overriding RSB Spread host with " << __ipaaca_static_option_rsb_spread_host) + setenv("RSB_TRANSPORT_SPREAD_HOST", __ipaaca_static_option_rsb_spread_host.c_str(), 1); + } + if (__ipaaca_static_option_rsb_spread_port!="") { + IPAACA_INFO("Overriding RSB Spread port with " << __ipaaca_static_option_rsb_spread_port) + setenv("RSB_TRANSPORT_SPREAD_PORT", __ipaaca_static_option_rsb_spread_port.c_str(), 1); + } + 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.") + IPAACA_WARN("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.") + IPAACA_INFO("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"; @@ -122,7 +122,7 @@ IPAACA_EXPORT void Initializer::auto_configure_rsb()//{{{ 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) + IPAACA_INFO("Found an RSB plugin dir which will be used automatically: " << found_path) setenv("RSB_PLUGINS_CPP_PATH", found_path, 1); break; } // else keep going @@ -131,7 +131,7 @@ IPAACA_EXPORT void Initializer::auto_configure_rsb()//{{{ } #endif } else { - LOG_IPAACA_CONSOLE("RSB_PLUGINS_CPP_PATH already defined: " << plugin_path) + IPAACA_INFO("RSB_PLUGINS_CPP_PATH already defined: " << plugin_path) } }//}}} @@ -145,10 +145,7 @@ IPAACA_EXPORT IUConverter::IUConverter() 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 @@ -175,8 +172,6 @@ IPAACA_EXPORT std::string IUConverter::serialize(const AnnotatedData& data, std: for (auto& kv: obj->_payload._document_store) { protobuf::PayloadItem* item = pbo->add_payload(); item->set_key(kv.first); - //item->set_value( kv.second->to_json_string_representation() ); - //item->set_type("JSON"); IPAACA_DEBUG("Payload type: " << obj->_payload_type) if (obj->_payload_type=="JSON") { item->set_value( kv.second->to_json_string_representation() ); @@ -197,20 +192,16 @@ IPAACA_EXPORT std::string IUConverter::serialize(const AnnotatedData& data, std: 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); @@ -249,7 +240,6 @@ IPAACA_EXPORT AnnotatedData IUConverter::deserialize(const std::string& wireSche ls.insert(pls.targets(j)); } } - //return std::make_pair(getDataType(), obj); return std::make_pair("ipaaca::RemotePushIU", obj); break; } @@ -287,12 +277,11 @@ IPAACA_EXPORT AnnotatedData IUConverter::deserialize(const std::string& wireSche 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 ) + // no other cases (yet) throw NotImplementedError(); } } @@ -307,9 +296,7 @@ IPAACA_EXPORT MessageConverter::MessageConverter() 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 @@ -336,8 +323,6 @@ IPAACA_EXPORT std::string MessageConverter::serialize(const AnnotatedData& data, for (auto& kv: obj->_payload._document_store) { protobuf::PayloadItem* item = pbo->add_payload(); item->set_key(kv.first); - //item->set_value( kv.second->to_json_string_representation() ); - //item->set_type("JSON"); if (obj->_payload_type=="JSON") { item->set_value( kv.second->to_json_string_representation() ); item->set_type("JSON"); @@ -361,7 +346,6 @@ IPAACA_EXPORT std::string MessageConverter::serialize(const AnnotatedData& data, case IU_ACCESS_MESSAGE: return "ipaaca-messageiu"; default: - //std::cout << "Requesting to send as default" << std::endl; return getWireSchema(); } @@ -406,7 +390,6 @@ IPAACA_EXPORT AnnotatedData MessageConverter::deserialize(const std::string& wir ls.insert(pls.targets(j)); } } - //return std::make_pair(getDataType(), obj); return std::make_pair("ipaaca::RemotePushIU", obj); break; } @@ -443,12 +426,11 @@ IPAACA_EXPORT AnnotatedData MessageConverter::deserialize(const std::string& wir 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 ) + // no other cases (yet) throw NotImplementedError(); } } @@ -536,7 +518,7 @@ IPAACA_EXPORT IULinkUpdateConverter::IULinkUpdateConverter() IPAACA_EXPORT std::string IULinkUpdateConverter::serialize(const AnnotatedData& data, std::string& wire) { - assert(data.first == getDataType()); // "ipaaca::IULinkUpdate" + assert(data.first == getDataType()); 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 @@ -598,8 +580,7 @@ IPAACA_EXPORT IntConverter::IntConverter() 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" + assert(data.first == getDataType()); // 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()); diff --git a/ipaacalib/cpp/src/ipaaca-iuinterface.cc b/ipaacalib/cpp/src/ipaaca-iuinterface.cc index 2c36848cbc6c29df0fc794e31e2927f6689d289e..1ea5975c4c8b3370642ac81a157a89d5e34576d5 100644 --- a/ipaacalib/cpp/src/ipaaca-iuinterface.cc +++ b/ipaacalib/cpp/src/ipaaca-iuinterface.cc @@ -70,7 +70,7 @@ IPAACA_EXPORT void IUInterface::_set_uid(const std::string& uid) { _uid = uid; } -IPAACA_EXPORT void IUInterface::_set_buffer(Buffer* buffer) { //boost::shared_ptr<Buffer> buffer) { +IPAACA_EXPORT void IUInterface::_set_buffer(Buffer* buffer) { if (_buffer) { throw IUAlreadyInABufferError(); } @@ -86,7 +86,7 @@ IPAACA_EXPORT void IUInterface::_set_owner_name(const std::string& 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) { +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()); diff --git a/ipaacalib/cpp/src/ipaaca-ius.cc b/ipaacalib/cpp/src/ipaaca-ius.cc index 07caeb65b2ed42aa132b265f75113c3e8bb6a87a..2626302121779f490b2d10d3af03f7e7c0da8e91 100644 --- a/ipaacalib/cpp/src/ipaaca-ius.cc +++ b/ipaacalib/cpp/src/ipaaca-ius.cc @@ -62,6 +62,7 @@ IPAACA_EXPORT IU::IU(const std::string& category, IUAccessMode access_mode, bool _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) @@ -70,6 +71,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()) { @@ -78,27 +82,6 @@ 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, PayloadDocumentEntry::ptr>& new_items, const std::vector<std::string>& keys_to_remove, const std::string& writer_name) { IPAACA_INFO("") @@ -106,6 +89,9 @@ IPAACA_EXPORT void IU::_modify_payload(bool is_delta, const std::map<std::string if (_committed) { _revision_lock.unlock(); throw IUCommittedError(); + } else if (_retracted) { + _revision_lock.unlock(); + throw IURetractedError(); } _increase_revision_number(); if (is_published()) { @@ -134,6 +120,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; @@ -186,20 +175,20 @@ 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); @@ -219,11 +208,12 @@ IPAACA_EXPORT void RemotePushIU::_modify_links(bool is_delta, const LinkMap& new } 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); @@ -247,6 +237,8 @@ IPAACA_EXPORT void RemotePushIU::commit() { if (_read_only) { throw IUReadOnlyError(); + } else if (_retracted) { + throw IURetractedError(); } if (_committed) { // Following python version: ignoring multiple commit @@ -305,13 +297,12 @@ 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) { diff --git a/ipaacalib/cpp/src/ipaaca-json.cc b/ipaacalib/cpp/src/ipaaca-json.cc index dfdd83ee63adc0603c0f9340cd017d33bd14f9e7..2c2d1cd937e3ac0b7187dde5fb649ca276b20689 100644 --- a/ipaacalib/cpp/src/ipaaca-json.cc +++ b/ipaacalib/cpp/src/ipaaca-json.cc @@ -31,11 +31,34 @@ * 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; @@ -107,6 +130,7 @@ int batch_update_main(int argc, char** argv)//{{{ } //}}} +#ifdef IPAACA_BUILD_MOCK_OBJECTS int iterators_main(int argc, char** argv)//{{{ { std::string json_source("[\n\ @@ -408,6 +432,7 @@ int fakeiu_main(int argc, char** argv)//{{{ return 0; } //}}} +#endif int legacy_iu_main(int argc, char** argv)//{{{ { diff --git a/ipaacalib/cpp/src/ipaaca-links.cc b/ipaacalib/cpp/src/ipaaca-links.cc index e0a6229068126ee2004768a040a4327efe8a32b4..33ff812efffa46ec3f7a42cf1bc316d4bef6763b 100644 --- a/ipaacalib/cpp/src/ipaaca-links.cc +++ b/ipaacalib/cpp/src/ipaaca-links.cc @@ -87,7 +87,6 @@ IPAACA_EXPORT void SmartLinkMap::_add_and_remove_links(const LinkMap& add, const } IPAACA_EXPORT void SmartLinkMap::_replace_links(const LinkMap& links) { - //_links.clear(); _links=links; } IPAACA_EXPORT const LinkSet& SmartLinkMap::get_links(const std::string& key) diff --git a/ipaacalib/cpp/src/ipaaca-payload.cc b/ipaacalib/cpp/src/ipaaca-payload.cc index 4047162a7630dc363318f2b4d62fc008e860fdc3..31a02c14b9df21ce6389e78d66532e39727095bf 100644 --- a/ipaacalib/cpp/src/ipaaca-payload.cc +++ b/ipaacalib/cpp/src/ipaaca-payload.cc @@ -53,10 +53,8 @@ std::string value_diagnosis(rapidjson::Value* val) 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); @@ -95,10 +93,10 @@ double strict_numerical_interpretation(const std::string& str) char* endptr; auto s = str_trim(str); const char* startptr = s.c_str(); - long l = strtod(startptr, &endptr); + double d = strtod(startptr, &endptr); if ((*endptr)=='\0') { // everything could be parsed - return l; + return d; } else { throw PayloadTypeConversionError(); } @@ -126,12 +124,6 @@ IPAACA_EXPORT template<> long json_value_cast(const rapidjson::Value& v) if (v.IsNull()) return 0l; // default: return parse of string version (should always be 0 though?) throw PayloadTypeConversionError(); - /* - rapidjson::StringBuffer buffer; - rapidjson::Writer<rapidjson::StringBuffer> writer(buffer); - v.Accept(writer); - return atol(std::string(buffer.GetString()).c_str()); - */ } IPAACA_EXPORT template<> int json_value_cast(const rapidjson::Value& v) { @@ -162,7 +154,6 @@ IPAACA_EXPORT template<> bool json_value_cast(const rapidjson::Value& v) if (v.IsString()) { std::string s = v.GetString(); return !((s=="")||(s=="false")||(s=="False")||(s=="0")); - //return ((s=="1")||(s=="true")||(s=="True")); } if (v.IsBool()) return v.GetBool(); if (v.IsNull()) return false; @@ -174,12 +165,6 @@ IPAACA_EXPORT template<> bool json_value_cast(const rapidjson::Value& v) // default: assume "pointer-like" semantics (i.e. objects are TRUE) return true; } -/* - * std::map<std::string, std::string> result; - std::for_each(_document_store.begin(), _document_store.end(), [&result](std::pair<std::string, PayloadDocumentEntry::ptr> pair) { - result[pair.first] = pair.second->document.GetString(); - }); - */ //}}} IPAACA_EXPORT void pack_into_json_value(rapidjson::Value& valueobject, rapidjson::Document::AllocatorType& allocator, int newvalue) @@ -206,25 +191,6 @@ IPAACA_EXPORT void pack_into_json_value(rapidjson::Value& valueobject, rapidjson { valueobject.SetString(newvalue, allocator); } -/* -IPAACA_EXPORT template<> void pack_into_json_value(rapidjson::Value& valueobject, rapidjson::Document::AllocatorType& allocator, const std::vector<std::string>& newvalue) -{ - valueobject.SetArray(); - for (auto& str: newvalue) { - rapidjson::Value sv; - sv.SetString(str, allocator); - valueobject.PushBack(sv, allocator); - } -} -IPAACA_EXPORT template<> void pack_into_json_value(rapidjson::Value& valueobject, rapidjson::Document::AllocatorType& allocator, const std::list<std::string>& newvalue) -{ - IPAACA_IMPLEMENT_ME -} -IPAACA_EXPORT template<> void pack_into_json_value(rapidjson::Value& valueobject, rapidjson::Document::AllocatorType& allocator, const std::map<std::string, std::string>& newvalue) -{ - IPAACA_IMPLEMENT_ME -} -*/ // PayloadDocumentEntry//{{{ IPAACA_EXPORT std::string PayloadDocumentEntry::to_json_string_representation() @@ -240,37 +206,25 @@ IPAACA_EXPORT PayloadDocumentEntry::ptr PayloadDocumentEntry::from_json_string_r if (entry->document.Parse(json_str.c_str()).HasParseError()) { throw JsonParsingError(); } - //entry->json_source = json_str; 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()); - //entry->update_json_source(); return entry; } -/// update json_source after a write operation (on newly cloned entries) -/* -IPAACA_EXPORT void PayloadDocumentEntry::update_json_source() -{ - json_source = to_json_string_representation(); -} -*/ - IPAACA_EXPORT PayloadDocumentEntry::ptr PayloadDocumentEntry::create_null() { PayloadDocumentEntry::ptr entry = std::make_shared<ipaaca::PayloadDocumentEntry>(); - //entry->json_source = "null"; // rapidjson::Document value is also null implicitly return entry; } IPAACA_EXPORT PayloadDocumentEntry::ptr PayloadDocumentEntry::clone() { - //auto entry = PayloadDocumentEntry::from_json_string_representation(this->json_source); auto entry = PayloadDocumentEntry::create_null(); entry->document.CopyFrom(this->document, entry->document.GetAllocator()); - IPAACA_DEBUG("Cloned for copy-on-write, contents: " << entry) + 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) @@ -282,6 +236,7 @@ IPAACA_EXPORT rapidjson::Value& PayloadDocumentEntry::get_or_create_nested_value 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; @@ -292,42 +247,13 @@ IPAACA_EXPORT rapidjson::Value& PayloadDocumentEntry::get_or_create_nested_value throw PayloadAddressingError(); } } - // for append / push_back? : - /*if (parent_value.IsNull()) { - wasnull = true; - parent_value.SetArray(); - } - if (wasnull || parent_value.IsArray()) { - long idx = pep->addressed_index; - long s = parent_value.Size(); - if (idx<s) { - // existing element modified - parent_value[idx] = *json_value; - } else { - // implicitly initialize missing elements to null values - if (idx>s) { - long missing_elements = pep->addressed_index - p; - for (int i=0; i<missing_elements; ++i) { - parent_value.PushBack(, allocator) - } - } - } - if (s == - } else { - throw PayloadAddressingError(); - }*/ } else { IPAACA_DEBUG("Addressed as dict with key " << pep->addressed_key) - // addressed as object (dict) - //rapidjson::Value& parent_value = *(pep->parent->json_value); if (! parent_value.IsObject()) { - IPAACA_DEBUG("parent is not of type Object") + IPAACA_INFO("parent value is not of type Object") throw PayloadAddressingError(); } else { rapidjson::Document::AllocatorType& allocator = document.GetAllocator(); - //Value key; - //key.SetString(pep->addressed_key, allocator); - //parent_value.AddMember(key, *json_value, allocator); rapidjson::Value key; key.SetString(pep->addressed_key, allocator); auto it = parent_value.FindMember(key); @@ -343,72 +269,10 @@ IPAACA_EXPORT rapidjson::Value& PayloadDocumentEntry::get_or_create_nested_value } } } - //}}} // PayloadEntryProxy//{{{ - // only if not top-level -#if 0 -IPAACA_EXPORT void PayloadEntryProxy::connect_to_existing_parents() -{ - rapidjson::Document::AllocatorType& allocator = document_entry->document.GetAllocator(); - PayloadEntryProxy* pep = this; - while (!(pep->existent) && pep->parent) { // only if not top-level - if (pep->addressed_as_array) { - rapidjson::Value& parent_value = *(pep->parent->json_value); - if (! parent_value.IsArray()) { - throw PayloadAddressingError(); - } else { - long idx = pep->addressed_index; - long s = parent_value.Size(); - if (idx<s) { - parent_value[idx] = *json_value; - } else { - throw PayloadAddressingError(); - } - } - /*if (parent_value.IsNull()) { - wasnull = true; - parent_value.SetArray(); - } - if (wasnull || parent_value.IsArray()) { - long idx = pep->addressed_index; - long s = parent_value.Size(); - if (idx<s) { - // existing element modified - parent_value[idx] = *json_value; - } else { - // implicitly initialize missing elements to null values - if (idx>s) { - long missing_elements = pep->addressed_index - p; - for (int i=0; i<missing_elements; ++i) { - parent_value.PushBack(, allocator) - } - } - } - if (s == - } else { - throw PayloadAddressingError(); - }*/ - } else { - // addressed as object (dict) - rapidjson::Value& parent_value = *(pep->parent->json_value); - if (! parent_value.IsObject()) { - throw PayloadAddressingError(); - } else { - Value key; - key.SetString(pep->addressed_key, allocator); - parent_value.AddMember(key, *json_value, allocator); - } - } - // repeat for next parent in the tree - pep = pep->parent; - } -} -#endif - - IPAACA_EXPORT PayloadEntryProxy::PayloadEntryProxy(Payload* payload, const std::string& key) : _payload(payload), _key(key), parent(nullptr) { @@ -447,11 +311,11 @@ IPAACA_EXPORT PayloadEntryProxy PayloadEntryProxy::operator[](const char* addr_k IPAACA_EXPORT PayloadEntryProxy PayloadEntryProxy::operator[](const std::string& addr_key_) { if (!json_value) { - IPAACA_DEBUG("Invalid json_value!") + IPAACA_INFO("Invalid json_value") throw PayloadAddressingError(); } if (! json_value->IsObject()) { - IPAACA_DEBUG("Expected Object for operator[](string)!") + IPAACA_INFO("Expected Object for operator[](string)") throw PayloadAddressingError(); } return PayloadEntryProxy(this, addr_key_); @@ -459,16 +323,16 @@ IPAACA_EXPORT PayloadEntryProxy PayloadEntryProxy::operator[](const std::string& IPAACA_EXPORT PayloadEntryProxy PayloadEntryProxy::operator[](size_t addr_idx_) { if (!json_value) { - IPAACA_DEBUG("Invalid json_value!") + IPAACA_INFO("Invalid json_value") throw PayloadAddressingError(); } if (! json_value->IsArray()) { - IPAACA_DEBUG("Expected Array for operator[](size_t)!") + IPAACA_INFO("Expected Array for operator[](size_t)") throw PayloadAddressingError(); } long s = json_value->Size(); if (addr_idx_>=s) { - IPAACA_DEBUG("Array out of bounds!") + IPAACA_INFO("Array out of bounds") throw PayloadAddressingError(); } return PayloadEntryProxy(this, addr_idx_); @@ -476,7 +340,7 @@ IPAACA_EXPORT PayloadEntryProxy PayloadEntryProxy::operator[](size_t addr_idx_) IPAACA_EXPORT PayloadEntryProxy PayloadEntryProxy::operator[](int addr_idx_) { if (addr_idx_ < 0) { - IPAACA_DEBUG("Negative index!") + IPAACA_INFO("Negative array index") throw PayloadAddressingError(); } return operator[]((size_t) addr_idx_); @@ -490,81 +354,41 @@ IPAACA_EXPORT PayloadEntryProxy& PayloadEntryProxy::operator=(const PayloadEntry if (valueptr) { // only set if value is valid, keep default null value otherwise newval.CopyFrom(*valueptr, new_entry->document.GetAllocator()); } - //new_entry->update_json_source(); _payload->set(_key, new_entry); return *this; } -/* -IPAACA_EXPORT PayloadEntryProxy& PayloadEntryProxy::operator=(const std::string& value) -{ - //std::cout << "operator=(string)" << std::endl; - IPAACA_IMPLEMENT_ME - //_payload->set(_key, value); - return *this; -} -IPAACA_EXPORT PayloadEntryProxy& PayloadEntryProxy::operator=(const char* value) -{ - //std::cout << "operator=(const char*)" << std::endl; - IPAACA_IMPLEMENT_ME - //_payload->set(_key, value); - return *this; -} -IPAACA_EXPORT PayloadEntryProxy& PayloadEntryProxy::operator=(double value) -{ - //std::cout << "operator=(double)" << std::endl; - IPAACA_IMPLEMENT_ME - //_payload->set(_key, boost::lexical_cast<std::string>(value)); - return *this; -} -IPAACA_EXPORT PayloadEntryProxy& PayloadEntryProxy::operator=(bool value) -{ - //std::cout << "operator=(bool)" << std::endl; - IPAACA_IMPLEMENT_ME - //_payload->set(_key, boost::lexical_cast<std::string>(value)); - return *this; -} -*/ - IPAACA_EXPORT PayloadEntryProxy::operator std::string() { return json_value_cast<std::string>(json_value); - //PayloadEntryProxy::get<std::string>(); } IPAACA_EXPORT PayloadEntryProxy::operator long() { return json_value_cast<long>(json_value); - //return PayloadEntryProxy::get<long>(); } IPAACA_EXPORT PayloadEntryProxy::operator double() { return json_value_cast<double>(json_value); - //return PayloadEntryProxy::get<double>(); } IPAACA_EXPORT PayloadEntryProxy::operator bool() { return json_value_cast<bool>(json_value); - //return PayloadEntryProxy::get<bool>(); } IPAACA_EXPORT std::string PayloadEntryProxy::to_str() { return json_value_cast<std::string>(json_value); - //return PayloadEntryProxy::get<std::string>(); } IPAACA_EXPORT long PayloadEntryProxy::to_long() { return json_value_cast<long>(json_value); - //return PayloadEntryProxy::get<long>(); } IPAACA_EXPORT double PayloadEntryProxy::to_float() { return json_value_cast<double>(json_value); - //return PayloadEntryProxy::get<double>(); } IPAACA_EXPORT bool PayloadEntryProxy::to_bool() { return json_value_cast<bool>(json_value); - //return PayloadEntryProxy::get<bool>(); } IPAACA_EXPORT PayloadEntryProxyMapDecorator PayloadEntryProxy::as_map() @@ -594,8 +418,8 @@ IPAACA_EXPORT bool PayloadEntryProxy::is_string() { return json_value && json_value->IsString(); } -/// is_number => whether it is *interpretable* as -/// a numerical value (i.e. including conversions) + +/// is_number => whether it is *interpretable* as a numerical value (i.e. including conversions) IPAACA_EXPORT bool PayloadEntryProxy::is_number() { if (!json_value) return false; @@ -615,58 +439,6 @@ IPAACA_EXPORT bool PayloadEntryProxy::is_map() return json_value && json_value->IsObject(); } -// -// new stuff for protocol v2 -// - -/* -IPAACA_EXPORT template<> std::string PayloadEntryProxy::get<std::string>() -{ - if (!json_value) return ""; - //IPAACA_INFO( value_diagnosis(json_value) ) - if (json_value->IsString()) return json_value->GetString(); - if (json_value->IsNull()) return ""; - rapidjson::StringBuffer buffer; - rapidjson::Writer<rapidjson::StringBuffer> writer(buffer); - json_value->Accept(writer); - return buffer.GetString(); - - //return _payload->get(_key); -} -IPAACA_EXPORT template<> long PayloadEntryProxy::get<long>() -{ - return atof(operator std::string().c_str()); -} -IPAACA_EXPORT template<> double PayloadEntryProxy::get<double>() -{ - return atol(operator std::string().c_str()); -} -IPAACA_EXPORT template<> bool PayloadEntryProxy::get<bool>() -{ - std::string s = operator std::string(); - return ((s=="1")||(s=="true")||(s=="True")); -} -// complex types -IPAACA_EXPORT template<> std::list<std::string> PayloadEntryProxy::get<std::list<std::string> >() -{ - std::list<std::string> l; - l.push_back(PayloadEntryProxy::get<std::string>()); - return l; -} -IPAACA_EXPORT template<> std::vector<std::string> PayloadEntryProxy::get<std::vector<std::string> >() -{ - std::vector<std::string> v; - v.push_back(PayloadEntryProxy::get<std::string>()); - return v; -} -IPAACA_EXPORT template<> std::map<std::string, std::string> PayloadEntryProxy::get<std::map<std::string, std::string> >() -{ - std::map<std::string, std::string> m; - m["__automatic__"] = PayloadEntryProxy::get<std::string>(); - return m; -} -*/ - //}}} // Payload//{{{ @@ -674,19 +446,19 @@ IPAACA_EXPORT template<> std::map<std::string, std::string> PayloadEntryProxy::g IPAACA_EXPORT void Payload::on_lock() { Locker locker(_payload_operation_mode_lock); - IPAACA_DEBUG("Starting batch update mode ...") + IPAACA_DEBUG("Starting payload batch update mode ...") _update_on_every_change = false; } IPAACA_EXPORT void Payload::on_unlock() { Locker locker(_payload_operation_mode_lock); - IPAACA_DEBUG("... applying batch update with " << _collected_modifications.size() << " modifications and " << _collected_removals.size() << " removals ...") + 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 batch update mode.") + IPAACA_DEBUG("... exiting payload batch update mode.") } IPAACA_EXPORT void Payload::initialize(boost::shared_ptr<IUInterface> iu) @@ -696,8 +468,6 @@ IPAACA_EXPORT void Payload::initialize(boost::shared_ptr<IUInterface> iu) IPAACA_EXPORT PayloadEntryProxy Payload::operator[](const std::string& key) { - // TODO atomicize - //boost::shared_ptr<PayloadEntryProxy> p(new PayloadEntryProxy(this, key)); return PayloadEntryProxy(this, key); } @@ -824,10 +594,6 @@ IPAACA_EXPORT void Payload::set(const std::map<std::string, std::string>& all_el { std::map<std::string, PayloadDocumentEntry::ptr> newmap; for (auto& kv: all_elems) { - /*PayloadDocumentEntry::ptr newit = PayloadDocumentEntry::create_null(); - newit->document.SetString(kv.second, newit->document.GetAllocator()); - newit->update_json_source(); - newmap[kv.first] = newit;*/ newmap[kv.first] = PayloadDocumentEntry::from_unquoted_string_value(kv.second); } _internal_replace_all(newmap); @@ -909,7 +675,6 @@ IPAACA_EXPORT PayloadEntryProxyMapIterator::PayloadEntryProxyMapIterator(Payload IPAACA_EXPORT PayloadEntryProxyMapIterator& PayloadEntryProxyMapIterator::operator++() { - // prevent increase beyond end() ? raw_iterator++; return *this; } diff --git a/ipaacalib/cpp/src/ipaaca-string-utils.cc b/ipaacalib/cpp/src/ipaaca-string-utils.cc index d3192fc858aed0814dbde2494ddb822172e98095..2a3b1b5e4a9999ea1374705fa167dc61e2427515 100644 --- a/ipaacalib/cpp/src/ipaaca-string-utils.cc +++ b/ipaacalib/cpp/src/ipaaca-string-utils.cc @@ -3,8 +3,9 @@ * "Incremental Processing Architecture * for Artificial Conversational Agents". * - * Copyright (c) 2009-2013 Sociable Agents Group - * CITEC, Bielefeld University + * 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 diff --git a/ipaacalib/cpp/src/ipaaca.cc b/ipaacalib/cpp/src/ipaaca.cc index 2e7f99510dcb8afda09c5019da4e40c9bce9583a..b475ff6677a705663439c1dc7131c5c465920e86 100644 --- a/ipaacalib/cpp/src/ipaaca.cc +++ b/ipaacalib/cpp/src/ipaaca.cc @@ -76,17 +76,8 @@ 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); -/* -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_rsb_spread_host(""); +IPAACA_EXPORT std::string __ipaaca_static_option_rsb_spread_port(""); } // of namespace ipaaca diff --git a/ipaacalib/cpp/src/util/notifier.cc b/ipaacalib/cpp/src/util/notifier.cc index df063512946b1482193e870c203473059445a921..aaca812a4a086cc5b8805072d6fed0005daa4cdf 100644 --- a/ipaacalib/cpp/src/util/notifier.cc +++ b/ipaacalib/cpp/src/util/notifier.cc @@ -3,8 +3,9 @@ * "Incremental Processing Architecture * for Artificial Conversational Agents". * - * Copyright (c) 2009-2013 Sociable Agents Group - * CITEC, Bielefeld University + * 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 @@ -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,7 +115,7 @@ 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() { diff --git a/ipaacalib/cpp/test/CMakeLists.txt b/ipaacalib/cpp/test/CMakeLists.txt index 6a56b612432f325165ffeeb542e002aa06ae4130..6568c8e4fec4dcdd0d8218d611c3ca784a9638a9 100644 --- a/ipaacalib/cpp/test/CMakeLists.txt +++ b/ipaacalib/cpp/test/CMakeLists.txt @@ -12,7 +12,7 @@ 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}) @@ -20,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 ) @@ -75,3 +78,7 @@ install ( ARCHIVE DESTINATION lib ) + +enable_testing() +add_test(TestIpaacaCpp testipaaca) + diff --git a/ipaacalib/cpp/test/src/testipaaca.cc b/ipaacalib/cpp/test/src/testipaaca.cc index 828136ba81da19eaf49546b225f229788c5ed986..7769f741060a5e27f77ec74368eb7ae3339e4c72 100644 --- a/ipaacalib/cpp/test/src/testipaaca.cc +++ b/ipaacalib/cpp/test/src/testipaaca.cc @@ -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( ) diff --git a/ipaacalib/java/.gitignore b/ipaacalib/java/.gitignore index 8ba77fee38b2e33a59879bea9ace3fe9f7d1f93a..c84f99e34ea3116bd737e7c981c578e46d640a69 100644 --- a/ipaacalib/java/.gitignore +++ b/ipaacalib/java/.gitignore @@ -6,3 +6,4 @@ dist privateprops .project .classpath +/bin/ diff --git a/ipaacalib/java/src/ipaaca/AbstractIU.java b/ipaacalib/java/src/ipaaca/AbstractIU.java index d79f1622871ec4f960781e6630604e9fe3054510..ba075e527c1054395ed6f965f94f0adac5e5dcc3 100644 --- a/ipaacalib/java/src/ipaaca/AbstractIU.java +++ b/ipaacalib/java/src/ipaaca/AbstractIU.java @@ -57,6 +57,7 @@ public abstract class AbstractIU protected Payload payload; protected String category; protected boolean committed = false; + protected boolean retracted = false; private String uid; protected int revision; private boolean readOnly = false; @@ -201,6 +202,11 @@ public abstract class AbstractIU return committed; } + public boolean isRetracted() + { + return retracted; + } + public void setBuffer(Buffer buffer) { this.buffer = buffer; @@ -218,6 +224,8 @@ public abstract class AbstractIU public abstract void commit(); + public abstract void retract(); + // XXX: might not be valid for all types of IUs public abstract void commit(String writerName); diff --git a/ipaacalib/java/src/ipaaca/Buffer.java b/ipaacalib/java/src/ipaaca/Buffer.java index 02b6b36f7eb190ae64344a53e8a7ce663ca80bad..d8851d4254a917d7d3f464cfd5c12f26fc7df1da 100644 --- a/ipaacalib/java/src/ipaaca/Buffer.java +++ b/ipaacalib/java/src/ipaaca/Buffer.java @@ -38,6 +38,8 @@ import java.util.List; import java.util.Set; import java.util.UUID; +import ipaaca.Initializer; + /** * Base class for InputBuffer and OutputBuffer. */ @@ -85,6 +87,7 @@ public abstract class Buffer */ public Buffer(String owningComponentName) { + Initializer.initializeIpaacaRsb(); this.owningComponentName = owningComponentName; uniqueName = "undef-" + uuid; } diff --git a/ipaacalib/cpp/include/ipaaca/ipaaca-json.h b/ipaacalib/java/src/ipaaca/IURetractedException.java similarity index 53% rename from ipaacalib/cpp/include/ipaaca/ipaaca-json.h rename to ipaacalib/java/src/ipaaca/IURetractedException.java index 30cac6c0594617ea28efd941bee08840b07eac93..b7d4f76c2e4809c731130c7d54103dde2caf5677 100644 --- a/ipaacalib/cpp/include/ipaaca/ipaaca-json.h +++ b/ipaacalib/java/src/ipaaca/IURetractedException.java @@ -1,11 +1,10 @@ /* * This file is part of IPAACA, the * "Incremental Processing Architecture - * for Artificial Conversational Agents". + * for Artificial Conversational Agents". * * Copyright (c) 2009-2015 Social Cognitive Systems Group - * (formerly the Sociable Agents Group) - * CITEC, Bielefeld University + * CITEC, Bielefeld University * * http://opensource.cit-ec.de/projects/ipaaca/ * http://purl.org/net/ipaaca @@ -22,7 +21,7 @@ * 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. + * 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. @@ -31,31 +30,25 @@ * Excellence Initiative. */ +package ipaaca; + /** - * \file ipaaca-json.h - * - * \brief Header file for JSON tests. [superfluous] - * - * Users should not include this file directly, but use ipaaca.h - * - * \author Ramin Yaghoubzadeh (ryaghoubzadeh@uni-bielefeld.de) - * \date March, 2015 + * Error indicating that an IU is immutable because it has been retracted. + * */ - -#ifndef __ipaaca_json_H__ -#define __ipaaca_json_H__ - -#include "rapidjson/document.h" -#include "rapidjson/prettywriter.h" -#include "rapidjson/filestream.h" -#include <cstdio> - -// 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. - - - -#endif // __IPAACA_JSON_H__ - +public class IURetractedException extends RuntimeException +{ + private static final long serialVersionUID = 1L; + private final AbstractIU iu; + + public AbstractIU getIU() + { + return iu; + } + + public IURetractedException(AbstractIU iu) + { + super("Writing to IU " + iu.getUid() + " failed -- it has been retracted."); + this.iu = iu; + } +} diff --git a/ipaacalib/java/src/ipaaca/Initializer.java b/ipaacalib/java/src/ipaaca/Initializer.java index 0af784bd8e7051dd1889edb0465ef07add9de566..c2b8c72cb19e9966906008c2fd855691976c5abc 100644 --- a/ipaacalib/java/src/ipaaca/Initializer.java +++ b/ipaacalib/java/src/ipaaca/Initializer.java @@ -3,7 +3,7 @@ * "Incremental Processing Architecture * for Artificial Conversational Agents". * - * Copyright (c) 2009-2013 Sociable Agents Group + * Copyright (c) 2009-2015 Social Cognitive Systems Group * CITEC, Bielefeld University * * http://opensource.cit-ec.de/projects/ipaaca/ @@ -32,9 +32,12 @@ package ipaaca; +import java.nio.ByteBuffer; import ipaaca.protobuf.Ipaaca.IUCommission; import ipaaca.protobuf.Ipaaca.IUResendRequest; +import ipaaca.protobuf.Ipaaca.IURetraction; import rsb.converter.ConverterSignature; +import rsb.converter.ConverterRepository; import rsb.converter.DefaultConverterRepository; import rsb.converter.ProtocolBufferConverter; @@ -43,34 +46,74 @@ import rsb.converter.ProtocolBufferConverter; * @author hvanwelbergen * */ -public final class Initializer -{ - private Initializer() - { - } +public final class Initializer { + + private Initializer() {} + private static volatile boolean initialized = false; - public synchronized static void initializeIpaacaRsb() - { - if(initialized)return; - DefaultConverterRepository.getDefaultConverterRepository().addConverter(new IntConverter()); - DefaultConverterRepository.getDefaultConverterRepository().addConverter( - new ProtocolBufferConverter<IUCommission>(IUCommission.getDefaultInstance())); - // dlw - DefaultConverterRepository.getDefaultConverterRepository().addConverter( - new ProtocolBufferConverter<IUResendRequest>(IUResendRequest.getDefaultInstance())); - - DefaultConverterRepository.getDefaultConverterRepository().addConverter( - new IUConverter(new ConverterSignature("ipaaca-iu", RemotePushIU.class))); - DefaultConverterRepository.getDefaultConverterRepository().addConverter( - new IUConverter(new ConverterSignature("ipaaca-localiu", LocalIU.class))); - DefaultConverterRepository.getDefaultConverterRepository().addConverter( - new IUConverter(new ConverterSignature("ipaaca-messageiu", RemoteMessageIU.class))); - DefaultConverterRepository.getDefaultConverterRepository().addConverter( - new IUConverter(new ConverterSignature("ipaaca-localmessageiu", LocalMessageIU.class))); + public synchronized static void initializeIpaacaRsb() { + if (initialized) + return; + + ConverterRepository<ByteBuffer> dcr = + DefaultConverterRepository.getDefaultConverterRepository(); + + // for IU revision numbers + dcr.addConverter( + new IntConverter()); + + // IU commit messages + dcr.addConverter( + new ProtocolBufferConverter<IUCommission>( + IUCommission.getDefaultInstance())); + + // IU commit messages + dcr.addConverter( + new ProtocolBufferConverter<IURetraction>( + IURetraction.getDefaultInstance())); + + // IU resend request messages + dcr.addConverter( + new ProtocolBufferConverter<IUResendRequest>( + IUResendRequest.getDefaultInstance())); + + // IUs + dcr.addConverter( + new IUConverter( + new ConverterSignature( + "ipaaca-iu", + RemotePushIU.class))); + + // Local IUs + dcr.addConverter( + new IUConverter( + new ConverterSignature( + "ipaaca-localiu", + LocalIU.class))); + + // Messages + dcr.addConverter( + new IUConverter( + new ConverterSignature( + "ipaaca-messageiu", + RemoteMessageIU.class))); + + // LocalMessages + dcr.addConverter( + new IUConverter( + new ConverterSignature( + "ipaaca-localmessageiu", + LocalMessageIU.class))); - DefaultConverterRepository.getDefaultConverterRepository().addConverter(new PayloadConverter()); - DefaultConverterRepository.getDefaultConverterRepository().addConverter(new LinkUpdateConverter()); + // Payloads + dcr.addConverter( + new PayloadConverter()); + + // LinkUpdates + dcr.addConverter( + new LinkUpdateConverter()); + initialized = true; } } diff --git a/ipaacalib/java/src/ipaaca/InputBuffer.java b/ipaacalib/java/src/ipaaca/InputBuffer.java index ccaabc922935c84a6808678a10c0dad5c0608e05..2a2b17c976de13990e6e53cfe4b0668829090782 100644 --- a/ipaacalib/java/src/ipaaca/InputBuffer.java +++ b/ipaacalib/java/src/ipaaca/InputBuffer.java @@ -33,6 +33,7 @@ package ipaaca; import ipaaca.protobuf.Ipaaca.IUCommission; +import ipaaca.protobuf.Ipaaca.IURetraction; import ipaaca.protobuf.Ipaaca.IUResendRequest; import ipaaca.protobuf.Ipaaca.IULinkUpdate; import ipaaca.protobuf.Ipaaca.IUPayloadUpdate; @@ -441,6 +442,22 @@ public class InputBuffer extends Buffer iu.setRevision(iuc.getRevision()); callIuEventHandlers(iuc.getUid(), false, IUEventType.COMMITTED, iu.getCategory()); } + if (event.getData() instanceof IURetraction) + { + IURetraction iuc = (IURetraction) event.getData(); + logger.debug("handleIUEvents invoked with an IURetraction: {}", iuc); + logger.debug("{}", this.getUniqueName()); + + if (!iuStore.containsKey(iuc.getUid())) + { + logger.warn("Update message for IU which we did not fully receive before."); + } + RemotePushIU iu = this.iuStore.get(iuc.getUid()); + if (iu != null) { + iu.applyRetraction(); + callIuEventHandlers(iuc.getUid(), false, IUEventType.RETRACTED, iu.getCategory()); + } + } } } diff --git a/ipaacalib/java/src/ipaaca/LocalIU.java b/ipaacalib/java/src/ipaaca/LocalIU.java index 6e87a82484f882a25dddda7e314dfd76ebdb3060..eb4ee552a4efc512992b16b9a10f5d957a422fd4 100644 --- a/ipaacalib/java/src/ipaaca/LocalIU.java +++ b/ipaacalib/java/src/ipaaca/LocalIU.java @@ -105,6 +105,10 @@ public class LocalIU extends AbstractIU synchronized (revisionLock) { + if (isRetracted()) + { + throw new IURetractedException(this); + } if (committed) { throw new IUCommittedException(this); @@ -121,6 +125,22 @@ public class LocalIU extends AbstractIU } } + private void internalRetract() + { + + synchronized (revisionLock) + { + if (isRetracted()) + return; + increaseRevisionNumber(); + retracted = true; + if (outputBuffer != null) + { + outputBuffer.sendIURetraction(this); + } + } + } + private void increaseRevisionNumber() { revision++; @@ -148,6 +168,10 @@ public class LocalIU extends AbstractIU @Override void modifyLinks(boolean isDelta, SetMultimap<String, String> linksToAdd, SetMultimap<String, String> linksToRemove, String writerName) { + if (isRetracted()) + { + throw new IURetractedException(this); + } if (isCommitted()) { throw new IUCommittedException(this); @@ -226,6 +250,10 @@ public class LocalIU extends AbstractIU { throw new IUCommittedException(this); } + if (isRetracted()) + { + throw new IURetractedException(this); + } increaseRevisionNumber(); if (isPublished()) { @@ -249,6 +277,10 @@ public class LocalIU extends AbstractIU { throw new IUCommittedException(this); } + if (isRetracted()) + { + throw new IURetractedException(this); + } increaseRevisionNumber(); if (isPublished()) { @@ -270,15 +302,29 @@ public class LocalIU extends AbstractIU @Override public void commit() { + if (isRetracted()) + { + throw new IURetractedException(this); + } internalCommit(null); } @Override public void commit(String writerName) { + if (isRetracted()) + { + throw new IURetractedException(this); + } internalCommit(writerName); } + @Override + public void retract() + { + internalRetract(); + } + @Override void removeFromPayload(Object key, String writer) { @@ -288,6 +334,10 @@ public class LocalIU extends AbstractIU { throw new IUCommittedException(this); } + if (isRetracted()) + { + throw new IURetractedException(this); + } increaseRevisionNumber(); if (isPublished()) { diff --git a/ipaacalib/java/src/ipaaca/LocalMessageIU.java b/ipaacalib/java/src/ipaaca/LocalMessageIU.java index bf9c12862d8b8027b8facbb0586f46894d5c2699..1bd5ea34687ebd45d92078aec87cab2429bf65c8 100644 --- a/ipaacalib/java/src/ipaaca/LocalMessageIU.java +++ b/ipaacalib/java/src/ipaaca/LocalMessageIU.java @@ -3,7 +3,7 @@ * "Incremental Processing Architecture * for Artificial Conversational Agents". * - * Copyright (c) 2009-2013 Sociable Agents Group + * Copyright (c) 2009-2015 Social Cognitive Systems Group * CITEC, Bielefeld University * * http://opensource.cit-ec.de/projects/ipaaca/ diff --git a/ipaacalib/java/src/ipaaca/OutputBuffer.java b/ipaacalib/java/src/ipaaca/OutputBuffer.java index 818621b07d24b974f7928e3d30fa59126caa5fd7..77f11a070a46b61c3fece8cb90a13caafbd20a14 100644 --- a/ipaacalib/java/src/ipaaca/OutputBuffer.java +++ b/ipaacalib/java/src/ipaaca/OutputBuffer.java @@ -1,9 +1,10 @@ + /* * This file is part of IPAACA, the * "Incremental Processing Architecture * for Artificial Conversational Agents". * - * Copyright (c) 2009-2013 Sociable Agents Group + * Copyright (c) 2009-2015 Social Cognitive Systems Group * CITEC, Bielefeld University * * http://opensource.cit-ec.de/projects/ipaaca/ @@ -34,6 +35,7 @@ package ipaaca; import ipaaca.protobuf.Ipaaca; import ipaaca.protobuf.Ipaaca.IUCommission; +import ipaaca.protobuf.Ipaaca.IURetraction; import ipaaca.protobuf.Ipaaca.IUResendRequest; import ipaaca.protobuf.Ipaaca.IULinkUpdate; import ipaaca.protobuf.Ipaaca.IUPayloadUpdate; @@ -474,7 +476,21 @@ public class OutputBuffer extends Buffer protected void sendIUCommission(AbstractIU iu, String writerName) { IUCommission iuc = Ipaaca.IUCommission.newBuilder().setUid(iu.getUid()).setRevision(iu.getRevision()) - .setWriterName(iu.getOwnerName() != null ? iu.getOwnerName() : writerName).build(); + .setWriterName(writerName == null ? iu.getOwnerName() : writerName).build(); + Informer<Object> informer = getInformer(iu.getCategory()); + try + { + informer.send(iuc); + } + catch (RSBException e) + { + throw new RuntimeException(e); + } + } + + protected void sendIURetraction(AbstractIU iu) + { + IURetraction iuc = Ipaaca.IURetraction.newBuilder().setUid(iu.getUid()).setRevision(iu.getRevision()).build(); Informer<Object> informer = getInformer(iu.getCategory()); try { diff --git a/ipaacalib/java/src/ipaaca/RemoteMessageIU.java b/ipaacalib/java/src/ipaaca/RemoteMessageIU.java index db69496e6709d9c453c34e2a94cf275f3bd4bedb..a3898a170138a0618d97ed97f2d51d7a3458af6c 100644 --- a/ipaacalib/java/src/ipaaca/RemoteMessageIU.java +++ b/ipaacalib/java/src/ipaaca/RemoteMessageIU.java @@ -3,7 +3,7 @@ * "Incremental Processing Architecture * for Artificial Conversational Agents". * - * Copyright (c) 2009-2013 Sociable Agents Group + * Copyright (c) 2009-2015 Social Cognitive Systems Group * CITEC, Bielefeld University * * http://opensource.cit-ec.de/projects/ipaaca/ @@ -58,6 +58,12 @@ public class RemoteMessageIU extends AbstractIU committed = true; } + @Override + public void retract() + { + log.info("Retracting a RemoteMessage has no effect."); + } + @Override public void commit(String writerName) { diff --git a/ipaacalib/java/src/ipaaca/RemotePushIU.java b/ipaacalib/java/src/ipaaca/RemotePushIU.java index bfb8060403c42031dfbf70c7b8c55eadaf72b334..f58e83c39b820be89909f9a6b0213171602d6d9f 100644 --- a/ipaacalib/java/src/ipaaca/RemotePushIU.java +++ b/ipaacalib/java/src/ipaaca/RemotePushIU.java @@ -84,9 +84,9 @@ public class RemotePushIU extends AbstractIU } @Override - public void commit() + public void retract() { - commit(null); + logger.info("Retracting a RemoteIU has no effect."); } void putIntoPayload(String key, String value, String writer) @@ -95,6 +95,10 @@ public class RemotePushIU extends AbstractIU { throw new IUCommittedException(this); } + if (isRetracted()) + { + throw new IURetractedException(this); + } if (isReadOnly()) { throw new IUReadOnlyException(this); @@ -136,6 +140,10 @@ public class RemotePushIU extends AbstractIU { throw new IUCommittedException(this); } + if (isRetracted()) + { + throw new IURetractedException(this); + } if (isReadOnly()) { throw new IUReadOnlyException(this); @@ -179,9 +187,19 @@ public class RemotePushIU extends AbstractIU setRevision(newRevision); } + @Override + public void commit() + { + commit(null); + } + @Override public void commit(String writerName) { + if (isRetracted()) + { + throw new IURetractedException(this); + } if (isReadOnly()) { throw new IUReadOnlyException(this); @@ -254,6 +272,10 @@ public class RemotePushIU extends AbstractIU { throw new IUCommittedException(this); } + if (isRetracted()) + { + throw new IURetractedException(this); + } if (isReadOnly()) { throw new IUReadOnlyException(this); @@ -357,6 +379,11 @@ public class RemotePushIU extends AbstractIU committed = true; } + public void applyRetraction() + { + retracted = true; + } + @Override void removeFromPayload(Object key, String writer) { @@ -364,6 +391,10 @@ public class RemotePushIU extends AbstractIU { throw new IUCommittedException(this); } + if (isRetracted()) + { + throw new IURetractedException(this); + } if (isReadOnly()) { throw new IUReadOnlyException(this); @@ -403,6 +434,10 @@ public class RemotePushIU extends AbstractIU { throw new IUCommittedException(this); } + if (isRetracted()) + { + throw new IURetractedException(this); + } if (isReadOnly()) { throw new IUReadOnlyException(this); diff --git a/ipaacalib/java/src/ipaaca/util/BlackboardClient.java b/ipaacalib/java/src/ipaaca/util/BlackboardClient.java index 6f70e78f922a289a29e2214b3861a0466755a063..ab72262ee99432ee255e6f66d9c341705d03eb3f 100644 --- a/ipaacalib/java/src/ipaaca/util/BlackboardClient.java +++ b/ipaacalib/java/src/ipaaca/util/BlackboardClient.java @@ -1,13 +1,5 @@ package ipaaca.util; -import ipaaca.AbstractIU; -import ipaaca.HandlerFunctor; -import ipaaca.IUEventType; -import ipaaca.InputBuffer; -import ipaaca.LocalMessageIU; -import ipaaca.OutputBuffer; -import ipaaca.protobuf.Ipaaca.IU; - import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -18,6 +10,13 @@ import java.util.Set; import com.google.common.collect.ImmutableSet; +import ipaaca.AbstractIU; +import ipaaca.HandlerFunctor; +import ipaaca.IUEventType; +import ipaaca.InputBuffer; +import ipaaca.LocalMessageIU; +import ipaaca.OutputBuffer; + /** * Client to get/set key value pairs on a Blackboard * @author hvanwelbergen diff --git a/ipaacalib/java/src/ipaaca/util/IpaacaLogger.java b/ipaacalib/java/src/ipaaca/util/IpaacaLogger.java new file mode 100644 index 0000000000000000000000000000000000000000..d55a46b2471e2a2fa3bc2bd9ef1ae2689a09d06f --- /dev/null +++ b/ipaacalib/java/src/ipaaca/util/IpaacaLogger.java @@ -0,0 +1,186 @@ +/* + * This file is part of IPAACA, the + * "Incremental Processing Architecture + * for Artificial Conversational Agents". + * + * Copyright (c) 2009-2016 Social Cognitive Systems 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. + */ + +package ipaaca.util; + +import ipaaca.LocalMessageIU; +import ipaaca.OutputBuffer; + +import java.util.HashMap; +import java.util.UUID; + +import org.apache.commons.lang.StringUtils; + +public class IpaacaLogger { + + private static OutputBuffer ob; + private static final Object lock = new Object(); + + private static boolean SEND_IPAACA_LOGS = true; + private static String MODULE_NAME = "???"; + + private static void initializeOutBuffer() { + synchronized (lock) { + if (ob == null) { + ob = new OutputBuffer("LogSender"); + } + } + } + + public static void setModuleName(String name) { + synchronized (lock) { + MODULE_NAME = name; + } + } + + public static void setLogFileName(String fileName, String logMode) { + initializeOutBuffer(); + LocalMessageIU msg = new LocalMessageIU("log"); + HashMap<String, String> pl = new HashMap<String, String>(); + pl.put("cmd", "open_log_file"); + pl.put("filename", fileName); + if (logMode != null) { + if (logMode.equals("append") || + logMode.equals("overwrite") || + logMode.equals("timestamp")) { + pl.put("existing", logMode); + } else { + + return; + } + } + ob.add(msg); + } + + public static void sendIpaacaLogs(boolean flag) { + synchronized (lock) { + SEND_IPAACA_LOGS = flag; + } + } + + private static void logConsole(String level, String text, float now, String function, String thread) { + for(String line: text.split("\n")) { + System.out.println("[" + level + "] " + thread + " " + function + " " + line); + function = StringUtils.leftPad("", function.length(), ' '); + thread = StringUtils.leftPad("", thread.length(), ' '); + } + } + + private static void logIpaaca(String level, String text, float now, String function, String thread) { + initializeOutBuffer(); + LocalMessageIU msg = new LocalMessageIU("log"); + HashMap<String, String> pl = new HashMap<String, String>(); + pl.put("module", MODULE_NAME); + pl.put("function", function); + pl.put("level", level); + pl.put("time", String.format("%.3f", now)); + pl.put("thread", thread); + pl.put("uuid", UUID.randomUUID().toString()); + pl.put("text", text); + msg.setPayload(pl); + ob.add(msg); + } + + private static String getCallerName() { + String function = Thread.currentThread().getStackTrace()[3].getClassName(); + function += "." + Thread.currentThread().getStackTrace()[3].getMethodName(); + return function; + } + + public static void logError(String msg) { + logError(msg, System.currentTimeMillis(), getCallerName()); + } + + public static void logError(String msg, float now) { + logError(msg, now, getCallerName()); + } + + private static void logError(String msg, float now, String callerName) { + String thread = Thread.currentThread().getName(); + if (SEND_IPAACA_LOGS) { + logIpaaca("ERROR", msg, now, callerName, thread); + } + logConsole("ERROR", msg, now, callerName, thread); + } + + + public static void logWarn(String msg) { + logWarn(msg, System.currentTimeMillis(), getCallerName()); + } + + public static void logWarn(String msg, float now) { + logWarn(msg, now, getCallerName()); + } + + private static void logWarn(String msg, float now, String callerName) { + String thread = Thread.currentThread().getName(); + if (SEND_IPAACA_LOGS) { + logIpaaca("WARN", msg, now, callerName, thread); + } + logConsole("WARN", msg, now, callerName, thread); + } + + + public static void logInfo(String msg) { + logInfo(msg, System.currentTimeMillis(), getCallerName()); + } + + public static void logInfo(String msg, float now) { + logInfo(msg, now, getCallerName()); + } + + private static void logInfo(String msg, float now, String callerName) { + String thread = Thread.currentThread().getName(); + if (SEND_IPAACA_LOGS) { + logIpaaca("INFO", msg, now, callerName, thread); + } + logConsole("INFO", msg, now, callerName, thread); + } + + + public static void logDebug(String msg) { + logDebug(msg, System.currentTimeMillis(), getCallerName()); + } + + public static void logDebug(String msg, float now) { + logDebug(msg, now, getCallerName()); + } + + private static void logDebug(String msg, float now, String callerName) { + String thread = Thread.currentThread().getName(); + if (SEND_IPAACA_LOGS) { + logIpaaca("DEBUG", msg, now, callerName, thread); + } + logConsole("DEBUG", msg, now, callerName, thread); + } + +} diff --git a/ipaacalib/java/src/ipaaca/util/communication/FutureIU.java b/ipaacalib/java/src/ipaaca/util/communication/FutureIU.java new file mode 100644 index 0000000000000000000000000000000000000000..1cd48549a65e6f968ec9b94907743ea59cb546e7 --- /dev/null +++ b/ipaacalib/java/src/ipaaca/util/communication/FutureIU.java @@ -0,0 +1,84 @@ +package ipaaca.util.communication; + +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.TimeUnit; + +import com.google.common.collect.ImmutableSet; + +import ipaaca.AbstractIU; +import ipaaca.HandlerFunctor; +import ipaaca.IUEventType; +import ipaaca.InputBuffer; + +/** + * Obtain a IU in the future. Usage:<br> + * FutureIU fu = FutureIU("componentx", "status", "started"); //wait for componentx to send a message that is it fully started<br> + * [Start componentx, assumes that component x will send a message or other iu with status=started in the payload]<br> + * AbstractIU iu = fu.take(); //get the actual IU + * @author hvanwelbergen + */ +public class FutureIU +{ + private final InputBuffer inBuffer; + private final BlockingQueue<AbstractIU> queue = new ArrayBlockingQueue<AbstractIU>(1); + + public FutureIU(String category, String idKey, String idVal) + { + inBuffer = new InputBuffer("FutureIU", ImmutableSet.of(category)); + inBuffer.registerHandler(new HandlerFunctor() + { + @Override + public void handle(AbstractIU iu, IUEventType type, boolean local) + { + String id = iu.getPayload().get(idKey); + if (idVal.equals(id)) + { + queue.offer(iu); + } + } + }, ImmutableSet.of(category)); + } + + /** + * Waits (if necessary) for the IU and take it (can be done only once) + */ + public AbstractIU take() throws InterruptedException + { + AbstractIU iu; + try + { + iu = queue.take(); + } + finally + { + inBuffer.close(); + } + return iu; + } + + /** + * Wait for at most the given time for the IU and take it (can be done only once), return null on timeout + */ + public AbstractIU take(long timeout, TimeUnit unit) throws InterruptedException + { + AbstractIU iu; + try + { + iu = queue.poll(timeout, unit); + } + finally + { + inBuffer.close(); + } + return iu; + } + + /** + * Closes the FutureIU, use only if get is not used. + */ + public void close() + { + inBuffer.close(); + } +} diff --git a/ipaacalib/java/src/ipaaca/util/communication/FutureIUs.java b/ipaacalib/java/src/ipaaca/util/communication/FutureIUs.java new file mode 100644 index 0000000000000000000000000000000000000000..2e9ed3b2d482132b93d3b04027b8ed2fcf8576c4 --- /dev/null +++ b/ipaacalib/java/src/ipaaca/util/communication/FutureIUs.java @@ -0,0 +1,70 @@ +package ipaaca.util.communication; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.TimeUnit; + +import com.google.common.collect.ImmutableSet; + +import ipaaca.AbstractIU; +import ipaaca.HandlerFunctor; +import ipaaca.IUEventType; +import ipaaca.InputBuffer; + +/** + * Obtain multiple future ius on an specific category. Usage:<br> + * FutureIUs futures = new FutureIUs(componentx, key);<br> + * [make componentx send a IU with key=keyvaluedesired1]<br> + * AbstractIU iu = futures.take(keyvaluedesired1);<br> + * [make componentx send a IU with key=keyvaluedesired2] + * AbstractIU iu = futures.take(keyvaluedesired2);<br> + * ...<br> + * futures.close(); + * @author hvanwelbergen + */ +public class FutureIUs +{ + private final InputBuffer inBuffer; + private final Map<String,BlockingQueue<AbstractIU>> resultsMap = Collections.synchronizedMap(new HashMap<>()); + + public FutureIUs(String category, String idKey) + { + inBuffer = new InputBuffer("FutureIUs", ImmutableSet.of(category)); + inBuffer.registerHandler(new HandlerFunctor() + { + @Override + public void handle(AbstractIU iu, IUEventType type, boolean local) + { + String id = iu.getPayload().get(idKey); + resultsMap.putIfAbsent(id, new ArrayBlockingQueue<AbstractIU>(1)); + resultsMap.get(id).offer(iu); + } + }, ImmutableSet.of(category)); + } + + /** + * Waits (if necessary) for the IU and take it (can be done only once) + */ + public AbstractIU take(String idValue) throws InterruptedException + { + resultsMap.putIfAbsent(idValue, new ArrayBlockingQueue<AbstractIU>(1)); + return resultsMap.get(idValue).take(); + } + + /** + * Wait for at most the given time for the IU and take it (can be done only once), return null on timeout + */ + public AbstractIU take(String idValue, long timeout, TimeUnit unit) throws InterruptedException + { + resultsMap.putIfAbsent(idValue, new ArrayBlockingQueue<AbstractIU>(1)); + return resultsMap.get(idValue).poll(timeout, unit); + } + + public void close() + { + inBuffer.close(); + } +} diff --git a/ipaacalib/java/test/src/ipaaca/util/communication/FutureIUTest.java b/ipaacalib/java/test/src/ipaaca/util/communication/FutureIUTest.java new file mode 100644 index 0000000000000000000000000000000000000000..bacf3013ca7cbcd7008895992d3cda71cf2fc921 --- /dev/null +++ b/ipaacalib/java/test/src/ipaaca/util/communication/FutureIUTest.java @@ -0,0 +1,61 @@ +package ipaaca.util.communication; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import java.util.concurrent.TimeUnit; + +import org.junit.Test; + +import ipaaca.LocalMessageIU; +import ipaaca.OutputBuffer; + +/** + * Unit tests for the FutureIU + * @author hvanwelbergen + * + */ +public class FutureIUTest +{ + private final OutputBuffer outBuffer = new OutputBuffer("component1"); + + @Test(timeout = 2000) + public void testSendBeforeTake() throws InterruptedException + { + FutureIU fu = new FutureIU("cat1", "status", "started"); + LocalMessageIU message = new LocalMessageIU("cat1"); + message.getPayload().put("status", "started"); + outBuffer.add(message); + assertEquals(message.getPayload(), fu.take().getPayload()); + } + + @Test(timeout = 2000) + public void testSendAfterTake() throws InterruptedException + { + FutureIU fu = new FutureIU("cat1", "status", "started"); + LocalMessageIU message = new LocalMessageIU("cat1"); + message.getPayload().put("status", "started"); + Runnable send = () -> { + try + { + Thread.sleep(1000); + } + catch (Exception e) + { + throw new RuntimeException(e); + } + outBuffer.add(message); + }; + new Thread(send).start(); + assertEquals(message.getPayload(), fu.take().getPayload()); + } + + @Test + public void testInvalidKeyValue() throws InterruptedException + { + FutureIU fu = new FutureIU("cat1", "status", "started"); + LocalMessageIU message = new LocalMessageIU("cat1"); + message.getPayload().put("status", "cancelled"); + assertNull(fu.take(1,TimeUnit.SECONDS)); + } +} diff --git a/ipaacalib/java/test/src/ipaaca/util/communication/FutureIUsTest.java b/ipaacalib/java/test/src/ipaaca/util/communication/FutureIUsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..87113d047304933708966471df1ba9da93c18a69 --- /dev/null +++ b/ipaacalib/java/test/src/ipaaca/util/communication/FutureIUsTest.java @@ -0,0 +1,81 @@ +package ipaaca.util.communication; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import java.util.concurrent.TimeUnit; + +import org.junit.After; +import org.junit.Test; + +import ipaaca.LocalMessageIU; +import ipaaca.OutputBuffer; + +/** + * Unit tests for FutureIUs + * @author hvanwelbergen + * + */ +public class FutureIUsTest +{ + private FutureIUs fus = new FutureIUs("cat1","id"); + private final OutputBuffer outBuffer = new OutputBuffer("component1"); + + @After + public void cleanup() + { + fus.close(); + } + + @Test(timeout = 2000) + public void testSendBeforeTake() throws InterruptedException + { + LocalMessageIU message = new LocalMessageIU("cat1"); + message.getPayload().put("id", "id1"); + outBuffer.add(message); + assertEquals(message.getPayload(), fus.take("id1").getPayload()); + } + + @Test(timeout = 2000) + public void testSendAfterTake() throws InterruptedException + { + LocalMessageIU message = new LocalMessageIU("cat1"); + message.getPayload().put("id", "id1"); + Runnable send = () -> { + try + { + Thread.sleep(1000); + } + catch (Exception e) + { + throw new RuntimeException(e); + } + outBuffer.add(message); + }; + new Thread(send).start(); + assertEquals(message.getPayload(), fus.take("id1").getPayload()); + } + + @Test + public void testNonMatchingKeyValue() throws InterruptedException + { + LocalMessageIU message = new LocalMessageIU("cat1"); + message.getPayload().put("id", "id2"); + outBuffer.add(message); + assertNull(fus.take("id1", 1,TimeUnit.SECONDS)); + } + + @Test + public void testMultipleKeyValues() throws InterruptedException + { + LocalMessageIU message1 = new LocalMessageIU("cat1"); + message1.getPayload().put("id", "id1"); + LocalMessageIU message2 = new LocalMessageIU("cat1"); + message2.getPayload().put("id", "id2"); + outBuffer.add(message2); + outBuffer.add(message1); + + assertEquals(message1.getPayload(), fus.take("id1").getPayload()); + assertEquals(message2.getPayload(), fus.take("id2").getPayload()); + } +} diff --git a/ipaacalib/python/src/ipaaca/__init__.py b/ipaacalib/python/src/ipaaca/__init__.py index 09321c0bd26070239ee9a44f354e62d5f40eeaff..9314caf9604777bf727e86235693b3c0670275f1 100755 --- a/ipaacalib/python/src/ipaaca/__init__.py +++ b/ipaacalib/python/src/ipaaca/__init__.py @@ -4,7 +4,7 @@ # "Incremental Processing Architecture # for Artificial Conversational Agents". # -# Copyright (c) 2009-2014 Social Cognitive Systems Group +# Copyright (c) 2009-2016 Social Cognitive Systems Group # CITEC, Bielefeld University # # http://opensource.cit-ec.de/projects/ipaaca/ @@ -32,6 +32,9 @@ from __future__ import division, print_function +import os +import threading + import rsb import rsb.converter @@ -44,46 +47,69 @@ from ipaaca.misc import enable_logging, IpaacaArgumentParser from ipaaca.payload import Payload -def initialize_ipaaca_rsb(): - ''''Register own RSB Converters and initialise RSB from default config file.''' - rsb.converter.registerGlobalConverter( - ipaaca.converter.IntConverter( - wireSchema="int32", - dataType=int)) - - rsb.converter.registerGlobalConverter( - ipaaca.converter.IUConverter( - wireSchema="ipaaca-iu", - dataType=IU)) - - rsb.converter.registerGlobalConverter( - ipaaca.converter.MessageConverter( - wireSchema="ipaaca-messageiu", - dataType=Message)) +__RSB_INITIALIZER_LOCK = threading.Lock() +__RSB_INITIALIZED = False - rsb.converter.registerGlobalConverter( - ipaaca.converter.IULinkUpdateConverter( - wireSchema="ipaaca-iu-link-update", - dataType=converter.IULinkUpdate)) - rsb.converter.registerGlobalConverter( - ipaaca.converter.IUPayloadUpdateConverter( - wireSchema="ipaaca-iu-payload-update", - dataType=converter.IUPayloadUpdate)) +def initialize_ipaaca_rsb_if_needed(): + """Initialise rsb if not yet initialise. - rsb.converter.registerGlobalConverter( - rsb.converter.ProtocolBufferConverter( - messageClass=ipaaca_pb2.IUCommission)) + * Register own RSB onverters. + * Initialise RSB from enviroment variables, rsb config file, or + from default values for RSB spread host and port (via + ipaaca.defaults or ipaaca.misc.IpaacaArgumentParser). + """ + global __RSB_INITIALIZED + with __RSB_INITIALIZER_LOCK: + if __RSB_INITIALIZED: + return + else: + rsb.converter.registerGlobalConverter( + ipaaca.converter.IntConverter( + wireSchema="int32", + dataType=int)) + + rsb.converter.registerGlobalConverter( + ipaaca.converter.IUConverter( + wireSchema="ipaaca-iu", + dataType=IU)) + + rsb.converter.registerGlobalConverter( + ipaaca.converter.MessageConverter( + wireSchema="ipaaca-messageiu", + dataType=Message)) + + rsb.converter.registerGlobalConverter( + ipaaca.converter.IULinkUpdateConverter( + wireSchema="ipaaca-iu-link-update", + dataType=converter.IULinkUpdate)) + + rsb.converter.registerGlobalConverter( + ipaaca.converter.IUPayloadUpdateConverter( + wireSchema="ipaaca-iu-payload-update", + dataType=converter.IUPayloadUpdate)) + + rsb.converter.registerGlobalConverter( + rsb.converter.ProtocolBufferConverter( + messageClass=ipaaca_pb2.IUCommission)) + + rsb.converter.registerGlobalConverter( + rsb.converter.ProtocolBufferConverter( + messageClass=ipaaca_pb2.IUResendRequest)) + + rsb.converter.registerGlobalConverter( + rsb.converter.ProtocolBufferConverter( + messageClass=ipaaca_pb2.IURetraction)) - rsb.converter.registerGlobalConverter( - rsb.converter.ProtocolBufferConverter( - messageClass=ipaaca_pb2.IUResendRequest)) + if ipaaca.defaults.IPAACA_DEFAULT_RSB_SPREAD_HOST is not None: + os.environ['RSB_TRANSPORT_SPREAD_HOST'] = str( + ipaaca.defaults.IPAACA_DEFAULT_RSB_SPREAD_HOST) - rsb.converter.registerGlobalConverter( - rsb.converter.ProtocolBufferConverter( - messageClass=ipaaca_pb2.IURetraction)) + if ipaaca.defaults.IPAACA_DEFAULT_RSB_SPREAD_PORT is not None: + os.environ['RSB_TRANSPORT_SPREAD_PORT'] = str( + ipaaca.defaults.IPAACA_DEFAULT_RSB_SPREAD_PORT) - rsb.__defaultParticipantConfig = rsb.ParticipantConfig.fromDefaultSources() + rsb.__defaultParticipantConfig = \ + rsb.ParticipantConfig.fromDefaultSources() -# Initialise module -initialize_ipaaca_rsb() + __RSB_INITIALIZED = True diff --git a/ipaacalib/python/src/ipaaca/buffer.py b/ipaacalib/python/src/ipaaca/buffer.py index c4b75a4450cbd1301717caf94fa36dfb46e8b2f1..6a408341f7991acf8bc19749def7a92648b39ef2 100644 --- a/ipaacalib/python/src/ipaaca/buffer.py +++ b/ipaacalib/python/src/ipaaca/buffer.py @@ -4,7 +4,7 @@ # "Incremental Processing Architecture # for Artificial Conversational Agents". # -# Copyright (c) 2009-2014 Social Cognitive Systems Group +# Copyright (c) 2009-2015 Social Cognitive Systems Group # CITEC, Bielefeld University # # http://opensource.cit-ec.de/projects/ipaaca/ @@ -37,6 +37,9 @@ import threading import uuid import traceback +import weakref +import atexit + import rsb import ipaaca_pb2 @@ -54,6 +57,27 @@ __all__ = [ LOGGER = ipaaca.misc.get_library_logger() +# set of objects to auto-clean on exit, assumes _teardown() method +TEARDOWN_OBJECTS = set() + +def atexit_cleanup_function(): + '''Function to call at program exit to auto-clean objects.''' + global TEARDOWN_OBJECTS + for obj_r in TEARDOWN_OBJECTS: + obj = obj_r() + if obj is not None: # if weakref still valid + obj._teardown() +atexit.register(atexit_cleanup_function) + +def auto_teardown_instances(fn): + '''Decorator function for object constructors, to add + new instances to the object set to auto-clean at exit.''' + def auto_teardown_instances_wrapper(instance, *args, **kwargs): + global TEARDOWN_OBJECTS + fn(instance, *args, **kwargs) + TEARDOWN_OBJECTS.add(weakref.ref(instance)) + return auto_teardown_instances_wrapper + class IUStore(dict): """A dictionary storing IUs.""" def __init__(self): @@ -133,6 +157,7 @@ class Buffer(object): participant_config -- RSB configuration ''' super(Buffer, self).__init__() + ipaaca.initialize_ipaaca_rsb_if_needed() self._owning_component_name = owning_component_name self._channel = channel if channel is not None else ipaaca.defaults.IPAACA_DEFAULT_CHANNEL self._participant_config = rsb.ParticipantConfig.fromDefaultSources() if participant_config is None else participant_config @@ -207,21 +232,33 @@ class InputBuffer(Buffer): self._add_category_listener(str(self._uuid)) if category_interests is not None: self.add_category_interests(category_interests) - - def _get_remote_server(self, iu): + + def _get_remote_server(self, event_or_iu): '''Return (or create, store and return) a remote server.''' - _owner = None - if hasattr(iu,'owner_name'): - _owner = iu.owner_name - elif hasattr(iu,'writer_name'): - _owner = iu.writer_name - if _owner is not None: - if _owner in self._remote_server_store: + _owner = self._get_owner(event_or_iu) + if _owner: + try: return self._remote_server_store[_owner] - # TODO remove the str() when unicode is supported (issue #490) - remote_server = rsb.createRemoteServer(rsb.Scope(str(_owner))) - self._remote_server_store[_owner] = remote_server - return remote_server + except KeyError: + remote_server = rsb.createRemoteServer(rsb.Scope(str(_owner))) + self._remote_server_store[_owner] = remote_server + return remote_server + else: + None + + def _get_owner(self, event_or_iu): + if hasattr(event_or_iu, 'data'): + # is RSB event + data = event_or_iu.data + if hasattr(data, 'owner_name'): + return data.owner_name + elif hasattr(data, 'writer_name'): + return data.writer_name + else: + return None + else: + # is IU + return event_or_iu.owner_name def _add_category_listener(self, iu_category): '''Create and store a listener on a specific category.''' @@ -270,9 +307,14 @@ class InputBuffer(Buffer): del self._iu_store[ event.data.uid ] else: if event.data.uid not in self._iu_store: - if self._resend_active: - # send resend request to remote server - self._request_remote_resend(event.data) + if (self._resend_active and + not type_ is ipaaca_pb2.IURetraction): + # send resend request to remote server, IURetraction is ignored + try: + self._request_remote_resend(event) + except ipaaca.exception.IUResendRequestFailedError: + LOGGER.warning('Requesting resend for IU {} failed.'. + format(event.data.uid)) else: LOGGER.warning("Received an update for an IU which we did not receive before.") return @@ -283,10 +325,6 @@ class InputBuffer(Buffer): iu._revision = event.data.revision iu._apply_retraction() # for now - just sets the _rectracted flag. self.call_iu_event_handlers(event.data.uid, local=False, event_type=ipaaca.iu.IUEventType.RETRACTED, category=iu.category) - # SPECIAL CASE: allow the handlers (which will need to find the IU - # in the buffer) to operate on the IU - then delete it afterwards! - # FIXME: for now: retracted == deleted! Think about this later - del(self._iu_store[iu.uid]) else: if event.data.writer_name == self.unique_name: # Notify only for remotely triggered events; @@ -325,13 +363,17 @@ class InputBuffer(Buffer): else: self._remove_category_listener(category_interests) - def _request_remote_resend(self, iu): - remote_server = self._get_remote_server(iu) - resend_request = ipaaca_pb2.IUResendRequest() - resend_request.uid = iu.uid # target iu - resend_request.hidden_scope_name = str(self._uuid) # hidden category name - remote_revision = remote_server.requestResend(resend_request) - if remote_revision == 0: + def _request_remote_resend(self, event): + remote_server = self._get_remote_server(event) + if remote_server: + resend_request = ipaaca_pb2.IUResendRequest() + resend_request.uid = event.data.uid # target iu + resend_request.hidden_scope_name = str(self._uuid) # hidden category name + remote_revision = remote_server.requestResend(resend_request) + if remote_revision == 0: + raise ipaaca.exception.IUResendRequestFailedError() + else: + # Remote server is not known raise ipaaca.exception.IUResendRequestFailedError() def register_handler(self, handler_function, for_event_types=None, for_categories=None): @@ -364,8 +406,9 @@ class OutputBuffer(Buffer): """An OutputBuffer that holds local IUs.""" + @auto_teardown_instances def __init__(self, owning_component_name, channel=None, participant_config=None): - '''Create an Output Buffer. + '''Create an OutputBuffer. Keyword arguments: owning_component_name -- name of the entity that own this buffer @@ -382,6 +425,16 @@ class OutputBuffer(Buffer): self._id_prefix = str(owning_component_name)+'-'+str(self._uuid)+'-IU-' self.__iu_id_counter_lock = threading.Lock() + def _teardown(self): + '''OutputBuffer retracts remaining live IUs on teardown''' + self._retract_all_internal() + def __del__(self): + '''Perform teardown (IU retractions) as soon as Buffer is lost. + Note that at program exit the teardown might be called + twice for live objects (atexit, then del), but the + _retract_all_internal method prevents double retractions.''' + self._retract_all_internal() + def _remote_update_links(self, update): '''Apply a remotely requested update to one of the stored IU's links.''' if update.uid not in self._iu_store: @@ -479,6 +532,8 @@ class OutputBuffer(Buffer): raise ipaaca.exception.IUPublishedError(iu) if iu.buffer is not None: raise ipaaca.exception.IUPublishedError(iu) + if iu.retracted: + raise ipaaca.exception.IURetractedError(iu) if iu.access_mode != ipaaca.iu.IUAccessMode.MESSAGE: # Messages are not really stored in the OutputBuffer self._iu_store[iu.uid] = iu @@ -486,12 +541,12 @@ class OutputBuffer(Buffer): self._publish_iu(iu) def remove(self, iu=None, iu_uid=None): - '''Remove the iu or an IU corresponding to iu_uid from the OutputBuffer, retracting it from the system.''' + '''Retracts an IU and removes it from the OutputBuffer.''' if iu is None: if iu_uid is None: return None else: - if iu_uid not in self. _iu_store: + if iu_uid not in self._iu_store: raise ipaaca.exception.IUNotFoundError(iu_uid) iu = self._iu_store[iu_uid] # unpublish the IU @@ -505,12 +560,19 @@ class OutputBuffer(Buffer): informer.publishData(iu) def _retract_iu(self, iu): - '''Retract (unpublish) an IU.''' + '''Retract an IU.''' + iu._retracted = True iu_retraction = ipaaca_pb2.IURetraction() iu_retraction.uid = iu.uid iu_retraction.revision = iu.revision informer = self._get_informer(iu._category) informer.publishData(iu_retraction) + + def _retract_all_internal(self): + '''Retract all IUs without removal (for Buffer teardown).''' + for iu in self._iu_store.values(): + if not iu._retracted: + self._retract_iu(iu) def _send_iu_commission(self, iu, writer_name): '''Send IU commission. diff --git a/ipaacalib/python/src/ipaaca/defaults.py b/ipaacalib/python/src/ipaaca/defaults.py index 706c714b1d270838f04a84f3cd20dffe432d747c..bf3d0f00d282a90f0c908ecf92f17f7447020b45 100644 --- a/ipaacalib/python/src/ipaaca/defaults.py +++ b/ipaacalib/python/src/ipaaca/defaults.py @@ -4,7 +4,7 @@ # "Incremental Processing Architecture # for Artificial Conversational Agents". # -# Copyright (c) 2009-2014 Social Cognitive Systems Group +# Copyright (c) 2009-2016 Social Cognitive Systems Group # CITEC, Bielefeld University # # http://opensource.cit-ec.de/projects/ipaaca/ @@ -33,6 +33,11 @@ IPAACA_DEFAULT_CHANNEL = 'default' IPAACA_LOGGER_NAME = 'ipaaca' + IPAACA_DEFAULT_LOGGING_LEVEL = 'WARNING' IPAACA_DEFAULT_IU_PAYLOAD_TYPE = 'JSON' # one of ipaaca.iu.IUPayloadType + +IPAACA_DEFAULT_RSB_SPREAD_HOST = None + +IPAACA_DEFAULT_RSB_SPREAD_PORT = None diff --git a/ipaacalib/python/src/ipaaca/exception.py b/ipaacalib/python/src/ipaaca/exception.py index f90a6756ef4f2935004e2b60fd76e14c612f60f4..f3a927d73cc31b44ee2b4880e1778f59616e7e55 100644 --- a/ipaacalib/python/src/ipaaca/exception.py +++ b/ipaacalib/python/src/ipaaca/exception.py @@ -4,7 +4,7 @@ # "Incremental Processing Architecture # for Artificial Conversational Agents". # -# Copyright (c) 2009-2014 Social Cognitive Systems Group +# Copyright (c) 2009-2015 Social Cognitive Systems Group # CITEC, Bielefeld University # # http://opensource.cit-ec.de/projects/ipaaca/ @@ -82,13 +82,21 @@ class IUPublishedError(IpaacaError): class IUReadOnlyError(IpaacaError): """Error indicating that an IU is immutable because it is 'read only'.""" def __init__(self, iu): - super(IUReadOnlyError, self).__init__('Writing to IU ' + str(iu.uid) + ' failed -- it is read-only.') + super(IUReadOnlyError, self).__init__( + 'Writing to IU ' + str(iu.uid) + ' failed -- it is read-only.') class IUResendRequestFailedError(IpaacaError): """Error indicating that a remote IU resend failed.""" def __init__(self, iu): - super(IUResendFailedError, self).__init__('Remote resend failed for IU ' + str(iu.uid) + '.') + super(IUResendRequestFailedError, self).__init__( + 'Remote resend failed for IU ' + str(iu.uid) + '.') + + +class IURetractedError(IpaacaError): + """Error indicating that an IU has been retracted.""" + def __init__(self, iu): + super(IURetractedError, self).__init__('Writing to IU ' + str(iu.uid) + ' failed -- it has been retracted.') class IUUpdateFailedError(IpaacaError): diff --git a/ipaacalib/python/src/ipaaca/iu.py b/ipaacalib/python/src/ipaaca/iu.py index fd55bd78a3dc7b15ae248432cbce202331d8323e..66f139fce36b2b97bb21a76c9fa18bd5763e98d3 100644 --- a/ipaacalib/python/src/ipaaca/iu.py +++ b/ipaacalib/python/src/ipaaca/iu.py @@ -4,7 +4,7 @@ # "Incremental Processing Architecture # for Artificial Conversational Agents". # -# Copyright (c) 2009-2014 Social Cognitive Systems Group +# Copyright (c) 2009-2015 Social Cognitive Systems Group # CITEC, Bielefeld University # # http://opensource.cit-ec.de/projects/ipaaca/ @@ -114,7 +114,7 @@ class IUInterface(object): s += k+":'"+unicode(v)+"', " s += "} " s += "links={ " - for t,ids in self.get_all_links().items(): + for t, ids in self.get_all_links().items(): s += t+":'"+unicode(ids)+"', " s += "} " s += "}" @@ -173,9 +173,9 @@ class IUInterface(object): if self._buffer is None: self._payload_type = type else: - raise IpaacaException('The IU is already in a buffer, cannot change payload type anymore.') + raise ipaaca.exception.IpaacaError('The IU is already in a buffer, cannot change payload type anymore.') payload_type = property( - fget=_get_payload_type, + fget=_get_payload_type, fset=_set_payload_type, doc='Type of the IU payload') @@ -209,7 +209,7 @@ class IUInterface(object): return self._buffer def _set_buffer(self, buffer): if self._buffer is not None: - raise IpaacaException('The IU is already in a buffer, cannot move it.') + raise ipaaca.exception.IpaacaError('The IU is already in a buffer, cannot move it.') self._buffer = buffer buffer = property( fget=_get_buffer, @@ -220,7 +220,7 @@ class IUInterface(object): return self._owner_name def _set_owner_name(self, owner_name): if self._owner_name is not None: - raise Exception('The IU already has an owner name, cannot change it.') + raise ipaaca.exception.IpaacaError('The IU already has an owner name, cannot change it.') self._owner_name = owner_name owner_name = property( fget=_get_owner_name, @@ -241,7 +241,9 @@ class IU(IUInterface): self._payload = ipaaca.payload.Payload(iu=self) def _modify_links(self, is_delta=False, new_links={}, links_to_remove={}, writer_name=None): - if self.committed: + if self._retracted: + raise ipaaca.exception.IURetractedError(self) + if self._committed: raise ipaaca.exception.IUCommittedError(self) with self.revision_lock: # modify links locally @@ -258,7 +260,9 @@ class IU(IUInterface): def _modify_payload(self, is_delta=True, new_items={}, keys_to_remove=[], writer_name=None): """Modify the payload: add or remove items from this payload locally and send update.""" - if self.committed: + if self._retracted: + raise ipaaca.exception.IURetractedError(self) + if self._committed: raise ipaaca.exception.IUCommittedError(self) with self.revision_lock: # set item locally @@ -279,23 +283,33 @@ class IU(IUInterface): self._revision += 1 def _internal_commit(self, writer_name=None): - if self.committed: - raise ipaaca.exception.IUCommittedError(self) + if self._committed: + return + if self._retracted: + raise ipaaca.exception.IURetractedError(self) with self.revision_lock: - if not self._committed: - self._increase_revision_number() - self._committed = True - if self.buffer is not None: - self.buffer._send_iu_commission(self, writer_name=writer_name) + self._increase_revision_number() + self._committed = True + if self.buffer is not None: + self.buffer._send_iu_commission(self, writer_name=writer_name) def commit(self): """Commit to this IU.""" return self._internal_commit() + def retract(self): + if self._buffer: + self._buffer.remove(self) + self._buffer = None + else: + self._retracted = True + def _get_payload(self): return self._payload def _set_payload(self, new_pl, writer_name=None): - if self.committed: + if self._retracted: + raise ipaaca.exception.IURetractedError(self) + if self._committed: raise ipaaca.exception.IUCommittedError(self) with self.revision_lock: self._increase_revision_number() @@ -316,7 +330,7 @@ class IU(IUInterface): def _set_buffer(self, buffer): if self._buffer is not None: - raise Exception('The IU is already in a buffer, cannot move it.') + raise ipaaca.exception.IpaacaError('The IU is already in a buffer, cannot move it.') self._buffer = buffer self.owner_name = buffer.unique_name self._payload.owner_name = buffer.unique_name @@ -364,7 +378,9 @@ class Message(IU): if self.is_published: LOGGER.info('Info: modifying a Message after sending has no global effects') else: - if self.committed: + if self._retracted: + raise ipaaca.exception.IURetractedError(self) + if self._committed: raise ipaaca.exception.IUCommittedError(self) with self.revision_lock: self._increase_revision_number() @@ -385,7 +401,7 @@ class Message(IU): def _set_buffer(self, buffer): if self._buffer is not None: - raise Exception('The IU is already in a buffer, cannot move it.') + raise ipaaca.exception.IpaacaError('The IU is already in a buffer, cannot move it.') self._buffer = buffer self.owner_name = buffer.unique_name self._payload.owner_name = buffer.unique_name @@ -414,7 +430,6 @@ class RemoteMessage(IUInterface): self._category = category self.owner_name = owner_name self._committed = committed - self._retracted = False # NOTE Since the payload is an already-existant Payload which we didn't modify ourselves, # don't try to invoke any modification checks or network updates ourselves either. # We are just receiving it here and applying the new data. @@ -481,7 +496,6 @@ class RemotePushIU(IUInterface): self._category = category self.owner_name = owner_name self._committed = committed - self._retracted = False # NOTE Since the payload is an already-existant Payload which we didn't modify ourselves, # don't try to invoke any modification checks or network updates ourselves either. # We are just receiving it here and applying the new data. @@ -490,9 +504,11 @@ class RemotePushIU(IUInterface): def _modify_links(self, is_delta=False, new_links={}, links_to_remove={}, writer_name=None): """Modify the links: add or remove item from this payload remotely and send update.""" - if self.committed: + if self._retracted: + raise ipaaca.exception.IURetractedError(self) + if self._committed: raise ipaaca.exception.IUCommittedError(self) - if self.read_only: + if self._read_only: raise ipaaca.exception.IUReadOnlyError(self) requested_update = ipaaca.converter.IULinkUpdate( uid=self.uid, @@ -510,9 +526,11 @@ class RemotePushIU(IUInterface): def _modify_payload(self, is_delta=True, new_items={}, keys_to_remove=[], writer_name=None): """Modify the payload: add or remove item from this payload remotely and send update.""" - if self.committed: + if self._retracted: + raise ipaaca.exception.IURetractedError(self) + if self._committed: raise ipaaca.exception.IUCommittedError(self) - if self.read_only: + if self._read_only: raise ipaaca.exception.IUReadOnlyError(self) requested_update = ipaaca.converter.IUPayloadUpdate( uid=self.uid, @@ -531,30 +549,32 @@ class RemotePushIU(IUInterface): def commit(self): """Commit to this IU.""" - if self.read_only: - raise ipaaca.exception.IUReadOnlyError(self) if self._committed: - # ignore commit requests when already committed return + if self._retracted: + raise ipaaca.exception.IURetractedError(self) + if self._read_only: + raise ipaaca.exception.IUReadOnlyError(self) + commission_request = ipaaca_pb2.IUCommission() + commission_request.uid = self.uid + commission_request.revision = self.revision + commission_request.writer_name = self.buffer.unique_name + remote_server = self.buffer._get_remote_server(self) + new_revision = remote_server.commit(commission_request) + if new_revision == 0: + raise ipaaca.exception.IUUpdateFailedError(self) else: - commission_request = ipaaca_pb2.IUCommission() - commission_request.uid = self.uid - commission_request.revision = self.revision - commission_request.writer_name = self.buffer.unique_name - remote_server = self.buffer._get_remote_server(self) - new_revision = remote_server.commit(commission_request) - if new_revision == 0: - raise ipaaca.exception.IUUpdateFailedError(self) - else: - self._revision = new_revision - self._committed = True + self._revision = new_revision + self._committed = True def _get_payload(self): return self._payload def _set_payload(self, new_pl): - if self.committed: + if self._retracted: + raise ipaaca.exception.IURetractedError(self) + if self._committed: raise ipaaca.exception.IUCommittedError(self) - if self.read_only: + if self._read_only: raise ipaaca.exception.IUReadOnlyError(self) requested_update = ipaaca.converter.IUPayloadUpdate( uid=self.uid, diff --git a/ipaacalib/python/src/ipaaca/misc.py b/ipaacalib/python/src/ipaaca/misc.py index 44932d5f47442df1b4ce44c5399a31433a374431..b3bec913534df397dcb44124c9ff23354b0cf04d 100644 --- a/ipaacalib/python/src/ipaaca/misc.py +++ b/ipaacalib/python/src/ipaaca/misc.py @@ -4,7 +4,7 @@ # "Incremental Processing Architecture # for Artificial Conversational Agents". # -# Copyright (c) 2009-2014 Social Cognitive Systems Group +# Copyright (c) 2009-2016 Social Cognitive Systems Group # CITEC, Bielefeld University # # http://opensource.cit-ec.de/projects/ipaaca/ @@ -124,6 +124,16 @@ class IpaacaArgumentParser(argparse.ArgumentParser): rsb_logger.removeHandler(__GENERIC_NO_LOG_HANDLER) rsb_logger.setLevel(level=values) + class IpaacaRSBSpreadHost(argparse.Action): + + def __call__(self, parser, namespace, values, option_string=None): + ipaaca.defaults.IPAACA_DEFAULT_RSB_SPREAD_HOST = values + + class IpaacaRSBSpreadPort(argparse.Action): + + def __call__(self, parser, namespace, values, option_string=None): + ipaaca.defaults.IPAACA_DEFAULT_RSB_SPREADPORT = values + def __init__(self, prog=None, usage=None, description=None, epilog=None, parents=[], formatter_class=argparse.HelpFormatter, prefix_chars='-', fromfile_prefix_chars=None, @@ -136,6 +146,7 @@ class IpaacaArgumentParser(argparse.ArgumentParser): conflict_handler=conflict_handler, add_help=add_help) def _add_ipaaca_lib_arguments(self): + # CMD-arguments for ipaaca ipaacalib_group = self.add_argument_group('IPAACA library arguments') ipaacalib_group.add_argument( '--ipaaca-payload-type', @@ -157,6 +168,7 @@ class IpaacaArgumentParser(argparse.ArgumentParser): choices=['CRITICAL', 'ERROR', 'WARNING', 'INFO', 'DEBUG'], dest='_ipaaca_logging_level_', help="enable IPAACA logging with threshold") + # CMD-arguments for rsb rsblib_group = self.add_argument_group('RSB library arguments') rsblib_group.add_argument( '--rsb-enable-logging', @@ -164,6 +176,20 @@ class IpaacaArgumentParser(argparse.ArgumentParser): choices=['CRITICAL', 'ERROR', 'WARNING', 'INFO', 'DEBUG'], dest='_ipaaca_rsb_enable_logging_', help="enable RSB logging with threshold") + rsblib_group.add_argument( + '--rsb-spread-host', + action=self.IpaacaRSBSpreadHost, + default=None, + dest='_ipaaca_rsb_set_spread_host_', + metavar='HOST', + help="set RSB spread host") + rsblib_group.add_argument( + '--rsb-spread-port', + action=self.IpaacaRSBSpreadPort, + default=None, + dest='_ipaaca_rsb_set_spread_port_', + metavar='PORT', + help="set RSB spread port") def parse_args(self, args=None, namespace=None): self._add_ipaaca_lib_arguments() # Add ipaaca-args just before parsing diff --git a/ipaacalib/python/src/ipaaca/util/logger.py b/ipaacalib/python/src/ipaaca/util/logger.py new file mode 100644 index 0000000000000000000000000000000000000000..bd254ba0c46203ce60b4f5c6be702a7160e288af --- /dev/null +++ b/ipaacalib/python/src/ipaaca/util/logger.py @@ -0,0 +1,313 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# This file is part of IPAACA, the +# "Incremental Processing Architecture +# for Artificial Conversational Agents". +# +# Copyright (c) 2009-2015 Social Cognitive Systems 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. + +from __future__ import division, print_function + +import datetime +import subprocess +import sys +import threading +import time +import traceback +import uuid + +import ipaaca + + +__all__ = [ + 'logger_send_ipaaca_logs', + 'logger_set_log_filename', + 'logger_set_module_name', + 'LOG_DEBUG', + 'LOG_INFO', + 'LOG_WARN', + 'LOG_WARNING', + 'LOG_ERROR', +] + +LOGGER_LOCK = threading.RLock() + +MODULE_NAME = sys.argv[0] + +SEND_IPAACA_LOGS = True + +OUTPUT_BUFFER = None + +STANDARD_LOG_FILE_EXTENSION = '.log' + +LOG_MODES = ['append', 'timestamp', 'overwrite'] + + +def logger_set_log_filename(filename, existing=None): + global OUTPUT_BUFFER + if existing is not None and not existing in LOG_MODES: + raise Exception('Invalid log mode {mode} given. ' + 'Valid options are {options}.'.format( + mode=existing, + options=', '.join(LOG_MODES))) + with LOGGER_LOCK: + if OUTPUT_BUFFER is None: + OUTPUT_BUFFER = ipaaca.OutputBuffer('LogSender') + msg = ipaaca.Message('logcontrol') + msg.payload = { + 'cmd': 'open_log_file', + 'filename': filename} + if existing is not None: + msg.payload['existing'] = existing + OUTPUT_BUFFER.add(msg) + + +def logger_set_module_name(name): + global MODULE_NAME + with LOGGER_LOCK: + MODULE_NAME = name + + +def logger_send_ipaaca_logs(flag=True): + global SEND_IPAACA_LOGS + with LOGGER_LOCK: + SEND_IPAACA_LOGS = flag + + +def LOG_IPAACA(lvl, text, now=0.0, fn='???', thread='???'): + global OUTPUT_BUFFER + uid = str(uuid.uuid4())[0:8] + with LOGGER_LOCK: + if OUTPUT_BUFFER is None: + OUTPUT_BUFFER = ipaaca.OutputBuffer('LogSender') + msg = ipaaca.Message('log') + msg.payload = { + 'module': MODULE_NAME, + 'function': fn, + 'level': lvl, + 'time':' %.3f'%now, + 'thread': thread, + 'uuid': uid, + 'text': text,} + try: + OUTPUT_BUFFER.add(msg) + except Exception, e: + LOG_ERROR('Caught an exception while logging via ipaaca. ' + + ' str(e); ' + + traceback.format_exc()) + + +def LOG_CONSOLE(lvlstr, msg, fn_markup='[38;5;142m', msg_markup='', now=0.0, fn='???', thread='???'): + if isinstance(msg, basestring): + lines = msg.split('\n') + else: + lines = [msg] + for line in lines: + text = lvlstr+' '+thread+' '+fn_markup+fn+'[m'+' '+msg_markup+unicode(line)+'[m' + print(text) + fn = ' '*len(fn) + + +def LOG_ERROR(msg, now=None): + now = time.time() if now is None else now + f = sys._getframe(1) + classprefix = (f.f_locals['self'].__class__.__name__+'.') if 'self' in f.f_locals else '' + fn = classprefix + f.f_code.co_name + thread = threading.current_thread().getName() + with LOGGER_LOCK: + if SEND_IPAACA_LOGS: LOG_IPAACA('ERROR', msg, now=now, fn=fn, thread=thread) + LOG_CONSOLE('[38;5;9;1;4m[ERROR][m', msg, fn_markup='[38;5;203m', msg_markup='[38;5;9;1;4m', now=now, fn=fn, thread=thread) + + +def LOG_WARN(msg, now=None): + now = time.time() if now is None else now + f = sys._getframe(1) + classprefix = (f.f_locals['self'].__class__.__name__+'.') if 'self' in f.f_locals else '' + fn = classprefix + f.f_code.co_name + thread = threading.current_thread().getName() + with LOGGER_LOCK: + if SEND_IPAACA_LOGS: LOG_IPAACA('WARN', msg, now=now, fn=fn, thread=thread) + LOG_CONSOLE('[38;5;208;1m[WARN][m ', msg, fn_markup='[38;5;214m', msg_markup='[38;5;208;1m', now=now, fn=fn, thread=thread) + + +LOG_WARNING = LOG_WARN + + +def LOG_INFO(msg, now=None): + now = time.time() if now is None else now + f = sys._getframe(1) + classprefix = (f.f_locals['self'].__class__.__name__+'.') if 'self' in f.f_locals else '' + fn = classprefix + f.f_code.co_name + thread = threading.current_thread().getName() + with LOGGER_LOCK: + if SEND_IPAACA_LOGS: LOG_IPAACA('INFO', msg, now=now, fn=fn, thread=thread) + LOG_CONSOLE('[INFO] ', msg, now=now, fn=fn, thread=thread) + + +def LOG_DEBUG(msg, now=None): + now = time.time() if now is None else now + f = sys._getframe(1) + classprefix = (f.f_locals['self'].__class__.__name__+'.') if 'self' in f.f_locals else '' + fn = classprefix + f.f_code.co_name + thread = threading.current_thread().getName() + with LOGGER_LOCK: + if SEND_IPAACA_LOGS: LOG_IPAACA('DEBUG', msg, now=now, fn=fn, thread=thread) + LOG_CONSOLE('[2m[DEBUG][m', msg, fn_markup='[38;5;144m', msg_markup='[38;5;248m', now=now, fn=fn, thread=thread) + + +class LoggerComponent(object): + + def __init__(self, filename, log_mode='append'): + self.ib = ipaaca.InputBuffer('Logger', ['log', 'logcontrol']) + self.ib.register_handler(self._logger_handle_iu_event) + self.logfile = None + self.log_mode = log_mode + self.open_logfile(filename) + if self.logfile is None: + print('Logging to console only ...') + print('Press Ctrl-C at any time to terminate the logger.') + + def open_logfile(self, filename): + with LOGGER_LOCK: + if filename is None or filename.strip() == '': + print('No log file name specified, not opening one.') + self.close_logfile() + else: + new_logfile = None + try: + # create dir first + ret = subprocess.call( + 'mkdir -p `dirname ' + filename + '`', + shell=True) + # proceed with dir+file + if self.log_mode == 'timestamp': + t = datetime.datetime.now().strftime('%Y-%m-%d-%H%M%S') + if filename.endswith(STANDARD_LOG_FILE_EXTENSION): + # insert timestamp between filename and extension + # (only for standard extension) + filename = filename.replace( + STANDARD_LOG_FILE_EXTENSION, + '.' + t + STANDARD_LOG_FILE_EXTENSION) + else: # prepend timestamp + filename = t + '_' + filename + append_if_exist = not (self.log_mode == 'overwrite' or + self.log_mode == 'timestamp') + new_logfile = open(filename, 'a' if append_if_exist else 'w') + if self.logfile is not None: + text = u'Will now continue logging in log file ' + unicode(filename) + uid = str(uuid.uuid4())[0:8] + tim = time.time() + record = { + 'uuid': uid, + 'time': tim, + 'level': u'INFO', + 'text': text, + 'module': u'logger', + 'function': u'LoggerComponent.open_logfile', + 'thread': '-', + 'logreceivedtime': tim} + self.logfile.write(unicode(record)+'\n') + self.logfile.close() + self.logfile = new_logfile + print('Logging to console and {filename} ...'.format(filename=filename)) + except Exception as e: + print('Failed to open logfile {filename} for writing! Keeping previous configuration'.format(filename=filename)) + + def close_logfile(self): + if self.logfile is not None: + text = u'Closing of log file requested.' + uid = unicode(uuid.uuid4())[0:8] + tim = unicode(time.time()) + record = { + 'uuid': uid, + 'time': tim, + 'level': u'INFO', + 'text': text, + 'module': u'logger', + 'function': u'LoggerComponent.close_logfile', + 'thread': u'-', + 'logreceivedtime': tim} + self.logfile.write(unicode(record)+'\n') + self.logfile.close() + print('Closed current log file.') + self.logfile = None + + def _logger_handle_iu_event(self, iu, event_type, own): + received_time = "%.3f" % time.time() + with LOGGER_LOCK: + try: + if iu.category == 'log': + pl = iu.payload + message = pl['text'] if 'text' in pl else '(No message.)' + uid = '????????' if 'uuid' not in pl else pl['uuid'] + tim = '???' if 'time' not in pl else pl['time'] + module = '???' if 'module' not in pl else pl['module'] + function = '???' if 'function' not in pl else pl['function'] + thread = '???' if 'thread' not in pl else pl['thread'] + level = 'INFO' if 'level' not in pl else pl['level'] + # dump to console + if level=='WARN': + level='WARNING' + if level not in ['DEBUG','INFO','WARNING','ERROR']: + level = 'INFO' + try: + print('%s %-8s {%s} {%s} {%s} %s'%(tim, ('['+level+']'), thread, module, function, message)) + except: + print('Failed to format a string for printing!') + if self.logfile is not None: + try: + record = { + 'uuid': uid, + 'time': tim, + 'level': level, + 'text': message, + 'module': module, + 'function': function, + 'thread': thread, + 'logreceivedtime': received_time} + self.logfile.write(unicode(record) + '\n') + except: + print('Failed to write to logfile!') + elif iu.category == 'logcontrol': + cmd = iu.payload['cmd'] + if cmd == 'open_log_file': + filename = iu.payload['filename'] if 'filename' in iu.payload else '' + if 'existing' in iu.payload: + log_mode_ = iu.payload['existing'].lower() + if log_mode_ not in LOG_MODES: + LOG_WARN(u'Value of "existing" should be "append", timestamp, or "overwrite", continuing with mode {mode}'.format(mode=self.log_mode)) + else: + self.log_mode = log_mode_ + self.open_logfile(filename) + elif cmd == 'close_log_file': + self.close_logfile() + else: + LOG_WARN(u'Received unknown logcontrol command: '+unicode(cmd)) + except Exception, e: + print('Exception while logging!') # TODO write to file as well? + print(u' '+unicode(traceback.format_exc())) diff --git a/ipaacatools/scripts/ipaaca-iu-sniffer b/ipaacatools/scripts/ipaaca-iu-sniffer index a4db5847098f8a1078cf50d4051719a84642f8f6..82e919432887c96b9d51320f174e71570b360d39 100755 --- a/ipaacatools/scripts/ipaaca-iu-sniffer +++ b/ipaacatools/scripts/ipaaca-iu-sniffer @@ -56,7 +56,7 @@ def event_type_color(typ): return colors.get(typ, '1') def highlight_if_color(s, c='1'): - return s if not arguments.color else '[' + c + 'm' + s +'[m' + return s if arguments.color else '[' + c + 'm' + s +'[m' def pretty_printed_dict(d): s='{\n' @@ -87,7 +87,7 @@ def pretty_printed_iu_event(iu, event_type, local): s += '\npayload=' + pretty_printed_dict(iu.payload) return s -def my_update_handler(iu, event_type, local): +def iu_event_handler(iu, event_type, local): if arguments.regex: for cat in arguments.categories: # actually now regexs, not categories if re.match(cat, iu.category): @@ -96,19 +96,13 @@ def my_update_handler(iu, event_type, local): return print(pretty_printed_iu_event(iu, event_type, local), end='\n\n') - +def exit(code): + if platform.system() == 'Windows': + os._exit(code) + else: + sys.exit(code) parser = ipaaca.IpaacaArgumentParser(description='Ipaaca IU Sniffer -- Selectively listen to IPAACA traffic') -parser.add_argument( - '-r', '--regex', - action='store_true', - dest='regex', - help='match categories by regular expressions') -parser.add_argument( - '-c', '--color', - action='store_true', - dest='color', - help='colorize output') parser.add_argument( '--channels', dest='channels', @@ -117,12 +111,29 @@ parser.add_argument( nargs='+', help="set the channels to listen on (otherwise 'default')") parser.add_argument( - '--categories', + '-c', '--categories', default=[''], dest='categories', metavar='CATEGORY', nargs='+', help='set categories (or regex patterns) to be matched') +parser.add_argument( + '-e', '--event-types', + default=None, + dest='event_types', + metavar='EVENT-TYPE', + nargs='+', + help='set event types ({})'.format(' '.join(ipaaca.iu.IUEventType._choices))) +parser.add_argument( + '-r', '--regex', + action='store_true', + dest='regex', + help='match categories by regular expressions') +parser.add_argument( + '--no-color', + action='store_true', + dest='color', + help='do not colorize output') parser.add_argument( '--size-limit', default=2048, @@ -134,37 +145,45 @@ parser.add_argument( if __name__ == '__main__': arguments = parser.parse_args() - buffers = {} + + # Create one input buffer for each channel we are listening on for channel in arguments.channels: buffers[channel] = ipaaca.InputBuffer( 'IpaacaIUSniffer', category_interests=arguments.categories if not arguments.regex else [''], channel=channel, resend_active=True) - buffers[channel].register_handler(my_update_handler) - - channellist = 's ' if len(arguments.channels) > 1 else ' ' - channellist += ', '.join(arguments.channels) - - print('Listening on channel' + channellist + ' for IU events of ', end='') + # Check whether the specified event_types are valid + if arguments.event_types is not None: + for et in arguments.event_types: + if et.upper() not in ipaaca.iu.IUEventType._choices: + print('ERROR: "{et}" is not a valid IPAACA event type.'.format(et=et.upper())) + exit(code=1) + buffers[channel].register_handler( + iu_event_handler, + for_event_types=[et.upper() for et in arguments.event_types] if arguments.event_types is not None else None) + + # Tell user what we are doing + print('ipaaca-iu-sniffer listening') + print(' * on channel(s): ' + ', '.join(arguments.channels)) + print(' * for event type(s): ', end='') + if arguments.event_types is None: + print('any') + else: + print(', '.join([highlight_if_color(et.upper(), event_type_color(et.upper())) for et in arguments.event_types])) + print(' * for category/ies', end='') if arguments.categories == ['']: - print('any category ...') + print(': any') else: if arguments.regex: - print('whose category matches one of the regexes:') - else: - print('categories:') - print('\t' + ', '.join(arguments.categories)) - print('') + print(' that match the regex', end='') + print(': ' + ', '.join(arguments.categories)) + + # Wait for the user to kill the sniffer try: while True: time.sleep(1) except KeyboardInterrupt: pass - - if platform.system() == 'Windows': - os._exit(0) - else: - sys.exit(0) - + exit(code=0) diff --git a/ipaacatools/scripts/ipaaca-logger b/ipaacatools/scripts/ipaaca-logger new file mode 100755 index 0000000000000000000000000000000000000000..230143cfd2e193ad2507aa7c2671e8585be76aa6 --- /dev/null +++ b/ipaacatools/scripts/ipaaca-logger @@ -0,0 +1,69 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# This file is part of IPAACA, the +# "Incremental Processing Architecture +# for Artificial Conversational Agents". +# +# Copyright (c) 2009-2015 Social Cognitive Systems 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. + +from __future__ import division, print_function + +import sys +import time + +import ipaaca +import ipaaca.util.logger as ipaacalog + + +def main(log_mode, filename=None): + ipaacalog.logger_send_ipaaca_logs(False) + il = ipaacalog.LoggerComponent(filename, log_mode) + try: + while True: + time.sleep(1) + except KeyboardInterrupt: + il.close_logfile() + print('Logging-Component closed by keyboard interrupt.') + sys.exit(0) + + +if __name__ == '__main__': + iap = ipaaca.IpaacaArgumentParser( + 'ipaaca-logger') + iap.add_argument( + '-m', '--log-mode', dest='log_mode', + choices=ipaacalog.LOG_MODES, + default='append', + help="set what to do when logfile exists " + "(default: 'append'; 'timestamp' adds timestamp in any case)") + iap.add_argument( + 'filename', nargs='?', + metavar='FILE', + help='set name of logfile') + arguments = iap.parse_args() + main(arguments.log_mode, arguments.filename)