# HG changeset patch # User Sebastien Jodogne # Date 1571323901 -7200 # Node ID d7a18a3cd6f903e820f1a7ae41fc88ac1ea8e3c9 # Parent 008dbc4ceb62adf2e6acdc53e0854d899caa4e6c IOracleRunner diff -r 008dbc4ceb62 -r d7a18a3cd6f9 Framework/Oracle/CustomOracleCommand.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Oracle/CustomOracleCommand.h Thu Oct 17 16:51:41 2019 +0200 @@ -0,0 +1,40 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + **/ + + +#pragma once + +#include "IOracleRunner.h" + +namespace OrthancStone +{ + class CustomOracleCommand : public IOracleCommand + { + public: + virtual Type GetType() const + { + return Type_Custom; + } + + virtual void Execute(IMessageEmitter& emitter, + boost::weak_ptr& receiver, + IOracleRunner& runner) = 0; + }; +} diff -r 008dbc4ceb62 -r d7a18a3cd6f9 Framework/Oracle/GenericOracleRunner.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Oracle/GenericOracleRunner.cpp Thu Oct 17 16:51:41 2019 +0200 @@ -0,0 +1,235 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + **/ + + +#include "GenericOracleRunner.h" + +#include "CustomOracleCommand.h" +#include "GetOrthancImageCommand.h" +#include "GetOrthancWebViewerJpegCommand.h" +#include "HttpCommand.h" +#include "OracleCommandExceptionMessage.h" +#include "OrthancRestApiCommand.h" + +#include +#include +#include +#include + +namespace OrthancStone +{ + static void CopyHttpHeaders(Orthanc::HttpClient& client, + const Orthanc::HttpClient::HttpHeaders& headers) + { + for (Orthanc::HttpClient::HttpHeaders::const_iterator + it = headers.begin(); it != headers.end(); it++ ) + { + client.AddHeader(it->first, it->second); + } + } + + + static void DecodeAnswer(std::string& answer, + const Orthanc::HttpClient::HttpHeaders& headers) + { + Orthanc::HttpCompression contentEncoding = Orthanc::HttpCompression_None; + + for (Orthanc::HttpClient::HttpHeaders::const_iterator it = headers.begin(); + it != headers.end(); ++it) + { + std::string s; + Orthanc::Toolbox::ToLowerCase(s, it->first); + + if (s == "content-encoding") + { + if (it->second == "gzip") + { + contentEncoding = Orthanc::HttpCompression_Gzip; + } + else + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol, + "Unsupported HTTP Content-Encoding: " + it->second); + } + + break; + } + } + + if (contentEncoding == Orthanc::HttpCompression_Gzip) + { + std::string compressed; + answer.swap(compressed); + + Orthanc::GzipCompressor compressor; + compressor.Uncompress(answer, compressed.c_str(), compressed.size()); + + LOG(INFO) << "Uncompressing gzip Encoding: from " << compressed.size() + << " to " << answer.size() << " bytes"; + } + } + + + static void Execute(IMessageEmitter& emitter, + boost::weak_ptr& receiver, + const HttpCommand& command) + { + Orthanc::HttpClient client; + client.SetUrl(command.GetUrl()); + client.SetMethod(command.GetMethod()); + client.SetTimeout(command.GetTimeout()); + + CopyHttpHeaders(client, command.GetHttpHeaders()); + + if (command.GetMethod() == Orthanc::HttpMethod_Post || + command.GetMethod() == Orthanc::HttpMethod_Put) + { + client.SetBody(command.GetBody()); + } + + std::string answer; + Orthanc::HttpClient::HttpHeaders answerHeaders; + client.ApplyAndThrowException(answer, answerHeaders); + + DecodeAnswer(answer, answerHeaders); + + HttpCommand::SuccessMessage message(command, answerHeaders, answer); + emitter.EmitMessage(receiver, message); + } + + + static void Execute(IMessageEmitter& emitter, + const Orthanc::WebServiceParameters& orthanc, + boost::weak_ptr& receiver, + const OrthancRestApiCommand& command) + { + Orthanc::HttpClient client(orthanc, command.GetUri()); + client.SetMethod(command.GetMethod()); + client.SetTimeout(command.GetTimeout()); + + CopyHttpHeaders(client, command.GetHttpHeaders()); + + if (command.GetMethod() == Orthanc::HttpMethod_Post || + command.GetMethod() == Orthanc::HttpMethod_Put) + { + client.SetBody(command.GetBody()); + } + + std::string answer; + Orthanc::HttpClient::HttpHeaders answerHeaders; + client.ApplyAndThrowException(answer, answerHeaders); + + DecodeAnswer(answer, answerHeaders); + + OrthancRestApiCommand::SuccessMessage message(command, answerHeaders, answer); + emitter.EmitMessage(receiver, message); + } + + + static void Execute(IMessageEmitter& emitter, + const Orthanc::WebServiceParameters& orthanc, + boost::weak_ptr& receiver, + const GetOrthancImageCommand& command) + { + Orthanc::HttpClient client(orthanc, command.GetUri()); + client.SetTimeout(command.GetTimeout()); + + CopyHttpHeaders(client, command.GetHttpHeaders()); + + std::string answer; + Orthanc::HttpClient::HttpHeaders answerHeaders; + client.ApplyAndThrowException(answer, answerHeaders); + + DecodeAnswer(answer, answerHeaders); + + command.ProcessHttpAnswer(emitter, receiver, answer, answerHeaders); + } + + + static void Execute(IMessageEmitter& emitter, + const Orthanc::WebServiceParameters& orthanc, + boost::weak_ptr& receiver, + const GetOrthancWebViewerJpegCommand& command) + { + Orthanc::HttpClient client(orthanc, command.GetUri()); + client.SetTimeout(command.GetTimeout()); + + CopyHttpHeaders(client, command.GetHttpHeaders()); + + std::string answer; + Orthanc::HttpClient::HttpHeaders answerHeaders; + client.ApplyAndThrowException(answer, answerHeaders); + + DecodeAnswer(answer, answerHeaders); + + command.ProcessHttpAnswer(emitter, receiver, answer); + } + + + void GenericOracleRunner::Run(boost::weak_ptr& receiver, + IOracleCommand& command) + { + try + { + switch (command.GetType()) + { + case IOracleCommand::Type_Sleep: + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadParameterType, + "Sleep command cannot be executed by the runner"); + break; + + case IOracleCommand::Type_Http: + Execute(emitter_, receiver, + dynamic_cast(command)); + break; + + case IOracleCommand::Type_OrthancRestApi: + Execute(emitter_, orthanc_, receiver, dynamic_cast(command)); + break; + + case IOracleCommand::Type_GetOrthancImage: + Execute(emitter_, orthanc_, receiver, dynamic_cast(command)); + break; + + case IOracleCommand::Type_GetOrthancWebViewerJpeg: + Execute(emitter_, orthanc_, receiver, dynamic_cast(command)); + break; + + case IOracleCommand::Type_Custom: + dynamic_cast(command).Execute(emitter_, receiver, *this); + break; + + default: + throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); + } + } + catch (Orthanc::OrthancException& e) + { + LOG(ERROR) << "Exception within the oracle: " << e.What(); + emitter_.EmitMessage(receiver, OracleCommandExceptionMessage(command, e)); + } + catch (...) + { + LOG(ERROR) << "Threaded exception within the oracle"; + emitter_.EmitMessage(receiver, OracleCommandExceptionMessage + (command, Orthanc::ErrorCode_InternalError)); + } + } +} diff -r 008dbc4ceb62 -r d7a18a3cd6f9 Framework/Oracle/GenericOracleRunner.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Oracle/GenericOracleRunner.h Thu Oct 17 16:51:41 2019 +0200 @@ -0,0 +1,49 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + **/ + + +#pragma once + +#include "../Messages/IMessageEmitter.h" +#include "IOracleRunner.h" + +#include // For ORTHANC_OVERRIDE +#include + +namespace OrthancStone +{ + class GenericOracleRunner : public IOracleRunner + { + private: + IMessageEmitter& emitter_; + const Orthanc::WebServiceParameters& orthanc_; + + public: + GenericOracleRunner(IMessageEmitter& emitter, + const Orthanc::WebServiceParameters& orthanc) : + emitter_(emitter), + orthanc_(orthanc) + { + } + + virtual void Run(boost::weak_ptr& receiver, + IOracleCommand& command) ORTHANC_OVERRIDE; + }; +} diff -r 008dbc4ceb62 -r d7a18a3cd6f9 Framework/Oracle/IOracle.h --- a/Framework/Oracle/IOracle.h Thu Oct 17 14:42:41 2019 +0200 +++ b/Framework/Oracle/IOracle.h Thu Oct 17 16:51:41 2019 +0200 @@ -22,7 +22,9 @@ #pragma once #include "../Messages/IObserver.h" -#include "IOracleCommand.h" +#include "IOracleRunner.h" + +#include namespace OrthancStone { @@ -35,5 +37,13 @@ virtual void Schedule(boost::shared_ptr& receiver, IOracleCommand* command) = 0; // Takes ownership + + template + void ScheduleAdapter(boost::shared_ptr& receiver, + IOracleCommand* command) + { + boost::shared_ptr converted(receiver); + Schedule(converted, command); + } }; } diff -r 008dbc4ceb62 -r d7a18a3cd6f9 Framework/Oracle/IOracleCommand.h --- a/Framework/Oracle/IOracleCommand.h Thu Oct 17 14:42:41 2019 +0200 +++ b/Framework/Oracle/IOracleCommand.h Thu Oct 17 16:51:41 2019 +0200 @@ -34,7 +34,8 @@ Type_Sleep, Type_OrthancRestApi, Type_GetOrthancImage, - Type_GetOrthancWebViewerJpeg + Type_GetOrthancWebViewerJpeg, + Type_Custom }; virtual ~IOracleCommand() diff -r 008dbc4ceb62 -r d7a18a3cd6f9 Framework/Oracle/IOracleRunner.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Oracle/IOracleRunner.h Thu Oct 17 16:51:41 2019 +0200 @@ -0,0 +1,40 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + **/ + + +#pragma once + +#include "IOracleCommand.h" + +#include + +namespace OrthancStone +{ + class IOracleRunner : public boost::noncopyable + { + public: + virtual ~IOracleRunner() + { + } + + virtual void Run(boost::weak_ptr& receiver, + IOracleCommand& command) = 0; + }; +} diff -r 008dbc4ceb62 -r d7a18a3cd6f9 Framework/Oracle/ThreadedOracle.cpp --- a/Framework/Oracle/ThreadedOracle.cpp Thu Oct 17 14:42:41 2019 +0200 +++ b/Framework/Oracle/ThreadedOracle.cpp Thu Oct 17 16:51:41 2019 +0200 @@ -21,18 +21,10 @@ #include "ThreadedOracle.h" -#include "GetOrthancImageCommand.h" -#include "GetOrthancWebViewerJpegCommand.h" -#include "HttpCommand.h" -#include "OrthancRestApiCommand.h" #include "SleepOracleCommand.h" -#include "OracleCommandExceptionMessage.h" -#include -#include +#include #include -#include - namespace OrthancStone { @@ -160,154 +152,6 @@ }; - static void CopyHttpHeaders(Orthanc::HttpClient& client, - const Orthanc::HttpClient::HttpHeaders& headers) - { - for (Orthanc::HttpClient::HttpHeaders::const_iterator - it = headers.begin(); it != headers.end(); it++ ) - { - client.AddHeader(it->first, it->second); - } - } - - - static void DecodeAnswer(std::string& answer, - const Orthanc::HttpClient::HttpHeaders& headers) - { - Orthanc::HttpCompression contentEncoding = Orthanc::HttpCompression_None; - - for (Orthanc::HttpClient::HttpHeaders::const_iterator it = headers.begin(); - it != headers.end(); ++it) - { - std::string s; - Orthanc::Toolbox::ToLowerCase(s, it->first); - - if (s == "content-encoding") - { - if (it->second == "gzip") - { - contentEncoding = Orthanc::HttpCompression_Gzip; - } - else - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol, - "Unsupported HTTP Content-Encoding: " + it->second); - } - - break; - } - } - - if (contentEncoding == Orthanc::HttpCompression_Gzip) - { - std::string compressed; - answer.swap(compressed); - - Orthanc::GzipCompressor compressor; - compressor.Uncompress(answer, compressed.c_str(), compressed.size()); - - LOG(INFO) << "Uncompressing gzip Encoding: from " << compressed.size() - << " to " << answer.size() << " bytes"; - } - } - - - static void Execute(IMessageEmitter& emitter, - boost::weak_ptr& receiver, - const HttpCommand& command) - { - Orthanc::HttpClient client; - client.SetUrl(command.GetUrl()); - client.SetMethod(command.GetMethod()); - client.SetTimeout(command.GetTimeout()); - - CopyHttpHeaders(client, command.GetHttpHeaders()); - - if (command.GetMethod() == Orthanc::HttpMethod_Post || - command.GetMethod() == Orthanc::HttpMethod_Put) - { - client.SetBody(command.GetBody()); - } - - std::string answer; - Orthanc::HttpClient::HttpHeaders answerHeaders; - client.ApplyAndThrowException(answer, answerHeaders); - - DecodeAnswer(answer, answerHeaders); - - HttpCommand::SuccessMessage message(command, answerHeaders, answer); - emitter.EmitMessage(receiver, message); - } - - - static void Execute(IMessageEmitter& emitter, - const Orthanc::WebServiceParameters& orthanc, - boost::weak_ptr& receiver, - const OrthancRestApiCommand& command) - { - Orthanc::HttpClient client(orthanc, command.GetUri()); - client.SetMethod(command.GetMethod()); - client.SetTimeout(command.GetTimeout()); - - CopyHttpHeaders(client, command.GetHttpHeaders()); - - if (command.GetMethod() == Orthanc::HttpMethod_Post || - command.GetMethod() == Orthanc::HttpMethod_Put) - { - client.SetBody(command.GetBody()); - } - - std::string answer; - Orthanc::HttpClient::HttpHeaders answerHeaders; - client.ApplyAndThrowException(answer, answerHeaders); - - DecodeAnswer(answer, answerHeaders); - - OrthancRestApiCommand::SuccessMessage message(command, answerHeaders, answer); - emitter.EmitMessage(receiver, message); - } - - - static void Execute(IMessageEmitter& emitter, - const Orthanc::WebServiceParameters& orthanc, - boost::weak_ptr& receiver, - const GetOrthancImageCommand& command) - { - Orthanc::HttpClient client(orthanc, command.GetUri()); - client.SetTimeout(command.GetTimeout()); - - CopyHttpHeaders(client, command.GetHttpHeaders()); - - std::string answer; - Orthanc::HttpClient::HttpHeaders answerHeaders; - client.ApplyAndThrowException(answer, answerHeaders); - - DecodeAnswer(answer, answerHeaders); - - command.ProcessHttpAnswer(emitter, receiver, answer, answerHeaders); - } - - - static void Execute(IMessageEmitter& emitter, - const Orthanc::WebServiceParameters& orthanc, - boost::weak_ptr& receiver, - const GetOrthancWebViewerJpegCommand& command) - { - Orthanc::HttpClient client(orthanc, command.GetUri()); - client.SetTimeout(command.GetTimeout()); - - CopyHttpHeaders(client, command.GetHttpHeaders()); - - std::string answer; - Orthanc::HttpClient::HttpHeaders answerHeaders; - client.ApplyAndThrowException(answer, answerHeaders); - - DecodeAnswer(answer, answerHeaders); - - command.ProcessHttpAnswer(emitter, receiver, answer); - } - - void ThreadedOracle::Step() { std::auto_ptr object(queue_.Dequeue(100)); @@ -316,60 +160,23 @@ { Item& item = dynamic_cast(*object); - try + if (item.GetCommand().GetType() == IOracleCommand::Type_Sleep) { - switch (item.GetCommand().GetType()) + SleepOracleCommand& command = dynamic_cast(item.GetCommand()); + + std::auto_ptr copy(new SleepOracleCommand(command.GetDelay())); + + if (command.HasPayload()) { - case IOracleCommand::Type_Sleep: - { - SleepOracleCommand& command = dynamic_cast(item.GetCommand()); - - std::auto_ptr copy(new SleepOracleCommand(command.GetDelay())); - - if (command.HasPayload()) - { - copy->SetPayload(command.ReleasePayload()); - } - - sleepingCommands_->Add(item.GetReceiver(), copy.release()); - - break; - } - - case IOracleCommand::Type_Http: - Execute(emitter_, item.GetReceiver(), - dynamic_cast(item.GetCommand())); - break; - - case IOracleCommand::Type_OrthancRestApi: - Execute(emitter_, orthanc_, item.GetReceiver(), - dynamic_cast(item.GetCommand())); - break; - - case IOracleCommand::Type_GetOrthancImage: - Execute(emitter_, orthanc_, item.GetReceiver(), - dynamic_cast(item.GetCommand())); - break; - - case IOracleCommand::Type_GetOrthancWebViewerJpeg: - Execute(emitter_, orthanc_, item.GetReceiver(), - dynamic_cast(item.GetCommand())); - break; - - default: - throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); + copy->SetPayload(command.ReleasePayload()); } - } - catch (Orthanc::OrthancException& e) - { - LOG(ERROR) << "Exception within the oracle: " << e.What(); - emitter_.EmitMessage(item.GetReceiver(), OracleCommandExceptionMessage(item.GetCommand(), e)); + + sleepingCommands_->Add(item.GetReceiver(), copy.release()); } - catch (...) + else { - LOG(ERROR) << "Threaded exception within the oracle"; - emitter_.EmitMessage(item.GetReceiver(), OracleCommandExceptionMessage - (item.GetCommand(), Orthanc::ErrorCode_InternalError)); + GenericOracleRunner runner(emitter_, orthanc_); + runner.Run(item.GetReceiver(), item.GetCommand()); } } } diff -r 008dbc4ceb62 -r d7a18a3cd6f9 Framework/Oracle/ThreadedOracle.h --- a/Framework/Oracle/ThreadedOracle.h Thu Oct 17 14:42:41 2019 +0200 +++ b/Framework/Oracle/ThreadedOracle.h Thu Oct 17 16:51:41 2019 +0200 @@ -29,10 +29,9 @@ # error This file can only compiled for native targets #endif -#include "../Messages/IMessageEmitter.h" #include "IOracle.h" +#include "GenericOracleRunner.h" -#include #include @@ -74,7 +73,6 @@ virtual ~ThreadedOracle(); - // The reference is not stored. void SetOrthancParameters(const Orthanc::WebServiceParameters& orthanc); void SetThreadsCount(unsigned int count); @@ -89,6 +87,6 @@ } virtual void Schedule(boost::shared_ptr& receiver, - IOracleCommand* command); + IOracleCommand* command) ORTHANC_OVERRIDE; }; } diff -r 008dbc4ceb62 -r d7a18a3cd6f9 Resources/CMake/OrthancStoneConfiguration.cmake --- a/Resources/CMake/OrthancStoneConfiguration.cmake Thu Oct 17 14:42:41 2019 +0200 +++ b/Resources/CMake/OrthancStoneConfiguration.cmake Thu Oct 17 16:51:41 2019 +0200 @@ -404,6 +404,7 @@ ${ORTHANC_STONE_ROOT}/Framework/Messages/LockingEmitter.cpp ${ORTHANC_STONE_ROOT}/Framework/Messages/LockingEmitter.h ${ORTHANC_STONE_ROOT}/Framework/Oracle/ThreadedOracle.cpp + ${ORTHANC_STONE_ROOT}/Framework/Oracle/GenericOracleRunner.cpp ) endif()