diff --git a/Modules/CppRestSdk/CMakeLists.txt b/Modules/CppRestSdk/CMakeLists.txt index 2d2cff193c..2bf7de274c 100644 --- a/Modules/CppRestSdk/CMakeLists.txt +++ b/Modules/CppRestSdk/CMakeLists.txt @@ -1,14 +1,16 @@ if(MITK_USE_CppRestSdk) MITK_CREATE_MODULE( - DEPENDS MitkCore MitkQtWidgetsExt + DEPENDS MitkCore MitkQtWidgetsExt CppMicroServices PACKAGE_DEPENDS Qt5|Core WARNINGS_NO_ERRORS - #AUTOLOAD_WITH MitkCore + AUTOLOAD_WITH MitkCore ) find_package(OpenSSL REQUIRED) target_link_libraries(${MODULE_TARGET} PRIVATE cpprestsdk::cpprest) target_link_libraries(${MODULE_TARGET} PUBLIC OpenSSL::SSL) + +add_subdirectory(test) endif(MITK_USE_CppRestSdk) diff --git a/Modules/CppRestSdk/include/mitkIRESTManager.h b/Modules/CppRestSdk/include/mitkIRESTManager.h index 041f259ce3..5c7f5eb332 100644 --- a/Modules/CppRestSdk/include/mitkIRESTManager.h +++ b/Modules/CppRestSdk/include/mitkIRESTManager.h @@ -1,89 +1,93 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkIRESTManager_h #define mitkIRESTManager_h -#include "cpprest/uri.h" #include "cpprest/json.h" +#include "cpprest/uri.h" #include #include #include + namespace mitk { + class RESTServerMicroService; class IRESTManager { - - public: virtual ~IRESTManager(); /** - * @brief request type for client requests by calling SendRequest - */ + * @brief request type for client requests by calling SendRequest + */ enum RequestType { get, post, put }; /** * @brief Executes a HTTP request in the mitkRESTClientMicroService class * * @param uri defines the URI the request is send to * @param type the RequestType of the HTTP request (optional) * @param body the body for the request (optional) * @return task to wait for */ virtual pplx::task SendRequest(const web::uri &uri, const RequestType &type = get, const web::json::value &body = NULL, const utility::string_t &filePath = L"") = 0; /** * @brief starts listening for requests if there isn't another observer listening and the port is free * * @param uri defines the URI for which incoming requests should be send to the observer * @param observer the observer which handles the incoming requests */ virtual void ReceiveRequest(const web::uri &uri, IRESTObserver *observer) = 0; /** * @brief Handles incoming requests by notifying the observer which should receive it * * @param uri defines the URI of the request * @param body the body of the request * @return the data which is modified by the notified observer */ virtual web::json::value Handle(const web::uri &uri, web::json::value &body) = 0; /** * @brief Handles the deletion of an observer for all or a specific uri * * @param observer the observer which shouldn't receive requests anymore * @param uri the uri for which the observer doesn't handle requests anymore (optional) */ virtual void HandleDeleteObserver(IRESTObserver *observer, const web::uri &uri = L"") = 0; + + virtual std::map GetM_ServerMap() = 0; + virtual std::map, IRESTObserver *> GetM_Observers() = 0; + }; } // namespace mitk MITK_DECLARE_SERVICE_INTERFACE(mitk::IRESTManager, "org.mitk.IRESTManager") #endif diff --git a/Modules/CppRestSdk/include/mitkIRESTObserver.h b/Modules/CppRestSdk/include/mitkIRESTObserver.h index 256a0da637..098bc279b4 100644 --- a/Modules/CppRestSdk/include/mitkIRESTObserver.h +++ b/Modules/CppRestSdk/include/mitkIRESTObserver.h @@ -1,48 +1,49 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkIRESTObserver_h #define mitkIRESTObserver_h #include "cpprest/json.h" +#include "cpprest/uri.h" #include namespace mitk { class MITKCPPRESTSDK_EXPORT IRESTObserver { public: /** * @brief Deletes an observer and calls HandleDeleteObserver() in RESTManager class * * @see HandleDeleteObserver() */ virtual ~IRESTObserver(); /** * @brief Called if there's an incoming request for the observer, observer implements how to handle request * * @param data the data of the incoming request * @return the modified data */ - virtual web::json::value Notify(web::json::value &data) = 0; + virtual web::json::value Notify(web::json::value &data, const web::uri &uri) = 0; private: }; } #endif // !mitkIRESTObserver diff --git a/Modules/CppRestSdk/include/mitkRESTManager.h b/Modules/CppRestSdk/include/mitkRESTManager.h index 7c9af10cdf..cdbcd0514d 100644 --- a/Modules/CppRestSdk/include/mitkRESTManager.h +++ b/Modules/CppRestSdk/include/mitkRESTManager.h @@ -1,84 +1,87 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkRESTManager_h #define mitkRESTManager_h #include #include #include #include #include #include namespace mitk { class MITKCPPRESTSDK_EXPORT RESTManager : public QObject, public IRESTManager { Q_OBJECT public: RESTManager(); ~RESTManager() override; /** * @brief Executes a HTTP request in the mitkRESTClientMicroService class * * @param uri defines the URI the request is send to * @param type the RequestType of the HTTP request (optional) * @param body the body for the request (optional) * @param filePath the file path to store the request to * @return task to wait for */ pplx::task SendRequest(const web::uri &uri, const RequestType &type = get, const web::json::value &body= NULL, const utility::string_t &filePath = L"") override; /** * @brief starts listening for requests if there isn't another observer listening and the port is free * * @param uri defines the URI for which incoming requests should be send to the observer * @param observer the observer which handles the incoming requests */ void ReceiveRequest(const web::uri &uri, IRESTObserver *observer) override; /** * @brief Handles incoming requests by notifying the observer which should receive it * * @param uri defines the URI of the request * @param body the body of the request * @return the data which is modified by the notified observer */ web::json::value Handle(const web::uri &uri, web::json::value &body) override; /** * @brief Handles the deletion of an observer for all or a specific uri * * @param observer the observer which shouldn't receive requests anymore * @param uri the uri for which the observer doesn't handle requests anymore (optional) */ virtual void HandleDeleteObserver(IRESTObserver *observer, const web::uri &uri) override; + virtual std::map GetM_ServerMap() override; + virtual std::map, IRESTObserver *> GetM_Observers() override; + private: std::map m_ServerMap; // Map with port server pairs std::map m_ServerThreadMap; // Map with threads for servers std::map, IRESTObserver *> m_Observers; // Map with all observers }; } // namespace mitk #endif // !mitkRESTManager_h diff --git a/Modules/CppRestSdk/src/mitkRESTManager.cpp b/Modules/CppRestSdk/src/mitkRESTManager.cpp index fdb04ecd65..400d879090 100644 --- a/Modules/CppRestSdk/src/mitkRESTManager.cpp +++ b/Modules/CppRestSdk/src/mitkRESTManager.cpp @@ -1,203 +1,227 @@ #include "mitkRESTManager.h" #include - +#include mitk::RESTManager::RESTManager() {} mitk::RESTManager::~RESTManager() {} pplx::task mitk::RESTManager::SendRequest(const web::uri &uri, const RequestType &type, const web::json::value &content, const utility::string_t &filePath) { pplx::task answer; auto client = new RESTClientMicroService(); //according to the RequestType, different HTTP requests are made switch (type) { case get: { if (filePath == L"") { //no file path specified, starts a normal get request returning the normal json result answer = client->Get(uri); } else { //file path ist specified, the result of the get request ist stored in this file //and an empty json object is returned answer = client->Get(uri, filePath); } break; } case post: { if (content == NULL) { //warning because normally you won't create an empty ressource MITK_WARN << "Content for put is empty, this will create an empty ressource"; } answer = client->POST(uri, content); break; } break; case put: { if (content == NULL) { //warning because normally you won't empty a ressource MITK_WARN << "Content for put is empty, this will empty the ressource"; } answer = client->PUT(uri,content); break; } } return answer; } void mitk::RESTManager::ReceiveRequest(const web::uri &uri, mitk::IRESTObserver *observer) { // New instance of RESTServerMicroservice in m_ServerMap, key is port of the request int port = uri.port(); // Checking if port is free to add a new Server if (m_ServerMap.count(port) == 0) { // new observer has to be added std::pair key(uri.port(), uri.path()); m_Observers[key] = observer; // testing if entry has been added to observer map utility::string_t uristringt = uri.path(); std::string uristring(uristringt.begin(), uristringt.end()); MITK_INFO <<"[" <moveToThread(m_ServerThreadMap[port]); + if (QCoreApplication::instance() != NULL) + { + // Move server to seperate Thread and create connections between threads + m_ServerThreadMap[port] = new QThread(); + server->moveToThread(m_ServerThreadMap[port]); - connect(m_ServerThreadMap[port], &QThread::finished, server, &QObject::deleteLater); + connect(m_ServerThreadMap[port], &QThread::finished, server, &QObject::deleteLater); - //starting Server - m_ServerThreadMap[port]->start(); - QMetaObject::invokeMethod(server, "OpenListener"); + // starting Server + m_ServerThreadMap[port]->start(); + QMetaObject::invokeMethod(server, "OpenListener"); + } + else + { + server->OpenListener(); + } utility::string_t host = uri.authority().to_string(); std::string hoststring(host.begin(), host.end()); MITK_INFO << "new server" << hoststring << " at port" << port; } // If there is already a server under this port else { // Same host, means new observer but not a new server instance if (m_ServerMap[port]->GetUri() == uri.authority()) { // new observer has to be added std::pair key(uri.port(), uri.path()); //only add a new observer if there isn't already an observer for this uri if (m_Observers.count(key) == 0) { m_Observers[key] = observer; // testing if entry has been added to map utility::string_t uristringt = uri.path(); std::string uristring(uristringt.begin(), uristringt.end()); MITK_INFO << "[" << uri.port() << ", " << uristring<< "] : Number of elements in map: " << m_Observers.count(key); // info output MITK_INFO << "started listening, no new server instance has been created"; } else { MITK_ERROR << "Threre is already a observer handeling this data"; } } // Error, since another server can't be added under this port else { MITK_ERROR << "There is already another server listening under this port"; } } } web::json::value mitk::RESTManager::Handle(const web::uri &uri, web::json::value &body) { // Checking if there is an observer for the port and path std::pair key(uri.port(), uri.path()); if (m_Observers.count(key) != 0) { MITK_INFO << "Manager: Data send to observer"; - return m_Observers[key]->Notify(body); + return m_Observers[key]->Notify(body,uri); } //No observer under this port, return null which results in status code 404 (s. RESTServerMicroService) else { MITK_WARN << "No Observer can handle the data"; return NULL; } } void mitk::RESTManager::HandleDeleteObserver(IRESTObserver *observer, const web::uri &uri= L"") { for (auto it = m_Observers.begin(); it != m_Observers.end();) { mitk::IRESTObserver *obsMap = it->second; // Check wether observer is at this place in map if (obsMap == observer) { //Check wether it is the right uri to be deleted if (uri==L""||it->first.second == uri.path()) { // if yes // 1. store port and path in a temporary variable // (path is only needed to create a key for info output) int port = it->first.first; utility::string_t path = it->first.second; std::pair key(port, path); MITK_INFO << "Number of elements at key [ " << port << ", " << std::string(key.second.begin(), key.second.end()) << "]: " << m_Observers.count(key); // 2. delete map entry it = m_Observers.erase(it); MITK_INFO << "Number of elements at key [ " << port << ", " << std::string(key.second.begin(), key.second.end()) << "]: " << m_Observers.count(key); // 3. check, if there is another observer under this port in observer map (with bool flag) bool noObserverForPort = true; for (auto o : m_Observers) { if (o.first.first == port) { // there still exists an observer for this port noObserverForPort = false; } } if (noObserverForPort) { // there isn't an observer at this port, delete m_ServerMap entry for this port // close listener - QMetaObject::invokeMethod(m_ServerMap[port], "CloseListener"); - // end thread - m_ServerThreadMap[port]->quit(); - m_ServerThreadMap[port]->wait(); + if (QCoreApplication::instance() != NULL) + { + QMetaObject::invokeMethod(m_ServerMap[port], "CloseListener"); + // end thread + m_ServerThreadMap[port]->quit(); + m_ServerThreadMap[port]->wait(); + } + else + { + m_ServerMap[port]->CloseListener(); + } // delete server from map m_ServerMap.erase(port); } } else { ++it; } } else { ++it; } } } +std::map mitk::RESTManager::GetM_ServerMap() +{ + return m_ServerMap; +} + +std::map, mitk::IRESTObserver *> mitk::RESTManager::GetM_Observers() +{ + return m_Observers; +} + diff --git a/Modules/CppRestSdk/test/CMakeLists.txt b/Modules/CppRestSdk/test/CMakeLists.txt new file mode 100644 index 0000000000..2d5e45bb88 --- /dev/null +++ b/Modules/CppRestSdk/test/CMakeLists.txt @@ -0,0 +1,2 @@ +MITK_CREATE_MODULE_TESTS() + diff --git a/Modules/CppRestSdk/test/files.cmake b/Modules/CppRestSdk/test/files.cmake new file mode 100644 index 0000000000..7299b4bcce --- /dev/null +++ b/Modules/CppRestSdk/test/files.cmake @@ -0,0 +1,4 @@ +set(MODULE_TESTS + mitkRESTClientTest.cpp + mitkRESTServerTest.cpp +) \ No newline at end of file diff --git a/Modules/CppRestSdk/test/mitkRESTClientTest.cpp b/Modules/CppRestSdk/test/mitkRESTClientTest.cpp new file mode 100644 index 0000000000..9554a63880 --- /dev/null +++ b/Modules/CppRestSdk/test/mitkRESTClientTest.cpp @@ -0,0 +1,281 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +// Testing +#include "mitkTestFixture.h" +#include "mitkTestingMacros.h" + +// MITK includes +#include "mitkRESTClientMicroService.h" + +// VTK includes +#include + +#include "mitkIRESTManager.h" +#include +#include +#include +#include +#include +#include + +#include +#include +class mitkRESTClientTestSuite : public mitk::TestFixture, mitk::IRESTObserver +{ + CPPUNIT_TEST_SUITE(mitkRESTClientTestSuite); + + MITK_TEST(GetRequestValidURI_ReturnsExpectedJSON); + MITK_TEST(MultipleGetRequestValidURI_AllTasksFinish); + MITK_TEST(PutRequestValidURI_ReturnsExpectedJSON); + MITK_TEST(PostRequestValidURI_ReturnsExpectedJSON); + MITK_TEST(GetRequestInvalidURI_ThrowsException); + MITK_TEST(PutRequestInvalidURI_ThrowsException); + MITK_TEST(PostRequestInvalidURI_ThrowsException); + CPPUNIT_TEST_SUITE_END(); + +public: + mitk::IRESTManager *m_Service; + + web::json::value Notify(web::json::value &data, const web::uri &uri) override + { + MITK_INFO << "Observer: Data in observer"; + data[L"userId"] = web::json::value(1); + data[L"id"] = web::json::value(1); + data[L"title"] = web::json::value(U("this is a title")); + data[L"body"] = web::json::value(U("this is a body")); + return data; + } + + /** + * @brief Setup Always call this method before each Test-case to ensure correct and new intialization of the used + * members for a new test case. (If the members are not used in a test, the method does not need to be called). + */ + void setUp() override + { + us::ServiceReference serviceRef = + us::GetModuleContext()->GetServiceReference(); + if (serviceRef) + { + m_Service = us::GetModuleContext()->GetService(serviceRef); + } + if (m_Service) + { + m_Service->ReceiveRequest(L"http://localhost:8080/test", this); + } + } + + void tearDown() override + { + if (m_Service) + { + m_Service->HandleDeleteObserver(this); + } + } + + void GetRequestValidURI_ReturnsExpectedJSON() + { + web::json::value *result = new web::json::value(); + web::json::value data; + data[L"userId"] = web::json::value(1); + data[L"id"] = web::json::value(1); + data[L"title"] = web::json::value(U("this is a title")); + data[L"body"] = web::json::value(U("this is a body")); + if (m_Service) + { + m_Service->SendRequest(L"http://localhost:8080/test") + .then([=](pplx::task resultTask) { + try + { + *result = resultTask.get(); + } + catch (const mitk::Exception &exception) + { + MITK_ERROR << exception.what(); + return; + } + }) + .wait(); + } + CPPUNIT_ASSERT_MESSAGE("Result is the expected JSON value", *result == data); + } + + void MultipleGetRequestValidURI_AllTasksFinish() + { + int *count = new int(0); + if (m_Service) + { + // Create multiple tasks e.g. as shown below + std::vector> tasks; + for (int i = 0; i < 20; i++) + { + pplx::task singleTask = + m_Service->SendRequest(L"http://localhost:8080/test") + .then([=](pplx::task resultTask) { + // Do something when a single task is done + try + { + resultTask.get(); + *count +=1; + } + catch (const mitk::Exception &exception) + { + MITK_ERROR << exception.what(); + return; + } + }); + tasks.push_back(singleTask); + } + // Create a joinTask which includes all tasks you've created + auto joinTask = pplx::when_all(begin(tasks), end(tasks)); + // Run asynchonously + joinTask.then([=](pplx::task resultTask) { + // Do something when all tasks are finished + try + { + resultTask.get(); + *count += 1; + } + catch (const mitk::Exception &exception) + { + MITK_ERROR << exception.what(); + return; + } + }).wait(); + } + CPPUNIT_ASSERT_MESSAGE("Multiple Requests", *count ==21); + } + + void PutRequestValidURI_ReturnsExpectedJSON() + { + // optional: link might get invalid or content is changed + web::json::value *result = new web::json::value(); + web::json::value data; + if (m_Service) + { + data[L"userId"] = web::json::value(1); + data[L"id"] = web::json::value(1); + data[L"title"] = web::json::value(U("this is a changed title")); + data[L"body"] = web::json::value(U("and the body is changed as well")); + m_Service + ->SendRequest(L"https://jsonplaceholder.typicode.com/posts/1", mitk::IRESTManager::RequestType::put, data) + .then([=](pplx::task resultTask) { + try + { + *result = resultTask.get(); + } + catch (const mitk::Exception &exception) + { + MITK_ERROR << exception.what(); + return; + } + }) + .wait(); + } + CPPUNIT_ASSERT_MESSAGE( + "Result is the expected JSON value, check if the link is still valid since this is an optional test", + *result == data); + } + + void PostRequestValidURI_ReturnsExpectedJSON() + { + // optional: link might get invalid or content is changed + web::json::value *result = new web::json::value(); + web::json::value data; + if (m_Service) + { + data[L"userId"] = web::json::value(1); + data[L"title"] = web::json::value(U("this is a new title")); + data[L"body"] = web::json::value(U("this is a new body")); + m_Service->SendRequest(L"https://jsonplaceholder.typicode.com/posts", mitk::IRESTManager::RequestType::post, data) + .then([=](pplx::task resultTask) { + try + { + *result = resultTask.get(); + } + catch (const mitk::Exception &exception) + { + MITK_ERROR << exception.what(); + return; + } + }) + .wait(); + } + data[L"id"] = web::json::value(101); + CPPUNIT_ASSERT_MESSAGE( + "Result is the expected JSON value, check if the link is still valid since this is an optional test", + *result == data); + } + + void GetException() + { + //Method which makes a get request to an invalid uri + web::json::value *result = new web::json::value(); + if (m_Service) + { + m_Service->SendRequest(L"http://localhost:1234/invalid") + .then([=](pplx::task resultTask) { *result = resultTask.get(); }) + .wait(); + } + } + void GetRequestInvalidURI_ThrowsException() { CPPUNIT_ASSERT_THROW(GetException(), mitk::Exception); } + + void PutException() + { + //Method which makes a put request to an invalid uri + web::json::value *result = new web::json::value(); + web::json::value data; + if (m_Service) + { + data[L"userId"] = web::json::value(1); + data[L"id"] = web::json::value(1); + data[L"title"] = web::json::value(U("this is a changed title")); + data[L"body"] = web::json::value(U("and the body is changed as well")); + m_Service->SendRequest(L"http://localhost:1234/invalid", mitk::IRESTManager::RequestType::put, data) + .then([=](pplx::task resultTask) { + *result = resultTask.get();}) + .wait(); + } + } + void PutRequestInvalidURI_ThrowsException() + { + CPPUNIT_ASSERT_THROW(PutException(), mitk::Exception); + } + + void PostException() + { + //Method which makes a post request to an invalid uri + web::json::value *result = new web::json::value(); + web::json::value data; + if (m_Service) + { + data[L"userId"] = web::json::value(1); + data[L"title"] = web::json::value(U("this is a new title")); + data[L"body"] = web::json::value(U("this is a new body")); + m_Service->SendRequest(L"http://localhost:1234/invalid", mitk::IRESTManager::RequestType::post, data) + .then([=](pplx::task resultTask) { + *result = resultTask.get(); + }) + .wait(); + } + } + void PostRequestInvalidURI_ThrowsException() + { + CPPUNIT_ASSERT_THROW(PostException(), mitk::Exception); + } +}; + +MITK_TEST_SUITE_REGISTRATION(mitkRESTClient) \ No newline at end of file diff --git a/Modules/CppRestSdk/test/mitkRESTServerTest.cpp b/Modules/CppRestSdk/test/mitkRESTServerTest.cpp new file mode 100644 index 0000000000..264e9c6439 --- /dev/null +++ b/Modules/CppRestSdk/test/mitkRESTServerTest.cpp @@ -0,0 +1,230 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +// Testing +#include "mitkTestFixture.h" +#include "mitkTestingMacros.h" + +// MITK includes +#include "mitkRESTServerMicroService.h" + +// VTK includes +#include + +class mitkRESTServerTestSuite : public mitk::TestFixture, mitk::IRESTObserver +{ + CPPUNIT_TEST_SUITE(mitkRESTServerTestSuite); + + MITK_TEST(OpenListener_Succeed); + MITK_TEST(TwoListenerSameHostSamePort_OnlyOneOpened); + MITK_TEST(CloseListener_Succeed); + MITK_TEST(OpenMultipleListenerCloseOne_Succeed); + MITK_TEST(OpenMultipleListenerCloseAll_Succeed); + MITK_TEST(OpenListenerGetRequestSamePath_ReturnExpectedJSON); + MITK_TEST(OpenListenerGetRequestDifferentPath_ReturnNotFound); + MITK_TEST(OpenListenerCloseAndReopen_Succeed); + CPPUNIT_TEST_SUITE_END(); + +public: + mitk::IRESTManager *m_Service; + web::json::value m_Data; + + web::json::value Notify(web::json::value &data, const web::uri &uri) override + { + MITK_INFO << "Observer: Data in observer"; + data[L"userId"] = web::json::value(1); + data[L"id"] = web::json::value(1); + data[L"title"] = web::json::value(U("this is a title")); + data[L"body"] = web::json::value(U("this is a body")); + return data; + } + + /** + * @brief Setup Always call this method before each Test-case to ensure correct and new intialization of the used + * members for a new test case. (If the members are not used in a test, the method does not need to be called). + */ + void setUp() override + { + m_Data[L"userId"] = web::json::value(1); + m_Data[L"id"] = web::json::value(1); + m_Data[L"title"] = web::json::value(U("this is a title")); + m_Data[L"body"] = web::json::value(U("this is a body")); + us::ServiceReference serviceRef = + us::GetModuleContext()->GetServiceReference(); + if (serviceRef) + { + m_Service = us::GetModuleContext()->GetService(serviceRef); + } + } + + void tearDown() override { m_Service->HandleDeleteObserver(this); } + + void OpenListener_Succeed() + { + if (m_Service) + { + m_Service->ReceiveRequest(L"http://localhost:8080/test", this); + } + CPPUNIT_ASSERT_MESSAGE("Open one listener, observer map size is one", m_Service->GetM_Observers().size() == 1); + CPPUNIT_ASSERT_MESSAGE("Open one listener, server map size is one", m_Service->GetM_ServerMap().size() == 1); + } + + void TwoListenerSameHostSamePort_OnlyOneOpened() + { + if (m_Service) + { + m_Service->ReceiveRequest(L"http://localhost:8080/test", this); + m_Service->ReceiveRequest(L"http://localhost:8080/example", this); + } + CPPUNIT_ASSERT_MESSAGE("Open two listener with a different path,same host, same port, observer map size is two", + m_Service->GetM_Observers().size() == 2); + CPPUNIT_ASSERT_MESSAGE("Open two listener with a different path,same host, same port, server map size is one", + m_Service->GetM_ServerMap().size() == 1); + } + + void CloseListener_Succeed() + { + if (m_Service) + { + m_Service->ReceiveRequest(L"http://localhost:8080/test", this); + } + CPPUNIT_ASSERT_MESSAGE("Open one listener, observer map size is one", m_Service->GetM_Observers().size() == 1); + CPPUNIT_ASSERT_MESSAGE("Open one listener, server map size is one", m_Service->GetM_ServerMap().size() == 1); + if (m_Service) + { + m_Service->HandleDeleteObserver(this); + } + CPPUNIT_ASSERT_MESSAGE("Closed listener, observer map is empty", m_Service->GetM_Observers().size() == 0); + CPPUNIT_ASSERT_MESSAGE("Closed listener, server map is empty", m_Service->GetM_ServerMap().size() == 0); + } + + void OpenMultipleListenerCloseOne_Succeed() + { + if (m_Service) + { + m_Service->ReceiveRequest(L"http://localhost:8080/test", this); + m_Service->ReceiveRequest(L"http://localhost:8090/example", this); + } + CPPUNIT_ASSERT_MESSAGE("Open two listener, observer map size is two", m_Service->GetM_Observers().size() == 2); + CPPUNIT_ASSERT_MESSAGE("Open two listener, server map size is two", m_Service->GetM_ServerMap().size() == 2); + if (m_Service) + { + m_Service->HandleDeleteObserver(this, L"http://localhost:8080/test"); + } + CPPUNIT_ASSERT_MESSAGE("Closed one of two listeners, observer map is size is one", + m_Service->GetM_Observers().size() == 1); + CPPUNIT_ASSERT_MESSAGE("Closed one of two listener, server map size is one", + m_Service->GetM_ServerMap().size() == 1); + } + + void OpenMultipleListenerCloseAll_Succeed() + { + if (m_Service) + { + m_Service->ReceiveRequest(L"http://localhost:8080/test", this); + m_Service->ReceiveRequest(L"http://localhost:8090/example", this); + } + CPPUNIT_ASSERT_MESSAGE("Open two listener, observer map size is two", m_Service->GetM_Observers().size() == 2); + CPPUNIT_ASSERT_MESSAGE("Open two listener, server map size is two", m_Service->GetM_ServerMap().size() == 2); + if (m_Service) + { + m_Service->HandleDeleteObserver(this); + } + CPPUNIT_ASSERT_MESSAGE("Closed all listeners, observer map is empty", m_Service->GetM_Observers().size() == 0); + CPPUNIT_ASSERT_MESSAGE("Closed all listeners, server map is empty", m_Service->GetM_ServerMap().size() == 0); + } + + void OpenListenerGetRequestSamePath_ReturnExpectedJSON() + { + if (m_Service) + { + m_Service->ReceiveRequest(L"http://localhost:8080/test", this); + } + web::json::value *result = new web::json::value(); + web::json::value data; + data[L"userId"] = web::json::value(1); + data[L"id"] = web::json::value(1); + data[L"title"] = web::json::value(U("this is a title")); + data[L"body"] = web::json::value(U("this is a body")); + + if (m_Service) + { + m_Service->SendRequest(L"http://localhost:8080/test") + .then([=](pplx::task resultTask) { + try + { + *result = resultTask.get(); + } + catch (const mitk::Exception &exception) + { + MITK_ERROR << exception.what(); + return; + } + }) + .wait(); + } + CPPUNIT_ASSERT_MESSAGE("Opened listener and send request to same uri, returned expected JSON", *result == data); + } + + void RequestToDifferentPathNotFound() + { + if (m_Service) + { + m_Service->ReceiveRequest(L"http://localhost:8080/test", this); + } + web::json::value *result = new web::json::value(); + web::json::value data; + data[L"userId"] = web::json::value(1); + data[L"id"] = web::json::value(1); + data[L"title"] = web::json::value(U("this is a title")); + data[L"body"] = web::json::value(U("this is a body")); + + if (m_Service) + { + m_Service->SendRequest(L"http://localhost:8080/example") + .then([=](pplx::task resultTask) { *result = resultTask.get(); }) + .wait(); + } + } + void OpenListenerGetRequestDifferentPath_ReturnNotFound() + { + CPPUNIT_ASSERT_THROW(RequestToDifferentPathNotFound(), mitk::Exception); + } + + void OpenListenerCloseAndReopen_Succeed() + { + if (m_Service) + { + m_Service->ReceiveRequest(L"http://localhost:8080/test", this); + } + CPPUNIT_ASSERT_MESSAGE("Open one listener, observer map size is one", m_Service->GetM_Observers().size() == 1); + CPPUNIT_ASSERT_MESSAGE("Open one listener, server map size is one", m_Service->GetM_ServerMap().size() == 1); + if (m_Service) + { + m_Service->HandleDeleteObserver(this); + } + CPPUNIT_ASSERT_MESSAGE("Closed listener, observer map is empty", m_Service->GetM_Observers().size() == 0); + CPPUNIT_ASSERT_MESSAGE("Closed listener, server map is empty", m_Service->GetM_ServerMap().size() == 0); + if (m_Service) + { + m_Service->ReceiveRequest(L"http://localhost:8080/test", this); + } + CPPUNIT_ASSERT_MESSAGE("Reopened listener, observer map size is one", m_Service->GetM_Observers().size() == 1); + CPPUNIT_ASSERT_MESSAGE("Reopened listener, server map size is one", m_Service->GetM_ServerMap().size() == 1); + } +}; + +MITK_TEST_SUITE_REGISTRATION(mitkRESTServer) \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.client/files.cmake b/Plugins/org.mitk.gui.qt.client/files.cmake index 70a828e79f..a2ec7a0c46 100644 --- a/Plugins/org.mitk.gui.qt.client/files.cmake +++ b/Plugins/org.mitk.gui.qt.client/files.cmake @@ -1,21 +1,21 @@ set(CPP_FILES src/internal/PluginActivator.cpp src/internal/QmitkClientView.cpp ) set(UI_FILES src/internal/QmitkClientView.ui ) set(MOC_H_FILES src/internal/PluginActivator.h src/internal/QmitkClientView.h ) set(CACHED_RESOURCE_FILES - resources/ClientIcon.png + resources/ClientIcon.svg plugin.xml ) set(QRC_FILES ) diff --git a/Plugins/org.mitk.gui.qt.client/plugin.xml b/Plugins/org.mitk.gui.qt.client/plugin.xml index 8a7740c52f..849355de07 100644 --- a/Plugins/org.mitk.gui.qt.client/plugin.xml +++ b/Plugins/org.mitk.gui.qt.client/plugin.xml @@ -1,10 +1,10 @@ + icon="resources/ClientIcon.svg" /> diff --git a/Plugins/org.mitk.gui.qt.client/resources/ClientIcon.svg b/Plugins/org.mitk.gui.qt.client/resources/ClientIcon.svg new file mode 100644 index 0000000000..cc8f386bb1 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.client/resources/ClientIcon.svg @@ -0,0 +1,111 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.thread/files.cmake b/Plugins/org.mitk.gui.qt.thread/files.cmake index 505c01fec8..283289a43d 100644 --- a/Plugins/org.mitk.gui.qt.thread/files.cmake +++ b/Plugins/org.mitk.gui.qt.thread/files.cmake @@ -1,21 +1,21 @@ set(CPP_FILES src/internal/PluginActivator.cpp src/internal/QmitkThreadView.cpp ) set(UI_FILES src/internal/QmitkThreadView.ui ) set(MOC_H_FILES src/internal/PluginActivator.h src/internal/QmitkThreadView.h ) set(CACHED_RESOURCE_FILES - resources/ThreadIcon.png + resources/ThreadIcon.svg plugin.xml ) set(QRC_FILES ) diff --git a/Plugins/org.mitk.gui.qt.thread/plugin.xml b/Plugins/org.mitk.gui.qt.thread/plugin.xml index a0aa4d1217..aa003e009e 100644 --- a/Plugins/org.mitk.gui.qt.thread/plugin.xml +++ b/Plugins/org.mitk.gui.qt.thread/plugin.xml @@ -1,10 +1,10 @@ + icon="resources/ThreadIcon.svg" /> diff --git a/Plugins/org.mitk.gui.qt.thread/resources/ThreadIcon.svg b/Plugins/org.mitk.gui.qt.thread/resources/ThreadIcon.svg new file mode 100644 index 0000000000..60961ebd98 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.thread/resources/ThreadIcon.svg @@ -0,0 +1,111 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.thread/src/internal/QmitkThreadView.cpp b/Plugins/org.mitk.gui.qt.thread/src/internal/QmitkThreadView.cpp index 12724b2ca3..53011b8c78 100644 --- a/Plugins/org.mitk.gui.qt.thread/src/internal/QmitkThreadView.cpp +++ b/Plugins/org.mitk.gui.qt.thread/src/internal/QmitkThreadView.cpp @@ -1,146 +1,146 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkThreadView.h" #include #include #include #include #include #include #include const std::string QmitkThreadView::VIEW_ID = "org.mitk.views.threadview"; QmitkThreadView::QmitkThreadView() : m_Ui(new Ui::QmitkThreadView) { } -web::json::value QmitkThreadView::Notify(web::json::value &data) +web::json::value QmitkThreadView::Notify(web::json::value &data, const web::uri &uri) { MITK_INFO << "Observer: Data in observer"; return data.at(U("key 1")); } QmitkThreadView::~QmitkThreadView() { delete m_Ui; } void QmitkThreadView::CreateQtPartControl(QWidget* parent) { m_Ui->setupUi(parent); connect(m_Ui->stopAllPushButton, &QPushButton::clicked, this, &QmitkThreadView::OnStopAllButtonClicked); connect(m_Ui->testListenCheckBox, &QCheckBox::clicked, this, &QmitkThreadView::OnTestListenCheckBoxClicked); connect(m_Ui->exampleListenCheckBox, &QCheckBox::clicked, this, &QmitkThreadView::OnExampleListenCheckBoxClicked); connect(m_Ui->port8090CheckBox, &QCheckBox::clicked, this, &QmitkThreadView::OnPort8090ListenCheckBoxClicked); connect(m_Ui->stopAllPushButton, &QPushButton::clicked, this, &QmitkThreadView::OnStopAllButtonClicked); } void QmitkThreadView::SetFocus() { } void QmitkThreadView::StartListening(web::uri uri) { us::ModuleContext *context = us::ModuleRegistry::GetModule(1)->GetModuleContext(); auto managerRef = context->GetServiceReference(); if (managerRef) { auto managerService = context->GetService(managerRef); if (managerService) { managerService->ReceiveRequest(uri, this); } } } void QmitkThreadView::StopListening(web::uri uri) { us::ModuleContext *context = us::ModuleRegistry::GetModule(1)->GetModuleContext(); auto managerRef = context->GetServiceReference(); if (managerRef) { auto managerService = context->GetService(managerRef); if (managerService) { managerService->HandleDeleteObserver(this,uri); } } } void QmitkThreadView::OnStopAllButtonClicked() { us::ModuleContext *context = us::ModuleRegistry::GetModule(1)->GetModuleContext(); auto managerRef = context->GetServiceReference(); if (managerRef) { auto managerService = context->GetService(managerRef); if (managerService) { managerService->HandleDeleteObserver(this); } } m_Ui->testListenCheckBox->setChecked(false); m_Ui->exampleListenCheckBox->setChecked(false); m_Ui->port8090CheckBox->setChecked(false); } void QmitkThreadView::OnTestListenCheckBoxClicked() { if (m_Ui->testListenCheckBox->isChecked()) { StartListening(L"http://localhost:8080/test"); } else { StopListening(L"http://localhost:8080/test"); } } void QmitkThreadView::OnExampleListenCheckBoxClicked() { if (m_Ui->exampleListenCheckBox->isChecked()) { StartListening(L"http://localhost:8080/example"); } else { StopListening(L"http://localhost:8080/example"); } } void QmitkThreadView::OnPort8090ListenCheckBoxClicked() { if (m_Ui->port8090CheckBox->isChecked()) { StartListening(L"http://localhost:8090"); } else { StopListening(L"http://localhost:8090"); } } diff --git a/Plugins/org.mitk.gui.qt.thread/src/internal/QmitkThreadView.h b/Plugins/org.mitk.gui.qt.thread/src/internal/QmitkThreadView.h index 06ceaaf9fb..9136b3a5e4 100644 --- a/Plugins/org.mitk.gui.qt.thread/src/internal/QmitkThreadView.h +++ b/Plugins/org.mitk.gui.qt.thread/src/internal/QmitkThreadView.h @@ -1,60 +1,60 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QmitkThreadView_h #define QmitkThreadView_h #include #include #include "cpprest/uri.h" namespace Ui { class QmitkThreadView; } namespace mitk { class RESTManager; } class QmitkThreadView : public QmitkAbstractView, public mitk::IRESTObserver { Q_OBJECT public: static const std::string VIEW_ID; QmitkThreadView(); ~QmitkThreadView() override; void CreateQtPartControl(QWidget *parent) override; - web::json::value Notify(web::json::value &data) override; + web::json::value Notify(web::json::value &data, const web::uri &uri) override; private slots: void OnStopAllButtonClicked(); void OnTestListenCheckBoxClicked(); void OnExampleListenCheckBoxClicked(); void OnPort8090ListenCheckBoxClicked(); private: void SetFocus() override; void StartListening(web::uri); void StopListening(web::uri); Ui::QmitkThreadView *m_Ui; }; #endif