diff --git a/Modules/CppRestSdk/src/mitkRESTManager.cpp b/Modules/CppRestSdk/src/mitkRESTManager.cpp index 400d879090..9fee438abf 100644 --- a/Modules/CppRestSdk/src/mitkRESTManager.cpp +++ b/Modules/CppRestSdk/src/mitkRESTManager.cpp @@ -1,227 +1,228 @@ #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]); connect(m_ServerThreadMap[port], &QThread::finished, server, &QObject::deleteLater); // 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,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 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(); + m_ServerMap[port]->~RESTServerMicroService(); } // 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/mitkRESTServerTest.cpp b/Modules/CppRestSdk/test/mitkRESTServerTest.cpp index 264e9c6439..e7f6e43cc3 100644 --- a/Modules/CppRestSdk/test/mitkRESTServerTest.cpp +++ b/Modules/CppRestSdk/test/mitkRESTServerTest.cpp @@ -1,230 +1,259 @@ /*=================================================================== 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(CloseListener_NoRequestPossible); 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 RequestToClosedListener() + { + web::json::value *result = new web::json::value(); + if (m_Service) + { + m_Service->SendRequest(L"http://localhost:8080/test") + .then([=](pplx::task resultTask) { *result = resultTask.get(); }) + .wait(); + } + } + void CloseListener_NoRequestPossible() + { + 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); + + CPPUNIT_ASSERT_THROW(RequestToClosedListener(), mitk::Exception); + } + 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