diff --git a/Modules/CppRestSdk/include/mitkIRESTManager.h b/Modules/CppRestSdk/include/mitkIRESTManager.h index 7d72bc6c2b..041f259ce3 100644 --- a/Modules/CppRestSdk/include/mitkIRESTManager.h +++ b/Modules/CppRestSdk/include/mitkIRESTManager.h @@ -1,84 +1,89 @@ /*=================================================================== 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 #include #include + namespace mitk { class IRESTManager { public: virtual ~IRESTManager(); + /** + * @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(web::uri uri, - RequestType type = get, - web::json::value body = NULL, - utility::string_t filePath = L"") = 0; + 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(web::uri uri, IRESTObserver *observer) = 0; + 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(web::uri uri, web::json::value body) = 0; + 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, web::uri uri = L"") = 0; + virtual void HandleDeleteObserver(IRESTObserver *observer, const web::uri &uri = L"") = 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 097c948e6c..256a0da637 100644 --- a/Modules/CppRestSdk/include/mitkIRESTObserver.h +++ b/Modules/CppRestSdk/include/mitkIRESTObserver.h @@ -1,48 +1,48 @@ /*=================================================================== 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 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) = 0; private: }; } #endif // !mitkIRESTObserver diff --git a/Modules/CppRestSdk/include/mitkRESTClientMicroService.h b/Modules/CppRestSdk/include/mitkRESTClientMicroService.h index 5e61c169ab..c34a9f7ac4 100644 --- a/Modules/CppRestSdk/include/mitkRESTClientMicroService.h +++ b/Modules/CppRestSdk/include/mitkRESTClientMicroService.h @@ -1,87 +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 mitkRESTClientMicroService_h #define mitkRESTClientMicroService_h #include "cpprest/asyncrt_utils.h" #include "cpprest/containerstream.h" #include "cpprest/filestream.h" #include "cpprest/http_client.h" #include "cpprest/json.h" #include "cpprest/producerconsumerstream.h" #include "cpprest/uri.h" #include "MitkCppRestSdkExports.h" #include #include #include #include typedef web::http::client::http_client MitkClient; typedef web::http::http_request MitkRequest; typedef web::http::http_response MitkResponse; typedef web::http::methods MitkRESTMethods; typedef web::http::uri_builder MitkUriBuilder; typedef web::http::status_codes MitkRestStatusCodes; typedef web::json::json_exception MitkJsonException; namespace mitk { class RESTClientMicroService { public: RESTClientMicroService(); ~RESTClientMicroService(); /** *@brief Executes a HTTP GET request with the given uri and returns a task waiting for a json object * * @param uri the URI resulting the target of the HTTP request - * @return task with to wait for with resulting json object + * @return task to wait for with resulting json object */ - pplx::task Get(web::uri uri); + pplx::task Get(const web::uri &uri); /** *@brief Executes a HTTP GET request with the given uri and and stores the byte stream in a file given by the filePath * * @param uri the URI resulting the target of the HTTP request - * @return task with to wait for + * @return task to wait for returning an empty json object */ - pplx::task Get(web::uri uri, utility::string_t filePath); + pplx::task Get(const web::uri &uri, const utility::string_t &filePath); /** * @brief Executes a HTTP PUT request with given uri and the content given as json * * @param uri defines the URI resulting the target of the HTTP request * @param content the content as json value which should be the body of the request and thus the content of the * created resources * @return task to wait for with resulting json object */ - pplx::task PUT(web::uri uri, web::json::value content); + pplx::task PUT(const web::uri &uri, const web::json::value &content); /** * @brief Executes a HTTP POST request with given uri and the content given as json * * @param uri defines the URI resulting the target of the HTTP request * @param content the content as json value which should be the body of the request and thus the content of the created resource * @return task to wait for with resulting json object */ - pplx::task POST(web::uri uri, web::json::value content); + pplx::task POST(const web::uri &uri, const web::json::value &content); }; } // namespace mitk #endif // !mitkRESTClientMicroService_h diff --git a/Modules/CppRestSdk/include/mitkRESTManager.h b/Modules/CppRestSdk/include/mitkRESTManager.h index df7dc38e09..272928f8a3 100644 --- a/Modules/CppRestSdk/include/mitkRESTManager.h +++ b/Modules/CppRestSdk/include/mitkRESTManager.h @@ -1,85 +1,85 @@ /*=================================================================== 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 #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(web::uri uri, - RequestType type = get, - web::json::value = NULL, - utility::string_t filePath = L"") override; + 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(web::uri uri, IRESTObserver *observer) override; + 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(web::uri uri, web::json::value body) override; + 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, web::uri uri) override; + virtual void HandleDeleteObserver(IRESTObserver *observer, const web::uri &uri) override; private: - std::map m_ClientMap; // Map with port client pairs std::map m_ServerMap; // Map with port server pairs std::map m_ServerThreadMap; // Map with threads for servers - std::map, IRESTObserver *> m_Observer; // Map with all observers + std::map, IRESTObserver *> m_Observers; // Map with all observers }; } // namespace mitk #endif // !mitkRESTManager_h diff --git a/Modules/CppRestSdk/src/mitkRESTClientMicroService.cpp b/Modules/CppRestSdk/src/mitkRESTClientMicroService.cpp index b40f0a6de4..af10fd205b 100644 --- a/Modules/CppRestSdk/src/mitkRESTClientMicroService.cpp +++ b/Modules/CppRestSdk/src/mitkRESTClientMicroService.cpp @@ -1,168 +1,210 @@ #include "mitkRESTClientMicroService.h" #include "mitkRESTUtil.h" #include mitk::RESTClientMicroService::RESTClientMicroService() {} mitk::RESTClientMicroService::~RESTClientMicroService() {} -pplx::task mitk::RESTClientMicroService::Get(web::uri uri) +pplx::task mitk::RESTClientMicroService::Get(const web::uri &uri) { + //Create new HTTP client MitkClient *client = new MitkClient(uri); MITK_INFO << "Calling GET with " << utility::conversions::to_utf8string(uri.path()) << " on client " << mitk::RESTUtil::convertToUtf8(uri.authority().to_string()); + //create get request MitkRequest getRequest(MitkRESTMethods::GET); + //make request return client->request(getRequest).then([=](pplx::task responseTask) { try { + //get response of the request MitkResponse response = responseTask.get(); auto status = response.status_code(); MITK_INFO << " status: " << status; if (status != MitkRestStatusCodes::OK) { + //throw if something went wrong (e.g. invalid uri) + //this exception can be handled by client mitkThrow() << "response was not OK"; } try { + //parse content type to application/json if it isn't already + //this is important if the content type is e.g. application/dicom+json utility::string_t requestContentType = response.headers().content_type(); if (requestContentType != L"application/json") { response.headers().set_content_type(L"application/json"); } + //return json answer return response.extract_json().get(); } catch (...) { mitkThrow() << "extracting json went wrong"; } } catch (...) { mitkThrow() << "getting response went wrong"; } }); } -pplx::task mitk::RESTClientMicroService::Get(web::uri uri, utility::string_t filePath) +pplx::task mitk::RESTClientMicroService::Get(const web::uri &uri, const utility::string_t &filePath) { + // Create new HTTP client MitkClient *client = new MitkClient(uri); + MITK_INFO << "Calling GET with " << utility::conversions::to_utf8string(uri.path()) << " on client " << mitk::RESTUtil::convertToUtf8(uri.authority().to_string()) << " save into " << mitk::RESTUtil::convertToUtf8(filePath); - + + //create new file buffer auto fileBuffer = std::make_shared>(); + // create get request MitkRequest getRequest(MitkRESTMethods::GET); + + //open file stream for the specified file path return concurrency::streams::file_buffer::open(filePath, std::ios::out) .then([=](concurrency::streams::streambuf outFile) -> pplx::task { *fileBuffer = outFile; - + //make the get request return client->request(MitkRESTMethods::GET); }) // Write the response body into the file buffer. .then([=](MitkResponse response) -> pplx::task { auto status = response.status_code(); MITK_DEBUG << "Status code: " << status; if (status != web::http::status_codes::OK) { + // throw if something went wrong (e.g. invalid uri) + // this exception can be handled by client mitkThrow() << "GET ended up with response " << mitk::RESTUtil::convertToUtf8(response.to_string()); } return response.body().read_to_end(*fileBuffer); }) // Close the file buffer. .then([=](size_t) { return fileBuffer->close(); }) .then([=]() { + //return empty json object web::json::value data; return data; }); } -pplx::task mitk::RESTClientMicroService::PUT(web::uri uri, web::json::value content) +pplx::task mitk::RESTClientMicroService::PUT(const web::uri &uri, const web::json::value &content) { + // Create new HTTP client MitkClient *client = new MitkClient(uri); + MITK_INFO << "Calling PUT with " << utility::conversions::to_utf8string(uri.path()) << " on client " << mitk::RESTUtil::convertToUtf8(uri.authority().to_string()); + // create put request MitkRequest putRequest(MitkRESTMethods::PUT); - putRequest.set_body(content); + //set body of the put request with data given by client + if (content != NULL) + { + putRequest.set_body(content); + } + //make put request return client->request(putRequest).then([=](pplx::task responseTask) { try { + // get response of the request MitkResponse response = responseTask.get(); auto status = response.status_code(); MITK_INFO << " status: " << status; if (status != MitkRestStatusCodes::OK) { + // throw if something went wrong (e.g. invalid uri) + // this exception can be handled by client mitkThrow() << "response was not OK"; } try { + // parse content type to application/json if it isn't already + // this is important if the content type is e.g. application/dicom+json utility::string_t requestContentType = response.headers().content_type(); if (requestContentType != L"application/json") { response.headers().set_content_type(L"application/json"); } + // return json answer return response.extract_json().get(); } catch (...) { mitkThrow() << "extracting json went wrong"; } } catch (...) { mitkThrow() << "getting response went wrong"; } }); } -pplx::task mitk::RESTClientMicroService::POST(web::uri uri, web::json::value content) +pplx::task mitk::RESTClientMicroService::POST(const web::uri &uri, const web::json::value &content) { + // Create new HTTP client MitkClient *client = new MitkClient(uri); MITK_INFO << "Calling POST with " << utility::conversions::to_utf8string(uri.path()) << " on client " << mitk::RESTUtil::convertToUtf8(uri.authority().to_string()); + // Create post request MitkRequest postRequest(MitkRESTMethods::POST); + // set body of the put request with data given by client if (content != NULL) { postRequest.set_body(content); } + //make post request return client->request(postRequest).then([=](pplx::task responseTask) { try { + // get response of the request MitkResponse response = responseTask.get(); auto status = response.status_code(); MITK_INFO << " status: " << status; if (status != MitkRestStatusCodes::Created) { + // throw if something went wrong (e.g. invalid uri) + // this exception can be handled by client mitkThrow() << "response was not Created"; } try { + // parse content type to application/json if it isn't already + // this is important if the content type is e.g. application/dicom+json utility::string_t requestContentType = response.headers().content_type(); if (requestContentType != L"application/json") { response.headers().set_content_type(L"application/json"); } + // return json answer return response.extract_json().get(); } catch (...) { mitkThrow() << "extracting json went wrong"; } } catch(...) { mitkThrow() << "getting response went wrong"; } }); } diff --git a/Modules/CppRestSdk/src/mitkRESTManager.cpp b/Modules/CppRestSdk/src/mitkRESTManager.cpp index f46d65f5db..fdb04ecd65 100644 --- a/Modules/CppRestSdk/src/mitkRESTManager.cpp +++ b/Modules/CppRestSdk/src/mitkRESTManager.cpp @@ -1,244 +1,203 @@ #include "mitkRESTManager.h" #include mitk::RESTManager::RESTManager() {} mitk::RESTManager::~RESTManager() {} -pplx::task mitk::RESTManager::SendRequest(web::uri uri, - RequestType type, - web::json::value content, - utility::string_t filePath) +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(web::uri uri, mitk::IRESTObserver *observer) +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_Observer[key] = observer; + 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"); 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_Observer.count(key) == 0) + if (m_Observers.count(key) == 0) { - m_Observer[key] = observer; + 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_Observer.count(key); + 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(web::uri uri, web::json::value data) +web::json::value mitk::RESTManager::Handle(const web::uri &uri, web::json::value &body) { - // Checking if is there is a observer for the port and path + // Checking if there is an observer for the port and path std::pair key(uri.port(), uri.path()); - if (m_Observer.count(key) != 0) + if (m_Observers.count(key) != 0) { MITK_INFO << "Manager: Data send to observer"; - return m_Observer[key]->Notify(data); + return m_Observers[key]->Notify(body); } - //No map under this port, delete Server Object to release port for other servers + //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(mitk::IRESTObserver *observer) -//{ -// for (auto it = m_Observer.begin(); it != m_Observer.end();) -// { -// mitk::IRESTObserver *obsMap = it->second; -// //Check weather observer is at this place in map -// if (obsMap == observer) -// { -// // if yes -// // 1. store port in a temporary variable -// 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_Observer.count(key); -// // 2. delete map entry -// it = m_Observer.erase(it); -// MITK_INFO << "Number of elements at key [ " << port << ", " << std::string(key.second.begin(), key.second.end()) -// << "]: " << m_Observer.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_Observer) -// { -// 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(); -// //delete server from map -// m_ServerMap.erase(port); -// } -// } -// else -// { -// ++it; -// } -// } -//} - -void mitk::RESTManager::HandleDeleteObserver(IRESTObserver *observer, web::uri uri=L"") +void mitk::RESTManager::HandleDeleteObserver(IRESTObserver *observer, const web::uri &uri= L"") { - for (auto it = m_Observer.begin(); it != m_Observer.end();) + 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 in a temporary variable + // 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_Observer.count(key); + << "]: " << m_Observers.count(key); // 2. delete map entry - it = m_Observer.erase(it); + it = m_Observers.erase(it); MITK_INFO << "Number of elements at key [ " << port << ", " << std::string(key.second.begin(), key.second.end()) - << "]: " << m_Observer.count(key); + << "]: " << 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_Observer) + 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(); // delete server from map m_ServerMap.erase(port); } } else { ++it; } } else { ++it; } } } diff --git a/Modules/CppRestSdk/src/mitkRESTServerMicroService.cpp b/Modules/CppRestSdk/src/mitkRESTServerMicroService.cpp index 914845ae75..84342e7621 100644 --- a/Modules/CppRestSdk/src/mitkRESTServerMicroService.cpp +++ b/Modules/CppRestSdk/src/mitkRESTServerMicroService.cpp @@ -1,69 +1,75 @@ #include "mitkRESTServerMicroService.h" #include #include #include mitk::RESTServerMicroService::RESTServerMicroService(web::uri uri) : m_Listener(uri) { m_Uri = uri; } mitk::RESTServerMicroService::~RESTServerMicroService() { } void mitk::RESTServerMicroService::OpenListener() { + //create listener m_Listener = MitkListener(m_Uri); + //Connect incoming get requests with HandleGet method m_Listener.support(web::http::methods::GET, std::bind(&mitk::RESTServerMicroService::HandleGet, this, std::placeholders::_1)); + //open listener m_Listener.open().wait(); } void mitk::RESTServerMicroService::CloseListener() { + //close listener m_Listener.close().wait(); } web::uri mitk::RESTServerMicroService::GetUri() { return m_Uri; } void mitk::RESTServerMicroService::HandleGet(MitkRequest request) { int port = m_Listener.uri().port(); //getting exact request uri has to be a parameter in handle function web::uri_builder build(m_Listener.uri()); build.append(request.absolute_uri()); utility::string_t uriStringT = build.to_uri().to_string(); std::string uriString(uriStringT.begin(), uriStringT.end()); MITK_INFO << "Get Request fot server at port " << port << " Exact request uri: " << uriString; web::json::value content; + //get RESTManager as microservice to call th Handle method of the manager us::ModuleContext *context = us::GetModuleContext(); auto managerRef = context->GetServiceReference(); if (managerRef) { auto managerService = context->GetService(managerRef); if (managerService) { web::json::value data = request.extract_json().get(); MITK_INFO << "Server: Data send to manager"; + //call the handle method content = managerService->Handle(build.to_uri(), data); MITK_INFO << "server: Data received from manager"; } } if (content!=NULL) { //content handled by observer request.reply(MitkRestStatusCodes::OK, content); } else { //no observer to handle data request.reply(MitkRestStatusCodes::NotFound); } } \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.client/src/internal/QmitkClientView.cpp b/Plugins/org.mitk.gui.qt.client/src/internal/QmitkClientView.cpp index 4923e0848a..374dd719f9 100644 --- a/Plugins/org.mitk.gui.qt.client/src/internal/QmitkClientView.cpp +++ b/Plugins/org.mitk.gui.qt.client/src/internal/QmitkClientView.cpp @@ -1,255 +1,269 @@ /*=================================================================== 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 "QmitkClientView.h" #include #include "cpprest/json.h" #include #include #include #include #include #include const std::string QmitkClientView::VIEW_ID = "org.mitk.views.clientview"; QmitkClientView::QmitkClientView() : m_Ui(new Ui::QmitkClientView) { } QmitkClientView::~QmitkClientView() { delete m_Ui; } void QmitkClientView::CreateQtPartControl(QWidget *parent) { m_Ui->setupUi(parent); connect(m_Ui->getMultiplePushButton, &QPushButton::clicked, this, &QmitkClientView::OnGetMultipleButtonClicked); connect(m_Ui->getSinglePushButton, &QPushButton::clicked, this, &QmitkClientView::OnGetSingleButtonClicked); connect(m_Ui->getSavePushButton, &QPushButton::clicked, this, &QmitkClientView::OnGetSaveButtonClicked); connect(m_Ui->putPushButton, &QPushButton::clicked, this, &QmitkClientView::OnPutButtonClicked); connect(m_Ui->postPushButton, &QPushButton::clicked, this, &QmitkClientView::OnPostButtonClicked); connect(this, &QmitkClientView::UpdateProgressBar, this, &QmitkClientView::OnUpdateProgressBar); connect(this, SIGNAL(UpdateLabel(QString)), this, SLOT(OnUpdateLabel(QString))); m_Ui->progressBar->setValue(0); } void QmitkClientView::OnUpdateProgressBar() { m_Ui->progressBar->setValue(m_Ui->progressBar->value() + 5); } void QmitkClientView::OnUpdateLabel(QString text) { m_Ui->responseLabel->setText(text); } void QmitkClientView::SetFocus() {} void QmitkClientView::OnGetMultipleButtonClicked() { m_Ui->progressBar->setValue(0); m_Ui->getMultiplePushButton->setDisabled(true); + //Get microservice us::ModuleContext *context = us::ModuleRegistry::GetModule(1)->GetModuleContext(); auto managerRef = context->GetServiceReference(); if (managerRef) { auto managerService = context->GetService(managerRef); if (managerService) { + //Create multiple tasks e.g. as shown below std::vector> tasks; for (int i = 0; i < 20; i++) { pplx::task singleTask = managerService->SendRequest(L"http://193.174.48.78:8090/dcm4chee-arc/aets/DCM4CHEE/rs/studies/1.2.840.113654.2.70.1.97144850941324808603541273584489321943/series/1.2.840.113654.2.70.1.15771179684190906938515254678965278540/instances") .then([=](pplx::task resultTask) { + //Do something when a single task is done try { resultTask.get(); emit UpdateProgressBar(); } 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(); emit UpdateLabel("All tasks finished"); } catch (const mitk::Exception &exception) { MITK_ERROR << exception.what(); return; } }); m_Ui->responseLabel->setText("Waiting for change"); } } m_Ui->getMultiplePushButton->setEnabled(true); } void QmitkClientView::OnGetSingleButtonClicked() { m_Ui->putPushButton->setDisabled(true); + //Get the micorservice us::ModuleContext *context = us::ModuleRegistry::GetModule(1)->GetModuleContext(); auto managerRef = context->GetServiceReference(); if (managerRef) { auto managerService = context->GetService(managerRef); if (managerService) { + //Call the send request method which starts the actual request managerService ->SendRequest(L"http://193.174.48.78:8090/dcm4chee-arc/aets/DCM4CHEE/rs/studies/1.2.840.113654.2.70.1.97144850941324808603541273584489321943/series/1.2.840.113654.2.70.1.15771179684190906938515254678965278540/instances") - .then([=](pplx::task resultTask) { + .then([=](pplx::task resultTask)/*It is important to use task-based continuation*/ { try { + //Get the result of the request + //This will throw an exception if the ascendent task threw an exception (e.g. invalid URI) web::json::value result = resultTask.get(); + //Do something with the result (e.g. convert it to a QSrting to update an UI element) utility::string_t stringT = result.to_string(); std::string stringStd(stringT.begin(), stringT.end()); QString stringQ = QString::fromStdString(stringStd); + //Note: if you want to update your UI, do this by using signals and slots. + //The UI can't be updated from a Thread different to the Qt main thread emit UpdateLabel(stringQ); } catch (const mitk::Exception &exception) { + //Exceptions from ascendent tasks are catched here MITK_ERROR << exception.what(); return; } }); } } m_Ui->putPushButton->setEnabled(true); } void QmitkClientView::OnGetSaveButtonClicked() { m_Ui->putPushButton->setDisabled(true); us::ModuleContext *context = us::ModuleRegistry::GetModule(1)->GetModuleContext(); auto managerRef = context->GetServiceReference(); if (managerRef) { auto managerService = context->GetService(managerRef); if (managerService) { managerService ->SendRequest(L"http://193.174.48.78:8090/dcm4chee-arc/aets/DCM4CHEE/rs/studies/1.2.840.113654.2.70.1.97144850941324808603541273584489321943/series/1.2.840.113654.2.70.1.15771179684190906938515254678965278540/instances", mitk::IRESTManager::RequestType::get, NULL,L"FileStream.txt") .then([=](pplx::task resultTask) { try { web::json::value result = resultTask.get(); utility::string_t stringT = result.to_string(); std::string stringStd(stringT.begin(), stringT.end()); QString stringQ = QString::fromStdString(stringStd); emit UpdateLabel(stringQ); } catch (const mitk::Exception &exception) { MITK_ERROR << exception.what(); return; } }); m_Ui->responseLabel->setText("Waiting for change"); } } m_Ui->putPushButton->setEnabled(true); } void QmitkClientView::OnPutButtonClicked() { m_Ui->putPushButton->setDisabled(true); us::ModuleContext *context = us::ModuleRegistry::GetModule(1)->GetModuleContext(); auto managerRef = context->GetServiceReference(); if (managerRef) { auto managerService = context->GetService(managerRef); if (managerService) { 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 changed title")); data[L"body"] = web::json::value(U("and the body is changed as well")); managerService->SendRequest( L"https://jsonplaceholder.typicode.com/posts/1", mitk::IRESTManager::RequestType::put, data) .then([=](pplx::task resultTask) { try { web::json::value result = resultTask.get(); utility::string_t stringT = result.to_string(); std::string stringStd(stringT.begin(), stringT.end()); QString stringQ = QString::fromStdString(stringStd); emit UpdateLabel(stringQ); } catch (const mitk::Exception &exception) { MITK_ERROR << exception.what(); return; } }); } } m_Ui->putPushButton->setEnabled(true); } void QmitkClientView::OnPostButtonClicked() { m_Ui->postPushButton->setDisabled(true); us::ModuleContext *context = us::ModuleRegistry::GetModule(1)->GetModuleContext(); auto managerRef = context->GetServiceReference(); if (managerRef) { auto managerService = context->GetService(managerRef); if (managerService) { web::json::value data; 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")); managerService ->SendRequest(L"https://jsonplaceholder.typicode.com/posts", mitk::IRESTManager::RequestType::post, data) .then([=](pplx::task resultTask) { try { web::json::value result = resultTask.get(); utility::string_t stringT = result.to_string(); std::string stringStd(stringT.begin(), stringT.end()); QString stringQ = QString::fromStdString(stringStd); emit UpdateLabel(stringQ); } catch (const mitk::Exception &exception) { MITK_ERROR << exception.what(); return; } }); } } m_Ui->postPushButton->setEnabled(true); } 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 1845b1c9c5..12724b2ca3 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) { 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 ea5f94c263..06ceaaf9fb 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) 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