# HG changeset patch # User am@osimis.io # Date 1534942760 -7200 # Node ID 89d02de83c035ac862b390c362e91117435701a7 # Parent c9cf95b49a86e697655748e9fd3785304817c19e added declaretion of messages handled/emitted diff -r c9cf95b49a86 -r 89d02de83c03 Applications/Samples/SimpleViewerApplication.h --- a/Applications/Samples/SimpleViewerApplication.h Tue Aug 21 18:14:22 2018 +0200 +++ b/Applications/Samples/SimpleViewerApplication.h Wed Aug 22 14:59:20 2018 +0200 @@ -177,8 +177,8 @@ virtual void HandleMessage(const IObservable& from, const IMessage& message) { switch (message.GetType()) { - case MessageType_GeometryReady: - mainLayout_->SetDefaultView(); + case MessageType_Widget_GeometryChanged: + //TODO remove constness !! dynamic_cast(from).SetDefaultView(); break; default: VLOG("unhandled message type" << message.GetType()); @@ -208,6 +208,8 @@ wasmViewport2_(NULL), slice_(0) { + DeclareIgnoredMessage(MessageType_Widget_ContentChanged); + DeclareHandledMessage(MessageType_Widget_GeometryChanged); } virtual void Finalize() {} @@ -267,6 +269,9 @@ mainViewport_ = new LayerWidget(broker_); thumbnails_.push_back(new LayerWidget(broker_)); thumbnails_.push_back(new LayerWidget(broker_)); + mainViewport_->RegisterObserver(*this); + thumbnails_[0]->RegisterObserver(*this); + thumbnails_[1]->RegisterObserver(*this); // hierarchy mainLayout_->AddWidget(thumbnailsLayout_); @@ -277,7 +282,6 @@ // sources smartLoader_.reset(new SmartLoader(broker_, context_->GetWebService())); smartLoader_->SetImageQuality(SliceImageQuality_FullPam); - smartLoader_->RegisterObserver(*this); mainViewport_->AddLayer(smartLoader_->GetFrame(instances_[currentInstanceIndex_], 0)); thumbnails_[0]->AddLayer(smartLoader_->GetFrame(instances_[0], 0)); diff -r c9cf95b49a86 -r 89d02de83c03 Framework/Layers/ILayerSource.h --- a/Framework/Layers/ILayerSource.h Tue Aug 21 18:14:22 2018 +0200 +++ b/Framework/Layers/ILayerSource.h Wed Aug 22 14:59:20 2018 +0200 @@ -35,7 +35,7 @@ { const Slice& slice_; SliceChangedMessage(const Slice& slice) - : IMessage(MessageType_SliceChanged), + : IMessage(MessageType_LayerSource_SliceChanged), slice_(slice) { } @@ -50,7 +50,7 @@ LayerReadyMessage(std::auto_ptr& layer, const CoordinateSystem3D& slice, bool isError) // TODO Shouldn't this be separate as NotifyLayerError? - : IMessage(MessageType_LayerReady), + : IMessage(MessageType_LayerSource_LayerReady), layer_(layer), slice_(slice), isError_(isError) diff -r c9cf95b49a86 -r 89d02de83c03 Framework/Layers/LayerSourceBase.cpp --- a/Framework/Layers/LayerSourceBase.cpp Tue Aug 21 18:14:22 2018 +0200 +++ b/Framework/Layers/LayerSourceBase.cpp Wed Aug 22 14:59:20 2018 +0200 @@ -27,17 +27,17 @@ { void LayerSourceBase::NotifyGeometryReady() { - EmitMessage(IMessage(MessageType_GeometryReady)); + EmitMessage(IMessage(MessageType_LayerSource_GeometryReady)); } void LayerSourceBase::NotifyGeometryError() { - EmitMessage(IMessage(MessageType_GeometryError)); + EmitMessage(IMessage(MessageType_LayerSource_GeometryError)); } void LayerSourceBase::NotifyContentChange() { - EmitMessage(IMessage(MessageType_ContentChanged)); + EmitMessage(IMessage(MessageType_LayerSource_ContentChanged)); } void LayerSourceBase::NotifySliceChange(const Slice& slice) diff -r c9cf95b49a86 -r 89d02de83c03 Framework/Layers/LayerSourceBase.h --- a/Framework/Layers/LayerSourceBase.h Tue Aug 21 18:14:22 2018 +0200 +++ b/Framework/Layers/LayerSourceBase.h Wed Aug 22 14:59:20 2018 +0200 @@ -13,7 +13,7 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . **/ @@ -43,7 +43,13 @@ LayerSourceBase(MessageBroker& broker) : ILayerSource(broker) - {} + { + DeclareEmittableMessage(MessageType_LayerSource_GeometryReady); + DeclareEmittableMessage(MessageType_LayerSource_GeometryError); + DeclareEmittableMessage(MessageType_LayerSource_ContentChanged); + DeclareEmittableMessage(MessageType_LayerSource_SliceChanged); + DeclareEmittableMessage(MessageType_LayerSource_LayerReady); + } }; } diff -r c9cf95b49a86 -r 89d02de83c03 Framework/Layers/OrthancFrameLayerSource.cpp --- a/Framework/Layers/OrthancFrameLayerSource.cpp Tue Aug 21 18:14:22 2018 +0200 +++ b/Framework/Layers/OrthancFrameLayerSource.cpp Wed Aug 22 14:59:20 2018 +0200 @@ -35,7 +35,7 @@ { switch (message.GetType()) { - case MessageType_SliceGeometryReady: + case MessageType_SliceLoader_GeometryReady: { const OrthancSlicesLoader& loader = dynamic_cast(from); if (loader.GetSliceCount() > 0) @@ -48,12 +48,12 @@ } }; break; - case MessageType_SliceGeometryError: + case MessageType_SliceLoader_GeometryError: { const OrthancSlicesLoader& loader = dynamic_cast(from); LayerSourceBase::NotifyGeometryError(); }; break; - case MessageType_SliceImageReady: + case MessageType_SliceLoader_ImageReady: { const OrthancSlicesLoader::SliceImageReadyMessage& msg = dynamic_cast(message); bool isFull = (msg.effectiveQuality_ == SliceImageQuality_FullPng || msg.effectiveQuality_ == SliceImageQuality_FullPam); @@ -61,7 +61,7 @@ msg.slice_.GetGeometry(), false); }; break; - case MessageType_SliceImageError: + case MessageType_SliceLoader_ImageError: { const OrthancSlicesLoader::SliceImageErrorMessage& msg = dynamic_cast(message); LayerSourceBase::NotifyLayerReady(NULL, msg.slice_.GetGeometry(), true); @@ -79,6 +79,10 @@ loader_(broker, orthanc), quality_(SliceImageQuality_FullPng) { + DeclareHandledMessage(MessageType_SliceLoader_GeometryReady); + DeclareHandledMessage(MessageType_SliceLoader_GeometryError); + DeclareHandledMessage(MessageType_SliceLoader_ImageReady); + DeclareHandledMessage(MessageType_SliceLoader_ImageError); loader_.RegisterObserver(*this); } diff -r c9cf95b49a86 -r 89d02de83c03 Framework/Messages/IObservable.h --- a/Framework/Messages/IObservable.h Tue Aug 21 18:14:22 2018 +0200 +++ b/Framework/Messages/IObservable.h Wed Aug 22 14:59:20 2018 +0200 @@ -21,17 +21,35 @@ #pragma once +#include +#include +#include +#include + #include "MessageBroker.h" -#include +#include "MessageType.h" +#include "IObserver.h" namespace OrthancStone { + class MessageNotDeclaredException : public std::logic_error + { + MessageType messageType_; + public: + MessageNotDeclaredException(MessageType messageType) + : std::logic_error("Message not declared by observer."), + messageType_(messageType) + { + } + }; + class IObservable : public boost::noncopyable { protected: MessageBroker& broker_; std::set observers_; + std::set emittableMessages_; public: @@ -45,11 +63,17 @@ void EmitMessage(const IMessage& message) const { + if (emittableMessages_.find(message.GetType()) == emittableMessages_.end()) + { + throw MessageNotDeclaredException(message.GetType()); + } + broker_.EmitMessage(*this, observers_, message); } void RegisterObserver(IObserver& observer) { + CheckObserverDeclaredAllObservableMessages(observer); observers_.insert(&observer); } @@ -57,6 +81,31 @@ { observers_.erase(&observer); } + + const std::set& GetEmittableMessages() const + { + return emittableMessages_; + } + + protected: + + void DeclareEmittableMessage(MessageType messageType) + { + emittableMessages_.insert(messageType); + } + + void CheckObserverDeclaredAllObservableMessages(IObserver& observer) + { + for (std::set::const_iterator it = emittableMessages_.begin(); it != emittableMessages_.end(); it++) + { + // the observer must have "declared" all observable messages + if (observer.GetHandledMessages().find(*it) == observer.GetHandledMessages().end() + && observer.GetIgnoredMessages().find(*it) == observer.GetIgnoredMessages().end()) + { + throw MessageNotDeclaredException(*it); + } + } + } }; } diff -r c9cf95b49a86 -r 89d02de83c03 Framework/Messages/IObserver.h --- a/Framework/Messages/IObserver.h Tue Aug 21 18:14:22 2018 +0200 +++ b/Framework/Messages/IObserver.h Wed Aug 22 14:59:20 2018 +0200 @@ -23,7 +23,8 @@ #include "MessageBroker.h" #include "IMessage.h" -#include "IObservable.h" +#include +#include namespace OrthancStone { @@ -33,6 +34,8 @@ { protected: MessageBroker& broker_; + std::set handledMessages_; + std::set ignoredMessages_; public: IObserver(MessageBroker& broker) @@ -46,7 +49,40 @@ broker_.Unregister(*this); } + void HandleMessage_(const IObservable &from, const IMessage &message) + { + assert(handledMessages_.find(message.GetType()) != handledMessages_.end()); // please declare the messages that you're handling + + HandleMessage(from, message); + } + virtual void HandleMessage(const IObservable& from, const IMessage& message) = 0; + + + const std::set& GetHandledMessages() const + { + return handledMessages_; + } + + const std::set& GetIgnoredMessages() const + { + return ignoredMessages_; + } + + protected: + + // when you connect an IObserver to an IObservable, the observer must handle all observable messages (this is checked during the registration) + // so, all messages that may be emitted by the observable must be declared "handled" or "ignored" by the observer + void DeclareHandledMessage(MessageType messageType) + { + handledMessages_.insert(messageType); + } + + void DeclareIgnoredMessage(MessageType messageType) + { + ignoredMessages_.insert(messageType); + } + }; } diff -r c9cf95b49a86 -r 89d02de83c03 Framework/Messages/MessageBroker.cpp --- a/Framework/Messages/MessageBroker.cpp Tue Aug 21 18:14:22 2018 +0200 +++ b/Framework/Messages/MessageBroker.cpp Wed Aug 22 14:59:20 2018 +0200 @@ -42,7 +42,14 @@ for (std::vector::iterator observer = activeObservers.begin(); observer != activeObservers.end(); observer++) { - (*observer)->HandleMessage(from, message); + if ((*observer)->GetHandledMessages().find(message.GetType()) != (*observer)->GetHandledMessages().end()) + { + (*observer)->HandleMessage_(from, message); + } + else + { + assert((*observer)->GetIgnoredMessages().find(message.GetType()) != (*observer)->GetIgnoredMessages().end()); // message has not been declared by Observer (this should already have been checked during registration) + } } } diff -r c9cf95b49a86 -r 89d02de83c03 Framework/Messages/MessageType.h --- a/Framework/Messages/MessageType.h Tue Aug 21 18:14:22 2018 +0200 +++ b/Framework/Messages/MessageType.h Wed Aug 22 14:59:20 2018 +0200 @@ -24,21 +24,26 @@ enum MessageType { - MessageType_Generic, + MessageType_Widget_GeometryChanged, + MessageType_Widget_ContentChanged, - MessageType_GeometryReady, - MessageType_GeometryError, - MessageType_ContentChanged, - MessageType_SliceChanged, - MessageType_LayerReady, + MessageType_LayerSource_GeometryReady, + MessageType_LayerSource_GeometryError, + MessageType_LayerSource_ContentChanged, + MessageType_LayerSource_SliceChanged, + MessageType_LayerSource_LayerReady, - MessageType_SliceGeometryReady, - MessageType_SliceGeometryError, - MessageType_SliceImageReady, - MessageType_SliceImageError, + MessageType_SliceLoader_GeometryReady, + MessageType_SliceLoader_GeometryError, + MessageType_SliceLoader_ImageReady, + MessageType_SliceLoader_ImageError, MessageType_HttpRequestSuccess, - MessageType_HttpRequestError + MessageType_HttpRequestError, + + // used in unit tests only + MessageType_Test1, + MessageType_Test2 }; } diff -r c9cf95b49a86 -r 89d02de83c03 Framework/SmartLoader.cpp --- a/Framework/SmartLoader.cpp Tue Aug 21 18:14:22 2018 +0200 +++ b/Framework/SmartLoader.cpp Wed Aug 22 14:59:20 2018 +0200 @@ -30,17 +30,23 @@ IObserver(broker), imageQuality_(SliceImageQuality_FullPam), webService_(webService) - {} + { + DeclareHandledMessage(MessageType_LayerSource_GeometryReady); + DeclareHandledMessage(MessageType_LayerSource_LayerReady); + DeclareIgnoredMessage(MessageType_LayerSource_GeometryError); + DeclareIgnoredMessage(MessageType_LayerSource_ContentChanged); + DeclareIgnoredMessage(MessageType_LayerSource_SliceChanged); + } void SmartLoader::HandleMessage(const IObservable& from, const IMessage& message) { switch (message.GetType()) { - case MessageType_SliceGeometryReady: + case MessageType_LayerSource_GeometryReady: { const OrthancFrameLayerSource* layerSource=dynamic_cast(&from); // TODO keep track of objects that have been loaded already }; break; - case MessageType_SliceImageReady: + case MessageType_LayerSource_LayerReady: { const OrthancFrameLayerSource* layerSource=dynamic_cast(&from); // TODO keep track of objects that have been loaded already diff -r c9cf95b49a86 -r 89d02de83c03 Framework/Toolbox/IWebService.h --- a/Framework/Toolbox/IWebService.h Tue Aug 21 18:14:22 2018 +0200 +++ b/Framework/Toolbox/IWebService.h Wed Aug 22 14:59:20 2018 +0200 @@ -70,7 +70,10 @@ ICallback(MessageBroker& broker) : IObserver(broker) - {} + { + DeclareHandledMessage(MessageType_HttpRequestError); + DeclareHandledMessage(MessageType_HttpRequestSuccess); + } virtual ~ICallback() { } diff -r c9cf95b49a86 -r 89d02de83c03 Framework/Toolbox/OrthancSlicesLoader.cpp --- a/Framework/Toolbox/OrthancSlicesLoader.cpp Tue Aug 21 18:14:22 2018 +0200 +++ b/Framework/Toolbox/OrthancSlicesLoader.cpp Wed Aug 22 14:59:20 2018 +0200 @@ -253,7 +253,7 @@ { case Mode_FrameGeometry: case Mode_SeriesGeometry: - that_.EmitMessage(IMessage(MessageType_SliceGeometryError)); + that_.EmitMessage(IMessage(MessageType_SliceLoader_GeometryError)); that_.state_ = State_Error; break; @@ -321,12 +321,12 @@ if (ok) { LOG(INFO) << "Loaded a series with " << slices_.GetSliceCount() << " slice(s)"; - EmitMessage(IMessage(MessageType_SliceGeometryReady)); + EmitMessage(IMessage(MessageType_SliceLoader_GeometryReady)); } else { LOG(ERROR) << "This series is empty"; - EmitMessage(IMessage(MessageType_SliceGeometryError)); + EmitMessage(IMessage(MessageType_SliceLoader_GeometryError)); } } @@ -338,7 +338,7 @@ if (!MessagingToolbox::ParseJson(series, answer, size) || series.type() != Json::objectValue) { - EmitMessage(IMessage(MessageType_SliceGeometryError)); + EmitMessage(IMessage(MessageType_SliceLoader_GeometryError)); return; } @@ -385,7 +385,7 @@ if (!MessagingToolbox::ParseJson(tags, answer, size) || tags.type() != Json::objectValue) { - EmitMessage(IMessage(MessageType_SliceGeometryError)); + EmitMessage(IMessage(MessageType_SliceLoader_GeometryError)); return; } @@ -412,7 +412,7 @@ else { LOG(WARNING) << "Skipping invalid multi-frame instance " << instanceId; - EmitMessage(IMessage(MessageType_SliceGeometryError)); + EmitMessage(IMessage(MessageType_SliceLoader_GeometryError)); return; } } @@ -430,7 +430,7 @@ if (!MessagingToolbox::ParseJson(tags, answer, size) || tags.type() != Json::objectValue) { - EmitMessage(IMessage(MessageType_SliceGeometryError)); + EmitMessage(IMessage(MessageType_SliceLoader_GeometryError)); return; } @@ -446,12 +446,12 @@ { LOG(INFO) << "Loaded instance geometry " << instanceId; slices_.AddSlice(slice.release()); - EmitMessage(IMessage(MessageType_SliceGeometryReady)); + EmitMessage(IMessage(MessageType_SliceLoader_GeometryReady)); } else { LOG(WARNING) << "Skipping invalid instance " << instanceId; - EmitMessage(IMessage(MessageType_SliceGeometryError)); + EmitMessage(IMessage(MessageType_SliceLoader_GeometryError)); } } @@ -784,6 +784,10 @@ orthanc_(orthanc), state_(State_Initialization) { + DeclareEmittableMessage(MessageType_SliceLoader_GeometryReady); + DeclareEmittableMessage(MessageType_SliceLoader_GeometryError); + DeclareEmittableMessage(MessageType_SliceLoader_ImageError); + DeclareEmittableMessage(MessageType_SliceLoader_ImageReady); } diff -r c9cf95b49a86 -r 89d02de83c03 Framework/Toolbox/OrthancSlicesLoader.h --- a/Framework/Toolbox/OrthancSlicesLoader.h Tue Aug 21 18:14:22 2018 +0200 +++ b/Framework/Toolbox/OrthancSlicesLoader.h Wed Aug 22 14:59:20 2018 +0200 @@ -24,7 +24,7 @@ #include "IWebService.h" #include "SlicesSorter.h" #include "../StoneEnumerations.h" - +#include "../Messages/IObservable.h" #include namespace OrthancStone @@ -43,7 +43,7 @@ const Slice& slice, std::auto_ptr& image, SliceImageQuality effectiveQuality) - : IMessage(MessageType_SliceImageReady), + : IMessage(MessageType_SliceLoader_ImageReady), sliceIndex_(sliceIndex), slice_(slice), image_(image), @@ -61,7 +61,7 @@ SliceImageErrorMessage(unsigned int sliceIndex, const Slice& slice, SliceImageQuality effectiveQuality) - : IMessage(MessageType_SliceImageError), + : IMessage(MessageType_SliceLoader_ImageError), slice_(slice), sliceIndex_(sliceIndex), effectiveQuality_(effectiveQuality) diff -r c9cf95b49a86 -r 89d02de83c03 Framework/Widgets/LayerWidget.cpp --- a/Framework/Widgets/LayerWidget.cpp Tue Aug 21 18:14:22 2018 +0200 +++ b/Framework/Widgets/LayerWidget.cpp Wed Aug 22 14:59:20 2018 +0200 @@ -361,8 +361,18 @@ LayerWidget::LayerWidget(MessageBroker& broker) : IObserver(broker), + IObservable(broker), started_(false) { + DeclareHandledMessage(MessageType_LayerSource_GeometryReady); + DeclareHandledMessage(MessageType_LayerSource_ContentChanged); + DeclareHandledMessage(MessageType_LayerSource_LayerReady); + DeclareHandledMessage(MessageType_LayerSource_SliceChanged); + DeclareHandledMessage(MessageType_LayerSource_GeometryError); + + DeclareEmittableMessage(MessageType_Widget_GeometryChanged); + DeclareEmittableMessage(MessageType_Widget_ContentChanged); + SetBackgroundCleared(true); } @@ -483,19 +493,19 @@ void LayerWidget::HandleMessage(const IObservable& from, const IMessage& message) { switch (message.GetType()) { - case MessageType_GeometryReady: + case MessageType_LayerSource_GeometryReady: OnGeometryReady(dynamic_cast(from)); break; - case MessageType_GeometryError: + case MessageType_LayerSource_GeometryError: LOG(ERROR) << "Cannot get geometry"; break; - case MessageType_ContentChanged: + case MessageType_LayerSource_ContentChanged: OnContentChanged(dynamic_cast(from)); break; - case MessageType_SliceChanged: + case MessageType_LayerSource_SliceChanged: OnSliceChanged(dynamic_cast(from), dynamic_cast(message).slice_); break; - case MessageType_LayerReady: + case MessageType_LayerSource_LayerReady: { const ILayerSource::LayerReadyMessage& layerReadyMessage = dynamic_cast(message); OnLayerReady(layerReadyMessage.layer_, @@ -518,6 +528,7 @@ changedLayers_[i] = true; //layers_[i]->ScheduleLayerCreation(slice_); } + EmitMessage(IMessage(MessageType_Widget_GeometryChanged)); } void LayerWidget::InvalidateAllLayers() diff -r c9cf95b49a86 -r 89d02de83c03 Framework/Widgets/LayerWidget.h --- a/Framework/Widgets/LayerWidget.h Tue Aug 21 18:14:22 2018 +0200 +++ b/Framework/Widgets/LayerWidget.h Wed Aug 22 14:59:20 2018 +0200 @@ -13,7 +13,7 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . **/ @@ -31,8 +31,9 @@ namespace OrthancStone { class LayerWidget : - public WorldSceneWidget, - public IObserver + public WorldSceneWidget, + public IObserver, + public IObservable { private: class Scene; @@ -59,12 +60,12 @@ virtual void OnContentChanged(const ILayerSource& source); virtual void OnSliceChanged(const ILayerSource& source, - const Slice& slice); + const Slice& slice); virtual void OnLayerReady(std::auto_ptr& renderer, - const ILayerSource& source, - const CoordinateSystem3D& slice, - bool isError); + const ILayerSource& source, + const CoordinateSystem3D& slice, + bool isError); void ResetChangedLayers(); @@ -75,7 +76,7 @@ virtual void HandleMessage(const IObservable& from, const IMessage& message); virtual Extent2D GetSceneExtent(); - + protected: virtual bool RenderScene(CairoContext& context, const ViewportGeometry& view); diff -r c9cf95b49a86 -r 89d02de83c03 Framework/dev.h --- a/Framework/dev.h Tue Aug 21 18:14:22 2018 +0200 +++ b/Framework/dev.h Wed Aug 22 14:59:20 2018 +0200 @@ -203,14 +203,14 @@ { switch (message.GetType()) { - case MessageType_SliceGeometryReady: + case MessageType_SliceLoader_GeometryReady: OnSliceGeometryReady(dynamic_cast(from)); - case MessageType_SliceGeometryError: + case MessageType_SliceLoader_GeometryError: { LOG(ERROR) << "Unable to download a volume image"; SlicedVolumeBase::NotifyGeometryError(); }; break; - case MessageType_SliceImageReady: + case MessageType_SliceLoader_ImageReady: { const OrthancSlicesLoader::SliceImageReadyMessage& msg = dynamic_cast(message); OnSliceImageReady(dynamic_cast(from), @@ -219,7 +219,7 @@ msg.image_, msg.effectiveQuality_); }; break; - case MessageType_SliceImageError: + case MessageType_SliceLoader_ImageError: { const OrthancSlicesLoader::SliceImageErrorMessage& msg = dynamic_cast(message); LOG(ERROR) << "Cannot download slice " << msg.sliceIndex_ << " in a volume image"; diff -r c9cf95b49a86 -r 89d02de83c03 Platforms/Generic/WebServiceCommandBase.cpp --- a/Platforms/Generic/WebServiceCommandBase.cpp Tue Aug 21 18:14:22 2018 +0200 +++ b/Platforms/Generic/WebServiceCommandBase.cpp Wed Aug 22 14:59:20 2018 +0200 @@ -38,6 +38,8 @@ headers_(headers), payload_(payload) { + DeclareEmittableMessage(MessageType_HttpRequestError); + DeclareEmittableMessage(MessageType_HttpRequestSuccess); RegisterObserver(callback); } diff -r c9cf95b49a86 -r 89d02de83c03 Resources/CMake/OrthancStoneConfiguration.cmake --- a/Resources/CMake/OrthancStoneConfiguration.cmake Tue Aug 21 18:14:22 2018 +0200 +++ b/Resources/CMake/OrthancStoneConfiguration.cmake Wed Aug 22 14:59:20 2018 +0200 @@ -93,7 +93,9 @@ -DORTHANC_ENABLE_LOGGING_PLUGIN=0 ) - +if (CMAKE_BUILD_TYPE STREQUAL "Debug") + add_definitions(-DCHECK_OBSERVERS_MESSAGES) +endif() ##################################################################### ## Embed the colormaps into the binaries diff -r c9cf95b49a86 -r 89d02de83c03 UnitTestsSources/TestMessageBroker.cpp --- a/UnitTestsSources/TestMessageBroker.cpp Tue Aug 21 18:14:22 2018 +0200 +++ b/UnitTestsSources/TestMessageBroker.cpp Wed Aug 22 14:59:20 2018 +0200 @@ -28,21 +28,74 @@ #include "../Framework/StoneEnumerations.h" -static int globalCounter = 0; -class MyObserver : public OrthancStone::IObserver +static int test1Counter = 0; +static int test2Counter = 0; +class MyFullObserver : public OrthancStone::IObserver +{ + +public: + MyFullObserver(OrthancStone::MessageBroker& broker) + : OrthancStone::IObserver(broker) + { + DeclareHandledMessage(OrthancStone::MessageType_Test1); + DeclareIgnoredMessage(OrthancStone::MessageType_Test2); + } + + + void HandleMessage(const OrthancStone::IObservable& from, const OrthancStone::IMessage& message) { + switch (message.GetType()) + { + case OrthancStone::MessageType_Test1: + test1Counter++; + break; + case OrthancStone::MessageType_Test2: + test2Counter++; + break; + default: + throw OrthancStone::MessageNotDeclaredException(message.GetType()); + } + } + +}; + +class MyPartialObserver : public OrthancStone::IObserver { public: - MyObserver(OrthancStone::MessageBroker& broker) + MyPartialObserver(OrthancStone::MessageBroker& broker) : OrthancStone::IObserver(broker) - {} + { + DeclareHandledMessage(OrthancStone::MessageType_Test1); + // don't declare Test2 on purpose + } void HandleMessage(const OrthancStone::IObservable& from, const OrthancStone::IMessage& message) { - if (message.GetType() == OrthancStone::MessageType_Generic) { - globalCounter++; + switch (message.GetType()) + { + case OrthancStone::MessageType_Test1: + test1Counter++; + break; + case OrthancStone::MessageType_Test2: + test2Counter++; + break; + default: + throw OrthancStone::MessageNotDeclaredException(message.GetType()); } + } +}; + + +class MyObservable : public OrthancStone::IObservable +{ + +public: + MyObservable(OrthancStone::MessageBroker& broker) + : OrthancStone::IObservable(broker) + { + DeclareEmittableMessage(OrthancStone::MessageType_Test1); + DeclareEmittableMessage(OrthancStone::MessageType_Test2); } }; @@ -51,59 +104,55 @@ TEST(MessageBroker, NormalUsage) { OrthancStone::MessageBroker broker; - OrthancStone::IObservable observable(broker); + MyObservable observable(broker); - globalCounter = 0; - - OrthancStone::IMessage genericMessage(OrthancStone::MessageType_Generic); + test1Counter = 0; // no observers have been registered -> nothing shall happen - observable.EmitMessage(genericMessage); + observable.EmitMessage(OrthancStone::IMessage(OrthancStone::MessageType_Test1)); - ASSERT_EQ(0, globalCounter); + ASSERT_EQ(0, test1Counter); // register an observer, check it is called - MyObserver observer(broker); - observable.RegisterObserver(observer); + MyFullObserver fullObserver(broker); + ASSERT_NO_THROW(observable.RegisterObserver(fullObserver)); - observable.EmitMessage(genericMessage); + observable.EmitMessage(OrthancStone::IMessage(OrthancStone::MessageType_Test1)); - ASSERT_EQ(1, globalCounter); + ASSERT_EQ(1, test1Counter); - // check the observer is not called when another message is issued - OrthancStone::IMessage wrongMessage(OrthancStone::MessageType_GeometryReady); - // no observers have been registered - observable.EmitMessage(wrongMessage); + // register an invalid observer, check it raises an exception + MyPartialObserver partialObserver(broker); + ASSERT_THROW(observable.RegisterObserver(partialObserver), OrthancStone::MessageNotDeclaredException); - ASSERT_EQ(1, globalCounter); + // check an exception is thrown when the observable emits an undeclared message + ASSERT_THROW(observable.EmitMessage(OrthancStone::IMessage(OrthancStone::MessageType_LayerSource_GeometryReady)), OrthancStone::MessageNotDeclaredException); // unregister the observer, make sure nothing happens afterwards - observable.UnregisterObserver(observer); - observable.EmitMessage(genericMessage); - ASSERT_EQ(1, globalCounter); + observable.UnregisterObserver(fullObserver); + observable.EmitMessage(OrthancStone::IMessage(OrthancStone::MessageType_Test1)); + ASSERT_EQ(1, test1Counter); } TEST(MessageBroker, DeleteObserverWhileRegistered) { OrthancStone::MessageBroker broker; - OrthancStone::IObservable observable(broker); + MyObservable observable(broker); - globalCounter = 0; - - OrthancStone::IMessage genericMessage(OrthancStone::MessageType_Generic); + test1Counter = 0; { // register an observer, check it is called - MyObserver observer(broker); + MyFullObserver observer(broker); observable.RegisterObserver(observer); - observable.EmitMessage(genericMessage); + observable.EmitMessage(OrthancStone::IMessage(OrthancStone::MessageType_Test1)); - ASSERT_EQ(1, globalCounter); + ASSERT_EQ(1, test1Counter); } // at this point, the observer has been deleted, the handle shall not be called again (and it shall not crash !) - observable.EmitMessage(genericMessage); + observable.EmitMessage(OrthancStone::IMessage(OrthancStone::MessageType_Test1)); - ASSERT_EQ(1, globalCounter); + ASSERT_EQ(1, test1Counter); }